Snap for 8426163 from 6c1d6414fd3b155cd2be344693f61f414bff20ea to mainline-tzdata2-release

Change-Id: I29fc51ed48fa0d69d79d61cd480b0fc1e9abb6a2
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 722d5e7..0000000
--- a/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-.vscode
diff --git a/METADATA b/METADATA
deleted file mode 100644
index 20b75c4..0000000
--- a/METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-third_party {
-  # would be NOTICE save for:
-  #   incfs/kernel-headers/linux/incrementalfs.h
-  license_type: RESTRICTED
-}
diff --git a/incfs/Android.bp b/incfs/Android.bp
index 88b3abb..a64821a 100644
--- a/incfs/Android.bp
+++ b/incfs/Android.bp
@@ -1,51 +1,28 @@
-// 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.
-
-package {
-    default_applicable_licenses: ["system_incremental_delivery_incfs_license"],
-}
-
-// Added automatically by a large-scale-change that took the approach of
-// 'apply every license found to every target'. While this makes sure we respect
-// every license restriction, it may not be entirely correct.
-//
-// e.g. GPL in an MIT project might only apply to the contrib/ directory.
-//
-// Please consider splitting the single license below into multiple licenses,
-// taking care not to lose any license_kind information, and overriding the
-// default license using the 'licenses: [...]' property on targets as needed.
-//
-// For unused files, consider creating a 'fileGroup' with "//visibility:private"
-// to attach the license to, and including a comment whether the files may be
-// used in the current project.
-// See: http://go/android-license-faq
-license {
-    name: "system_incremental_delivery_incfs_license",
-    visibility: [":__subpackages__"],
-    license_kinds: [
-        "SPDX-license-identifier-Apache-2.0",
-        "SPDX-license-identifier-GPL-2.0",
-    ],
-    license_text: [
-        "NOTICE",
-    ],
-}
-
 cc_defaults {
-    name: "libincfs_defaults_common",
+    name: "libincfs_defaults",
     cpp_std: "c++2a",
     cflags: ["-Werror", "-Wall", "-Wextra"],
+    defaults: ["linux_bionic_supported"],
+    export_include_dirs: ["include/", "kernel-headers",],
+    local_include_dirs: ["include/"],
+    header_libs: [
+        "libincfs_headers",
+    ],
+    export_header_lib_headers: ["libincfs_headers"],
+    static_libs: [
+        "libbase",
+        "com.android.sysprop.incremental",
+    ],
+    shared_libs: [
+        "libcrypto",
+        "liblog",
+        "libselinux",
+    ],
+    target: {
+        linux_bionic: {
+            enabled: true,
+        }
+    },
     tidy: true,
     tidy_checks: [
         "android-*",
@@ -59,36 +36,6 @@
         // operator=() does not handle self-assignment properly - all protobuf-generated classes
         "-cert-oop54-cpp",
     ],
-    target: {
-        linux_bionic: {
-            enabled: true,
-        },
-    },
-}
-
-cc_defaults {
-    name: "libincfs_defaults",
-    defaults: [
-        "libincfs_defaults_common",
-        "linux_bionic_supported",
-    ],
-    header_libs: ["libincfs_headers"],
-    export_header_lib_headers: ["libincfs_headers"],
-    static_libs: [
-        "libbase",
-    ],
-    shared_libs: [
-        "libcrypto",
-        "liblog",
-        "libselinux",
-    ],
-    target: {
-        android: {
-            static_libs: [
-                "com.android.sysprop.incremental",
-            ],
-        },
-    },
 }
 
 cc_library {
@@ -102,36 +49,6 @@
     ],
 }
 
-cc_library_static {
-    name: "libincfs-utils",
-    defaults: ["libincfs_defaults_common"],
-    local_include_dirs: ["util/include"],
-    export_include_dirs: ["util/include"],
-    host_supported: true,
-    srcs: [
-        "util/map_ptr.cpp",
-    ],
-    target: {
-        android: {
-            header_libs: ["libincfs_headers"],
-            shared_libs: [
-                "libbase",
-                "libincfs",
-                "libutils",
-            ],
-        },
-        host: {
-            static_libs: [
-                "libbase",
-                "libutils",
-            ],
-        },
-        windows: {
-            enabled: true,
-        },
-    },
-}
-
 cc_library_headers {
     name: "libincfs_headers",
     export_include_dirs: ["include/", "kernel-headers",],
@@ -146,38 +63,19 @@
 cc_test {
     name: "libincfs-test",
     defaults: ["libincfs_defaults"],
-    local_include_dirs: ["tests/include"],
     static_libs: [
         "libincfs",
-        "libincfs-utils",
     ],
     shared_libs: [
         "libbase",
-        "libutils",
     ],
     srcs: [
-        "tests/util/map_ptr_test.cpp",
         "tests/incfs_test.cpp",
         "tests/MountRegistry_test.cpp",
     ],
     require_root: true,
 }
 
-cc_benchmark {
-    name: "hardening-benchmark",
-    defaults: ["libincfs_defaults"],
-
-    srcs: [
-        "tests/hardening_benchmark.cpp",
-    ],
-    static_libs: [
-        "libziparchive_for_incfs",
-        "libutils",
-        "libincfs",
-        "libincfs-utils",
-    ],
-}
-
 cc_binary {
     name: "incfsdump",
     defaults: ["libincfs_defaults"],
diff --git a/incfs/MountRegistry.cpp b/incfs/MountRegistry.cpp
index b7b53c8..c4752f3 100644
--- a/incfs/MountRegistry.cpp
+++ b/incfs/MountRegistry.cpp
@@ -18,18 +18,18 @@
 
 #include "MountRegistry.h"
 
-#include <android-base/logging.h>
-#include <poll.h>
-#include <stdlib.h>
-
-#include <charconv>
-#include <set>
-#include <unordered_map>
-
 #include "incfs.h"
 #include "path.h"
 #include "split.h"
 
+#include <android-base/logging.h>
+
+#include <charconv>
+#include <unordered_map>
+
+#include <poll.h>
+#include <stdlib.h>
+
 using namespace std::literals;
 
 namespace android::incfs {
@@ -69,7 +69,7 @@
     std::vector<std::pair<std::string_view, std::string_view>> result;
     result.reserve(mBase->binds.size());
     for (auto it : mBase->binds) {
-        result.emplace_back(it->second.subdir, it->first);
+        result.emplace_back(it->second.first, it->first);
     }
     return result;
 }
@@ -88,12 +88,12 @@
         std::string_view path) const {
     auto it = rootByBindPoint.lower_bound(path);
     if (it != rootByBindPoint.end() && it->first == path) {
-        return {it->second.rootIndex, it};
+        return {it->second.second, it};
     }
     if (it != rootByBindPoint.begin()) {
         --it;
         if (path::startsWith(path, it->first) && path.size() > it->first.size()) {
-            const auto index = it->second.rootIndex;
+            const auto index = it->second.second;
             if (index >= int(roots.size()) || roots[index].empty()) {
                 LOG(ERROR) << "[incfs] Root for path '" << path << "' #" << index
                            << " is not valid";
@@ -113,24 +113,24 @@
     return roots[index].path;
 }
 
-auto MountRegistry::Mounts::rootAndSubpathFor(std::string_view path) const
-        -> std::pair<const Root*, std::string> {
+std::pair<std::string_view, std::string> MountRegistry::Mounts::rootAndSubpathFor(
+        std::string_view path) const {
     auto normalPath = path::normalize(path);
     auto [index, bindIt] = rootIndex(normalPath);
     if (index < 0) {
         return {};
     }
 
-    const auto& bindSubdir = bindIt->second.subdir;
+    const auto& bindSubdir = bindIt->second.first;
     const auto pastBindSubdir = path::relativize(bindIt->first, normalPath);
     const auto& root = roots[index];
-    return {&root, path::join(bindSubdir, pastBindSubdir)};
+    return {root.path, path::join(bindSubdir, pastBindSubdir)};
 }
 
 void MountRegistry::Mounts::addRoot(std::string_view root, std::string_view backingDir) {
     const auto index = roots.size();
     auto absolute = path::normalize(root);
-    auto it = rootByBindPoint.insert_or_assign(absolute, Bind{std::string(), int(index)}).first;
+    auto it = rootByBindPoint.insert_or_assign(absolute, std::pair{std::string(), index}).first;
     roots.push_back({std::move(absolute), path::normalize(backingDir), {it}});
 }
 
@@ -141,17 +141,13 @@
         LOG(WARNING) << "[incfs] Trying to remove non-existent root '" << root << '\'';
         return;
     }
-    const auto index = it->second.rootIndex;
+    const auto index = it->second.second;
     if (index >= int(roots.size())) {
         LOG(ERROR) << "[incfs] Root '" << root << "' has index " << index
                    << " out of bounds (total roots count is " << roots.size();
         return;
     }
 
-    for (auto bindIt : roots[index].binds) {
-        rootByBindPoint.erase(bindIt);
-    }
-
     if (index + 1 == int(roots.size())) {
         roots.pop_back();
         // Run a small GC job here as we may be able to remove some obsolete
@@ -162,6 +158,37 @@
     } else {
         roots[index].clear();
     }
+    rootByBindPoint.erase(it);
+}
+
+void MountRegistry::Mounts::moveBind(std::string_view src, std::string_view dest) {
+    auto srcAbsolute = path::normalize(src);
+    auto destAbsolute = path::normalize(dest);
+    if (srcAbsolute == destAbsolute) {
+        return;
+    }
+
+    auto [root, rootIt] = rootIndex(srcAbsolute);
+    if (root < 0) {
+        LOG(ERROR) << "[incfs] No root found for bind move from " << src << " to " << dest;
+        return;
+    }
+
+    if (roots[root].path == srcAbsolute) {
+        // moving the whole root
+        roots[root].path = destAbsolute;
+    }
+
+    // const_cast<> here is safe as we're erasing that element on the next line.
+    const auto newRootIt = rootByBindPoint
+                                   .insert_or_assign(std::move(destAbsolute),
+                                                     std::pair{std::move(const_cast<std::string&>(
+                                                                       rootIt->second.first)),
+                                                               root})
+                                   .first;
+    rootByBindPoint.erase(rootIt);
+    const auto bindIt = std::find(roots[root].binds.begin(), roots[root].binds.end(), rootIt);
+    *bindIt = newRootIt;
 }
 
 void MountRegistry::Mounts::addBind(std::string_view what, std::string_view where) {
@@ -174,10 +201,11 @@
 
     const auto& currentBind = rootIt->first;
     auto whatSubpath = path::relativize(currentBind, whatAbsolute);
-    const auto& subdir = rootIt->second.subdir;
+    const auto& subdir = rootIt->second.first;
     auto realSubdir = path::join(subdir, whatSubpath);
     auto it = rootByBindPoint
-                      .insert_or_assign(path::normalize(where), Bind{std::move(realSubdir), root})
+                      .insert_or_assign(path::normalize(where),
+                                        std::pair{std::move(realSubdir), root})
                       .first;
     roots[root].binds.push_back(it);
 }
@@ -216,23 +244,10 @@
     auto lock = ensureUpToDate();
     return std::string(mMounts.rootFor(path));
 }
-
-auto MountRegistry::detailsFor(std::string_view path) -> Details {
-    auto lock = ensureUpToDate();
-    auto [root, subpath] = mMounts.rootAndSubpathFor(path);
-    if (!root) {
-        return {};
-    }
-    return {root->path, root->backing, subpath};
-}
-
 std::pair<std::string, std::string> MountRegistry::rootAndSubpathFor(std::string_view path) {
     auto lock = ensureUpToDate();
     auto [root, subpath] = mMounts.rootAndSubpathFor(path);
-    if (!root) {
-        return {};
-    }
-    return {std::string(root->path), std::move(subpath)};
+    return {std::string(root), std::move(subpath)};
 }
 
 MountRegistry::Mounts MountRegistry::copyMounts() {
@@ -304,8 +319,8 @@
 
 bool MountRegistry::Mounts::loadFrom(base::borrowed_fd fd, std::string_view filesystem) {
     struct MountInfo {
+        std::string root;
         std::string backing;
-        std::set<std::string, std::less<>> roots;
         std::vector<std::pair<std::string, std::string>> bindPoints;
     };
     std::unordered_map<std::string, MountInfo> mountsByGroup(16);
@@ -327,22 +342,20 @@
         }
         const auto groupId = items[2];
         auto subdir = items[3];
-        auto backingDir = items.rbegin()[1];
         auto mountPoint = std::string(items[4]);
         fixProcPath(mountPoint);
         mountPoint = path::normalize(mountPoint);
         auto& mount = mountsByGroup[std::string(groupId)];
-        if (mount.backing.empty()) {
-            mount.backing.assign(backingDir);
-        } else if (mount.backing != backingDir) {
-            LOG(WARNING) << "[incfs] root '" << *mount.roots.begin()
-                         << "' mounted in multiple places with different backing dirs, '"
-                         << mount.backing << "' vs new '" << backingDir
-                         << "'; updating to the new one";
-            mount.backing.assign(backingDir);
-        }
         if (subdir == "/"sv) {
-            mount.roots.emplace(mountPoint);
+            if (mount.root.empty()) {
+                mount.root.assign(mountPoint);
+                mount.backing.assign(items.rbegin()[1]);
+                fixProcPath(mount.backing);
+            } else {
+                LOG(WARNING) << "[incfs] incfs root '" << mount.root
+                             << "' mounted in multiple places, ignoring later mount '" << mountPoint
+                             << '\'';
+            }
             subdir = ""sv;
         }
         mount.bindPoints.emplace_back(std::string(subdir), std::move(mountPoint));
@@ -353,7 +366,7 @@
     }
 
     rootByBindPoint.clear();
-    // preserve the allocated capacity, but clear existing data
+    // preserve the allocated capacity, but clean existing data
     roots.resize(mountsByGroup.size());
     for (auto& root : roots) {
         root.binds.clear();
@@ -361,32 +374,20 @@
 
     int index = 0;
     for (auto& [_, mount] : mountsByGroup) {
-        if (mount.roots.empty()) {
-            // the mount has no root, and without root we have no good way of accessing the
-            // control files - so the only valid reaction here is to ignore it
-            LOG(WARNING) << "[incfs] mount '" << mount.backing << "' has no root, but "
-                         << mount.bindPoints.size() << " bind(s), ignoring";
-            continue;
-        }
-
         Root& root = roots[index];
         auto& binds = root.binds;
         binds.reserve(mount.bindPoints.size());
         for (auto& [subdir, bind] : mount.bindPoints) {
-            auto it = rootByBindPoint
-                              .insert_or_assign(std::move(bind), Bind{std::move(subdir), index})
-                              .first;
+            auto it =
+                    rootByBindPoint
+                            .insert_or_assign(std::move(bind), std::pair(std::move(subdir), index))
+                            .first;
             binds.push_back(it);
         }
+        root.path = std::move(mount.root);
         root.backing = std::move(mount.backing);
-        fixProcPath(root.backing);
-
-        // a trick here: given that as of now we either have exactly one root, or the preferred one
-        // is always at the front, let's pick that one here.
-        root.path = std::move(mount.roots.extract(mount.roots.begin()).value());
         ++index;
     }
-    roots.resize(index);
 
     LOG(INFO) << "[incfs] Loaded " << filesystem << " mount info: " << roots.size()
               << " instances, " << rootByBindPoint.size() << " mount points";
@@ -395,7 +396,7 @@
             LOG(INFO) << "[incfs]  '" << root << '\'';
             LOG(INFO) << "[incfs]    backing: '" << backing << '\'';
             for (auto&& bind : binds) {
-                LOG(INFO) << "[incfs]      bind : '" << bind->second.subdir << "'->'" << bind->first
+                LOG(INFO) << "[incfs]      bind : '" << bind->second.first << "'->'" << bind->first
                           << '\'';
             }
         }
diff --git a/incfs/incfs.cpp b/incfs/incfs.cpp
index 842e381..7994c54 100644
--- a/incfs/incfs.cpp
+++ b/incfs/incfs.cpp
@@ -23,7 +23,6 @@
 #include <android-base/logging.h>
 #include <android-base/no_destructor.h>
 #include <android-base/parsebool.h>
-#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
@@ -34,7 +33,6 @@
 #include <openssl/sha.h>
 #include <selinux/android.h>
 #include <selinux/selinux.h>
-#include <sys/inotify.h>
 #include <sys/mount.h>
 #include <sys/poll.h>
 #include <sys/stat.h>
@@ -44,8 +42,8 @@
 #include <sys/xattr.h>
 #include <unistd.h>
 
-#include <charconv>
 #include <chrono>
+#include <fstream>
 #include <iterator>
 #include <mutex>
 #include <optional>
@@ -63,9 +61,8 @@
     IncFsFd cmd;
     IncFsFd pendingReads;
     IncFsFd logs;
-    IncFsFd blocksWritten;
-    constexpr IncFsControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs, IncFsFd blocksWritten)
-          : cmd(cmd), pendingReads(pendingReads), logs(logs), blocksWritten(blocksWritten) {}
+    constexpr IncFsControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs)
+          : cmd(cmd), pendingReads(pendingReads), logs(logs) {}
 };
 
 static MountRegistry& registry() {
@@ -85,10 +82,6 @@
     return openRaw(path::join(dir, name));
 }
 
-static std::string indexPath(std::string_view root, IncFsFileId fileId) {
-    return path::join(root, INCFS_INDEX_NAME, toString(fileId));
-}
-
 static std::string rootForCmd(int fd) {
     auto cmdFile = path::fromFd(fd);
     if (cmdFile.empty()) {
@@ -111,29 +104,41 @@
     return std::string(res);
 }
 
+static Features readIncFsFeatures() {
+    static const char kSysfsFeaturesDir[] = "/sys/fs/" INCFS_NAME "/features";
+    const auto dir = path::openDir(kSysfsFeaturesDir);
+    if (!dir) {
+        return Features::none;
+    }
+
+    int res = Features::none;
+    while (auto entry = ::readdir(dir.get())) {
+        if (entry->d_type != DT_REG) {
+            continue;
+        }
+        if (entry->d_name == "corefs"sv) {
+            res |= Features::core;
+        }
+    }
+
+    return Features(res);
+}
+
+IncFsFeatures IncFs_Features() {
+    return IncFsFeatures(readIncFsFeatures());
+}
+
 static bool isFsAvailable() {
     static const char kProcFilesystems[] = "/proc/filesystems";
     std::string filesystems;
     if (!ab::ReadFileToString(kProcFilesystems, &filesystems)) {
         return false;
     }
-    const auto result = filesystems.find("\t" INCFS_NAME "\n") != std::string::npos;
-    LOG(INFO) << "isFsAvailable: " << (result ? "true" : "false");
-    return result;
-}
-
-static int getFirstApiLevel() {
-    uint64_t api_level = android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
-    LOG(INFO) << "Initial API level of the device: " << api_level;
-    return api_level;
+    return filesystems.find("\t" INCFS_NAME "\n") != std::string::npos;
 }
 
 static std::string_view incFsPropertyValue() {
-    constexpr const int R_API = 30;
-    static const auto kDefaultValue{getFirstApiLevel() > R_API ? "on" : ""};
-    static const ab::NoDestructor<std::string> kValue{
-            IncrementalProperties::enable().value_or(kDefaultValue)};
-    LOG(INFO) << "ro.incremental.enable: " << *kValue;
+    static const ab::NoDestructor<std::string> kValue{IncrementalProperties::enable().value_or("")};
     return *kValue;
 }
 
@@ -155,29 +160,6 @@
     return {false, {}};
 }
 
-template <class Callback>
-static IncFsErrorCode forEachFileIn(std::string_view dirPath, Callback cb) {
-    auto dir = path::openDir(details::c_str(dirPath));
-    if (!dir) {
-        return -EINVAL;
-    }
-
-    int res = 0;
-    while (auto entry = (errno = 0, ::readdir(dir.get()))) {
-        if (entry->d_type != DT_REG) {
-            continue;
-        }
-        ++res;
-        if (!cb(entry->d_name)) {
-            break;
-        }
-    }
-    if (errno) {
-        return -errno;
-    }
-    return res;
-}
-
 namespace {
 
 class IncFsInit {
@@ -203,12 +185,6 @@
             return true;
         }
         std::call_once(loadedFlag_, [this] {
-            if (isFsAvailable()) {
-                // Loaded from a different process, I suppose.
-                loaded_ = true;
-                LOG(INFO) << "IncFS is already available, skipped loading";
-                return;
-            }
             const ab::unique_fd fd(TEMP_FAILURE_RETRY(
                     ::open(details::c_str(moduleName_), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
             if (fd < 0) {
@@ -249,50 +225,7 @@
     return init().enabled();
 }
 
-static Features readIncFsFeatures() {
-    init().enabledAndReady();
-
-    int res = Features::none | Features::mappingFilesProgressFixed;
-
-    static const char kSysfsFeaturesDir[] = "/sys/fs/" INCFS_NAME "/features";
-    const auto dir = path::openDir(kSysfsFeaturesDir);
-    if (!dir) {
-        PLOG(ERROR) << "IncFs_Features: failed to open features dir, assuming v1/none.";
-        return Features(res);
-    }
-
-    while (auto entry = ::readdir(dir.get())) {
-        if (entry->d_type != DT_REG) {
-            continue;
-        }
-        if (entry->d_name == "corefs"sv) {
-            res |= Features::core;
-        } else if (entry->d_name == "v2"sv || entry->d_name == "report_uid"sv) {
-            res |= Features::v2;
-        }
-    }
-
-    LOG(INFO) << "IncFs_Features: " << ((res & Features::v2) ? "v2" : "v1");
-
-    return Features(res);
-}
-
-IncFsFeatures IncFs_Features() {
-    static const auto features = IncFsFeatures(readIncFsFeatures());
-    return features;
-}
-
-bool isIncFsFdImpl(int fd) {
-    struct statfs fs = {};
-    if (::fstatfs(fd, &fs) != 0) {
-        PLOG(WARNING) << __func__ << "(): could not fstatfs fd " << fd;
-        return false;
-    }
-
-    return fs.f_type == (decltype(fs.f_type))INCFS_MAGIC_NUMBER;
-}
-
-bool isIncFsPathImpl(const char* path) {
+bool isIncFsPath(const char* path) {
     struct statfs fs = {};
     if (::statfs(path, &fs) != 0) {
         PLOG(WARNING) << __func__ << "(): could not statfs " << path;
@@ -361,18 +294,11 @@
 }
 
 static std::string makeMountOptionsString(IncFsMountOptions options) {
-    auto opts = ab::StringPrintf("read_timeout_ms=%u,readahead=0,rlog_pages=%u,rlog_wakeup_cnt=1,",
-                                 unsigned(options.defaultReadTimeoutMs),
-                                 unsigned(options.readLogBufferPages < 0
-                                                  ? INCFS_DEFAULT_PAGE_READ_BUFFER_PAGES
-                                                  : options.readLogBufferPages));
-    if (features() & Features::v2) {
-        ab::StringAppendF(&opts, "report_uid,");
-        if (options.sysfsName && *options.sysfsName) {
-            ab::StringAppendF(&opts, "sysfs_name=%s,", options.sysfsName);
-        }
-    }
-    return opts;
+    return ab::StringPrintf("read_timeout_ms=%u,readahead=0,rlog_pages=%u,rlog_wakeup_cnt=1",
+                            unsigned(options.defaultReadTimeoutMs),
+                            unsigned(options.readLogBufferPages < 0
+                                             ? INCFS_DEFAULT_PAGE_READ_BUFFER_PAGES
+                                             : options.readLogBufferPages));
 }
 
 static IncFsControl* makeControl(const char* root) {
@@ -385,25 +311,12 @@
         return nullptr;
     }
     auto logs = openRaw(root, INCFS_LOG_FILENAME);
-    if (!logs.ok()) {
-        return nullptr;
-    }
-    ab::unique_fd blocksWritten;
-    if (features() & Features::v2) {
-        blocksWritten = openRaw(root, INCFS_BLOCKS_WRITTEN_FILENAME);
-        if (!blocksWritten.ok()) {
-            return nullptr;
-        }
-    }
-    auto control =
-            IncFs_CreateControl(cmd.get(), pendingReads.get(), logs.get(), blocksWritten.get());
+    // logs may be absent, that's fine
+    auto control = IncFs_CreateControl(cmd.get(), pendingReads.get(), logs.get());
     if (control) {
         (void)cmd.release();
         (void)pendingReads.release();
         (void)logs.release();
-        (void)blocksWritten.release();
-    } else {
-        errno = ENOMEM;
     }
     return control;
 }
@@ -441,7 +354,7 @@
     IncFsFileId res;
     auto out = (char*)&res;
     for (auto it = str.begin(); it != str.end(); it += 2, ++out) {
-        static const auto fromChar = [](char src) -> int {
+        static const auto fromChar = [](char src) -> char {
             if (src >= '0' && src <= '9') {
                 return src - '0';
             }
@@ -451,7 +364,7 @@
             return -1;
         };
 
-        const int c[2] = {fromChar(it[0]), fromChar(it[1])};
+        const char c[2] = {fromChar(it[0]), fromChar(it[1])};
         if (c[0] == -1 || c[1] == -1) {
             errno = EINVAL;
             return kIncFsInvalidFileId;
@@ -491,24 +404,17 @@
 }
 
 static bool restoreconControlFiles(std::string_view targetDir) {
-    static constexpr auto restorecon = [](const char* name) {
-        if (const auto err = selinux_android_restorecon(name, SELINUX_ANDROID_RESTORECON_FORCE);
+    const std::string controlFilePaths[] = {path::join(targetDir, INCFS_PENDING_READS_FILENAME),
+                                            path::join(targetDir, INCFS_LOG_FILENAME)};
+    for (size_t i = 0; i < std::size(controlFilePaths); i++) {
+        if (const auto err = selinux_android_restorecon(controlFilePaths[i].c_str(),
+                                                        SELINUX_ANDROID_RESTORECON_FORCE);
             err != 0) {
+            PLOG(ERROR) << "[incfs] Failed to restorecon: " << controlFilePaths[i]
+                        << " error code: " << err;
             errno = -err;
-            PLOG(ERROR) << "[incfs] Failed to restorecon: " << name;
             return false;
         }
-        return true;
-    };
-    if (!restorecon(path::join(targetDir, INCFS_PENDING_READS_FILENAME).c_str())) {
-        return false;
-    }
-    if (!restorecon(path::join(targetDir, INCFS_LOG_FILENAME).c_str())) {
-        return false;
-    }
-    if ((features() & Features::v2) &&
-        !restorecon(path::join(targetDir, INCFS_BLOCKS_WRITTEN_FILENAME).c_str())) {
-        return false;
     }
     return true;
 }
@@ -545,18 +451,17 @@
     const auto opts = makeMountOptionsString(options);
     if (::mount(backingPath, targetDir, INCFS_NAME, MS_NOSUID | MS_NODEV | MS_NOATIME,
                 opts.c_str())) {
-        PLOG(ERROR) << "[incfs] Failed to mount IncFS filesystem: " << targetDir;
+        PLOG(ERROR) << "[incfs] Failed to mount IncFS filesystem: " << targetDir
+                    << " errno: " << errno;
         return nullptr;
     }
 
     if (!restoreconControlFiles(targetDir)) {
-        (void)IncFs_Unmount(targetDir);
         return nullptr;
     }
 
     auto control = makeControl(targetDir);
     if (control == nullptr) {
-        (void)IncFs_Unmount(targetDir);
         return nullptr;
     }
     return control;
@@ -582,8 +487,6 @@
             return control->pendingReads;
         case LOGS:
             return control->logs;
-        case BLOCKS_WRITTEN:
-            return control->blocksWritten;
         default:
             return -EINVAL;
     }
@@ -599,13 +502,11 @@
     out[CMD] = std::exchange(control->cmd, -1);
     out[PENDING_READS] = std::exchange(control->pendingReads, -1);
     out[LOGS] = std::exchange(control->logs, -1);
-    out[BLOCKS_WRITTEN] = std::exchange(control->blocksWritten, -1);
     return IncFsFdType::FDS_COUNT;
 }
 
-IncFsControl* IncFs_CreateControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs,
-                                  IncFsFd blocksWritten) {
-    return new IncFsControl(cmd, pendingReads, logs, blocksWritten);
+IncFsControl* IncFs_CreateControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs) {
+    return new IncFsControl(cmd, pendingReads, logs);
 }
 
 void IncFs_DeleteControl(IncFsControl* control) {
@@ -619,9 +520,6 @@
         if (control->logs >= 0) {
             close(control->logs);
         }
-        if (control->blocksWritten >= 0) {
-            close(control->blocksWritten);
-        }
         delete control;
     }
 }
@@ -796,48 +694,6 @@
     return 0;
 }
 
-IncFsErrorCode IncFs_MakeMappedFile(const IncFsControl* control, const char* path, int32_t mode,
-                                    IncFsNewMappedFileParams params) {
-    if (!control) {
-        return -EINVAL;
-    }
-
-    auto [root, subpath] = registry().rootAndSubpathFor(path);
-    if (root.empty()) {
-        PLOG(WARNING) << "[incfs] makeMappedFile failed for path " << path << ", root is empty.";
-        return -EINVAL;
-    }
-    if (params.size < 0) {
-        LOG(WARNING) << "[incfs] makeMappedFile failed for path " << path
-                     << ", size is invalid: " << params.size;
-        return -ERANGE;
-    }
-
-    const auto [subdir, name] = path::splitDirBase(subpath);
-    incfs_create_mapped_file_args args = {
-            .size = (uint64_t)params.size,
-            .mode = (uint16_t)mode,
-            .directory_path = (uint64_t)subdir.data(),
-            .file_name = (uint64_t)name.data(),
-            .source_offset = (uint64_t)params.sourceOffset,
-    };
-    static_assert(sizeof(args.source_file_id.bytes) == sizeof(params.sourceId.data));
-    memcpy(args.source_file_id.bytes, params.sourceId.data, sizeof(args.source_file_id.bytes));
-
-    if (::ioctl(control->cmd, INCFS_IOC_CREATE_MAPPED_FILE, &args)) {
-        PLOG(WARNING) << "[incfs] makeMappedFile failed for " << root << " / " << subdir << " / "
-                      << name << " of " << params.size << " bytes starting at "
-                      << params.sourceOffset;
-        return -errno;
-    }
-    if (::chmod(path::join(root, subpath).c_str(), mode)) {
-        PLOG(WARNING) << "[incfs] makeMappedFile error: couldn't change file mode to 0" << std::oct
-                      << mode;
-    }
-
-    return 0;
-}
-
 static IncFsErrorCode makeDir(const char* commandPath, int32_t mode, bool allowExisting) {
     if (!::mkdir(commandPath, mode)) {
         if (::chmod(commandPath, mode)) {
@@ -937,7 +793,7 @@
     if (root.empty()) {
         return -EINVAL;
     }
-    auto name = indexPath(root, fileId);
+    auto name = path::join(root, kIndexDir, toStringImpl(fileId));
     return getMetadata(details::c_str(name), buffer, bufferSize);
 }
 
@@ -955,16 +811,6 @@
     return getMetadata(path, buffer, bufferSize);
 }
 
-template <class GetterFunc, class Param>
-static IncFsFileId getId(GetterFunc getter, Param param) {
-    char buffer[kIncFsFileIdStringLength];
-    const auto res = getter(param, kIdAttrName, buffer, sizeof(buffer));
-    if (res != sizeof(buffer)) {
-        return kIncFsInvalidFileId;
-    }
-    return toFileIdImpl({buffer, std::size(buffer)});
-}
-
 IncFsFileId IncFs_GetId(const IncFsControl* control, const char* path) {
     if (!control) {
         return kIncFsInvalidFileId;
@@ -975,7 +821,12 @@
         errno = EINVAL;
         return kIncFsInvalidFileId;
     }
-    return getId(::getxattr, path);
+    char buffer[kIncFsFileIdStringLength];
+    const auto res = ::getxattr(path, kIdAttrName, buffer, sizeof(buffer));
+    if (res != sizeof(buffer)) {
+        return kIncFsInvalidFileId;
+    }
+    return toFileIdImpl({buffer, std::size(buffer)});
 }
 
 static IncFsErrorCode getSignature(int fd, char buffer[], size_t* bufferSize) {
@@ -1005,7 +856,7 @@
     if (root.empty()) {
         return -EINVAL;
     }
-    auto file = indexPath(root, fileId);
+    auto file = path::join(root, kIndexDir, toStringImpl(fileId));
     auto fd = openRaw(file);
     if (fd < 0) {
         return fd.get();
@@ -1086,9 +937,8 @@
     return 0;
 }
 
-template <class RawPendingRead>
-static int waitForReadsImpl(int fd, int32_t timeoutMs, RawPendingRead pendingReadsBuffer[],
-                            size_t* pendingReadsBufferSize) {
+static int waitForReads(int fd, int32_t timeoutMs, incfs_pending_read_info pendingReadsBuffer[],
+                        size_t* pendingReadsBufferSize) {
     using namespace std::chrono;
     auto hrTimeout = steady_clock::duration(milliseconds(timeoutMs));
 
@@ -1136,81 +986,53 @@
     return 0;
 }
 
-template <class PublicPendingRead, class RawPendingRead>
-PublicPendingRead convertRead(RawPendingRead rawRead) {
-    PublicPendingRead res = {
-            .bootClockTsUs = rawRead.timestamp_us,
-            .block = (IncFsBlockIndex)rawRead.block_index,
-            .serialNo = rawRead.serial_number,
-    };
-    memcpy(&res.id.data, rawRead.file_id.bytes, sizeof(res.id.data));
-
-    if constexpr (std::is_same_v<PublicPendingRead, IncFsReadInfoWithUid>) {
-        if constexpr (std::is_same_v<RawPendingRead, incfs_pending_read_info2>) {
-            res.uid = rawRead.uid;
-        } else {
-            res.uid = kIncFsNoUid;
-        }
-    }
-    return res;
-}
-
-template <class RawPendingRead, class PublicPendingRead>
-static int waitForReads(IncFsFd readFd, int32_t timeoutMs, PublicPendingRead buffer[],
-                        size_t* bufferSize) {
-    std::vector<RawPendingRead> pendingReads(*bufferSize);
-    if (const auto res = waitForReadsImpl(readFd, timeoutMs, pendingReads.data(), bufferSize)) {
-        return res;
-    }
-    for (size_t i = 0; i != *bufferSize; ++i) {
-        buffer[i] = convertRead<PublicPendingRead>(pendingReads[i]);
-    }
-    return 0;
-}
-
-template <class PublicPendingRead>
-static int waitForReads(IncFsFd readFd, int32_t timeoutMs, PublicPendingRead buffer[],
-                        size_t* bufferSize) {
-    if (features() & Features::v2) {
-        return waitForReads<incfs_pending_read_info2>(readFd, timeoutMs, buffer, bufferSize);
-    }
-    return waitForReads<incfs_pending_read_info>(readFd, timeoutMs, buffer, bufferSize);
-}
-
 IncFsErrorCode IncFs_WaitForPendingReads(const IncFsControl* control, int32_t timeoutMs,
                                          IncFsReadInfo buffer[], size_t* bufferSize) {
     if (!control || control->pendingReads < 0) {
         return -EINVAL;
     }
 
-    return waitForReads(control->pendingReads, timeoutMs, buffer, bufferSize);
-}
-
-IncFsErrorCode IncFs_WaitForPendingReadsWithUid(const IncFsControl* control, int32_t timeoutMs,
-                                                IncFsReadInfoWithUid buffer[], size_t* bufferSize) {
-    if (!control || control->pendingReads < 0) {
-        return -EINVAL;
+    std::vector<incfs_pending_read_info> pendingReads;
+    pendingReads.resize(*bufferSize);
+    if (const auto res =
+                waitForReads(control->pendingReads, timeoutMs, pendingReads.data(), bufferSize)) {
+        return res;
     }
-
-    return waitForReads(control->pendingReads, timeoutMs, buffer, bufferSize);
+    for (size_t i = 0; i != *bufferSize; ++i) {
+        buffer[i] = IncFsReadInfo{
+                .bootClockTsUs = pendingReads[i].timestamp_us,
+                .block = (IncFsBlockIndex)pendingReads[i].block_index,
+                .serialNo = pendingReads[i].serial_number,
+        };
+        memcpy(&buffer[i].id.data, pendingReads[i].file_id.bytes, sizeof(buffer[i].id.data));
+    }
+    return 0;
 }
 
 IncFsErrorCode IncFs_WaitForPageReads(const IncFsControl* control, int32_t timeoutMs,
                                       IncFsReadInfo buffer[], size_t* bufferSize) {
-    if (!control || control->logs < 0) {
+    if (!control) {
         return -EINVAL;
     }
 
-    return waitForReads(control->logs, timeoutMs, buffer, bufferSize);
-}
-
-IncFsErrorCode IncFs_WaitForPageReadsWithUid(const IncFsControl* control, int32_t timeoutMs,
-                                             IncFsReadInfoWithUid buffer[], size_t* bufferSize) {
-    if (!control || control->logs < 0) {
+    auto logsFd = control->logs;
+    if (logsFd < 0) {
         return -EINVAL;
     }
-
-    return waitForReads(control->logs, timeoutMs, buffer, bufferSize);
+    std::vector<incfs_pending_read_info> pendingReads;
+    pendingReads.resize(*bufferSize);
+    if (const auto res = waitForReads(logsFd, timeoutMs, pendingReads.data(), bufferSize)) {
+        return res;
+    }
+    for (size_t i = 0; i != *bufferSize; ++i) {
+        buffer[i] = IncFsReadInfo{
+                .bootClockTsUs = pendingReads[i].timestamp_us,
+                .block = (IncFsBlockIndex)pendingReads[i].block_index,
+                .serialNo = pendingReads[i].serial_number,
+        };
+        memcpy(&buffer[i].id.data, pendingReads[i].file_id.bytes, sizeof(buffer[i].id.data));
+    }
+    return 0;
 }
 
 static IncFsFd openForSpecialOps(int cmd, const char* path) {
@@ -1250,7 +1072,7 @@
     if (root.empty()) {
         return -EINVAL;
     }
-    auto name = indexPath(root, id);
+    auto name = path::join(root, kIndexDir, toStringImpl(id));
     return openForSpecialOps(cmd, makeCommandPath(root, name).c_str());
 }
 
@@ -1365,12 +1187,8 @@
     return 0;
 }
 
-bool IncFs_IsIncFsFd(int fd) {
-    return isIncFsFdImpl(fd);
-}
-
 bool IncFs_IsIncFsPath(const char* path) {
-    return isIncFsPathImpl(path);
+    return isIncFsPath(path);
 }
 
 IncFsErrorCode IncFs_GetFilledRanges(int fd, IncFsSpan outBuffer, IncFsFilledRanges* filledRanges) {
@@ -1479,17 +1297,7 @@
     return -error;
 }
 
-static IncFsErrorCode isFullyLoadedV2(std::string_view root, IncFsFileId id) {
-    if (::access(path::join(root, INCFS_INCOMPLETE_NAME, toStringImpl(id)).c_str(), F_OK)) {
-        if (errno == ENOENT) {
-            return 0; // no such incomplete file -> it's fully loaded.
-        }
-        return -errno;
-    }
-    return -ENODATA;
-}
-
-static IncFsErrorCode isFullyLoadedSlow(int fd) {
+IncFsErrorCode IncFs_IsFullyLoaded(int fd) {
     char buffer[2 * sizeof(IncFsBlockRange)];
     IncFsFilledRanges ranges;
     auto res = IncFs_GetFilledRanges(fd, IncFsSpan{.data = buffer, .size = std::size(buffer)},
@@ -1527,567 +1335,6 @@
     return -ENODATA;
 }
 
-IncFsErrorCode IncFs_IsFullyLoaded(int fd) {
-    if (features() & Features::v2) {
-        const auto fdPath = path::fromFd(fd);
-        if (fdPath.empty()) {
-            return errno ? -errno : -EINVAL;
-        }
-        const auto id = getId(::fgetxattr, fd);
-        if (id == kIncFsInvalidFileId) {
-            return -errno;
-        }
-        return isFullyLoadedV2(registry().rootFor(fdPath), id);
-    }
-    return isFullyLoadedSlow(fd);
-}
-IncFsErrorCode IncFs_IsFullyLoadedByPath(const IncFsControl* control, const char* path) {
-    if (!control || !path) {
-        return -EINVAL;
-    }
-    const auto root = rootForCmd(control->cmd);
-    if (root.empty()) {
-        return -EINVAL;
-    }
-    const auto pathRoot = registry().rootFor(path);
-    if (pathRoot != root) {
-        return -EINVAL;
-    }
-    if (features() & Features::v2) {
-        const auto id = getId(::getxattr, path);
-        if (id == kIncFsInvalidFileId) {
-            return -ENOTSUP;
-        }
-        return isFullyLoadedV2(root, id);
-    }
-    return isFullyLoadedSlow(openForSpecialOps(control->cmd, makeCommandPath(root, path).c_str()));
-}
-IncFsErrorCode IncFs_IsFullyLoadedById(const IncFsControl* control, IncFsFileId fileId) {
-    if (!control) {
-        return -EINVAL;
-    }
-    const auto root = rootForCmd(control->cmd);
-    if (root.empty()) {
-        return -EINVAL;
-    }
-    if (features() & Features::v2) {
-        return isFullyLoadedV2(root, fileId);
-    }
-    return isFullyLoadedSlow(
-            openForSpecialOps(control->cmd,
-                              makeCommandPath(root, indexPath(root, fileId)).c_str()));
-}
-
-static IncFsErrorCode isEverythingLoadedV2(const IncFsControl* control) {
-    const auto root = rootForCmd(control->cmd);
-    if (root.empty()) {
-        return -EINVAL;
-    }
-    auto res = forEachFileIn(path::join(root, INCFS_INCOMPLETE_NAME), [](auto) { return false; });
-    return res < 0 ? res : res > 0 ? -ENODATA : 0;
-}
-
-static IncFsErrorCode isEverythingLoadedSlow(const IncFsControl* control) {
-    const auto root = rootForCmd(control->cmd);
-    if (root.empty()) {
-        return -EINVAL;
-    }
-    // No special API for this version of the driver, need to recurse and check each file
-    // separately. Can at least speed it up by iterating over the .index/ dir and not dealing with
-    // the directory tree.
-    const auto indexPath = path::join(root, INCFS_INDEX_NAME);
-    const auto dir = path::openDir(indexPath.c_str());
-    if (!dir) {
-        return -EINVAL;
-    }
-    while (const auto entry = ::readdir(dir.get())) {
-        if (entry->d_type != DT_REG) {
-            continue;
-        }
-        const auto name = path::join(indexPath, entry->d_name);
-        auto fd =
-                ab::unique_fd(openForSpecialOps(control->cmd, makeCommandPath(root, name).c_str()));
-        if (fd.get() < 0) {
-            PLOG(WARNING) << __func__ << "(): can't open " << entry->d_name << " for special ops";
-            return fd.release();
-        }
-        const auto checkFullyLoaded = IncFs_IsFullyLoaded(fd.get());
-        if (checkFullyLoaded == 0 || checkFullyLoaded == -EOPNOTSUPP ||
-            checkFullyLoaded == -ENOTSUP || checkFullyLoaded == -ENOENT) {
-            // special kinds of files may return an error here, but it still means
-            // _this_ file is OK - you simply need to check the rest. E.g. can't query
-            // a mapped file, instead need to check its parent.
-            continue;
-        }
-        return checkFullyLoaded;
-    }
-    return 0;
-}
-
-IncFsErrorCode IncFs_IsEverythingFullyLoaded(const IncFsControl* control) {
-    if (!control) {
-        return -EINVAL;
-    }
-    if (features() & Features::v2) {
-        return isEverythingLoadedV2(control);
-    }
-    return isEverythingLoadedSlow(control);
-}
-
-IncFsErrorCode IncFs_SetUidReadTimeouts(const IncFsControl* control,
-                                        const IncFsUidReadTimeouts timeouts[], size_t count) {
-    if (!control) {
-        return -EINVAL;
-    }
-    if (!(features() & Features::v2)) {
-        return -ENOTSUP;
-    }
-
-    std::vector<incfs_per_uid_read_timeouts> argTimeouts(count);
-    for (size_t i = 0; i != count; ++i) {
-        argTimeouts[i] = incfs_per_uid_read_timeouts{
-                .uid = (uint32_t)timeouts[i].uid,
-                .min_time_us = timeouts[i].minTimeUs,
-                .min_pending_time_us = timeouts[i].minPendingTimeUs,
-                .max_pending_time_us = timeouts[i].maxPendingTimeUs,
-        };
-    }
-    incfs_set_read_timeouts_args args = {.timeouts_array = (uint64_t)(uintptr_t)argTimeouts.data(),
-                                         .timeouts_array_size = uint32_t(
-                                                 argTimeouts.size() * sizeof(*argTimeouts.data()))};
-    if (::ioctl(control->cmd, INCFS_IOC_SET_READ_TIMEOUTS, &args)) {
-        PLOG(WARNING) << "[incfs] setUidReadTimeouts failed";
-        return -errno;
-    }
-    return 0;
-}
-
-IncFsErrorCode IncFs_GetUidReadTimeouts(const IncFsControl* control,
-                                        IncFsUidReadTimeouts timeouts[], size_t* bufferSize) {
-    if (!control || !bufferSize) {
-        return -EINVAL;
-    }
-    if (!(features() & Features::v2)) {
-        return -ENOTSUP;
-    }
-
-    std::vector<incfs_per_uid_read_timeouts> argTimeouts(*bufferSize);
-    incfs_get_read_timeouts_args args = {.timeouts_array = (uint64_t)(uintptr_t)argTimeouts.data(),
-                                         .timeouts_array_size = uint32_t(
-                                                 argTimeouts.size() * sizeof(*argTimeouts.data())),
-                                         .timeouts_array_size_out = args.timeouts_array_size};
-    if (::ioctl(control->cmd, INCFS_IOC_GET_READ_TIMEOUTS, &args)) {
-        if (errno == E2BIG) {
-            *bufferSize = args.timeouts_array_size_out / sizeof(*argTimeouts.data());
-        }
-        return -errno;
-    }
-
-    *bufferSize = args.timeouts_array_size_out / sizeof(*argTimeouts.data());
-    for (size_t i = 0; i != *bufferSize; ++i) {
-        timeouts[i].uid = argTimeouts[i].uid;
-        timeouts[i].minTimeUs = argTimeouts[i].min_time_us;
-        timeouts[i].minPendingTimeUs = argTimeouts[i].min_pending_time_us;
-        timeouts[i].maxPendingTimeUs = argTimeouts[i].max_pending_time_us;
-    }
-    return 0;
-}
-
-// Trying to detect if this is a mapped file.
-// Not the best way as it might return true for other system files.
-// TODO: remove after IncFS returns ENOTSUP for such files.
-static bool isMapped(int fd) {
-    char buffer[kIncFsFileIdStringLength];
-    const auto res = ::fgetxattr(fd, kIdAttrName, buffer, sizeof(buffer));
-    return res != sizeof(buffer);
-}
-
-static IncFsErrorCode getFileBlockCount(int fd, IncFsBlockCounts* blockCount) {
-    if (isMapped(fd)) {
-        return -ENOTSUP;
-    }
-
-    incfs_get_block_count_args args = {};
-    auto res = ::ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &args);
-    if (res < 0) {
-        return -errno;
-    }
-    *blockCount = IncFsBlockCounts{
-            .totalDataBlocks = args.total_data_blocks_out,
-            .filledDataBlocks = args.filled_data_blocks_out,
-            .totalHashBlocks = args.total_hash_blocks_out,
-            .filledHashBlocks = args.filled_hash_blocks_out,
-    };
-    return 0;
-}
-
-IncFsErrorCode IncFs_GetFileBlockCountById(const IncFsControl* control, IncFsFileId id,
-                                           IncFsBlockCounts* blockCount) {
-    if (!control) {
-        return -EINVAL;
-    }
-    if (!(features() & Features::v2)) {
-        return -ENOTSUP;
-    }
-    const auto root = rootForCmd(control->cmd);
-    if (root.empty()) {
-        return -EINVAL;
-    }
-    auto name = indexPath(root, id);
-    auto fd = openRaw(name);
-    if (fd < 0) {
-        return fd.get();
-    }
-    return getFileBlockCount(fd, blockCount);
-}
-
-IncFsErrorCode IncFs_GetFileBlockCountByPath(const IncFsControl* control, const char* path,
-                                             IncFsBlockCounts* blockCount) {
-    if (!control) {
-        return -EINVAL;
-    }
-    if (!(features() & Features::v2)) {
-        return -ENOTSUP;
-    }
-    const auto pathRoot = registry().rootFor(path);
-    const auto root = rootForCmd(control->cmd);
-    if (root.empty() || root != pathRoot) {
-        return -EINVAL;
-    }
-    auto fd = openRaw(path);
-    if (fd < 0) {
-        return fd.get();
-    }
-    return getFileBlockCount(fd, blockCount);
-}
-
-IncFsErrorCode IncFs_ListIncompleteFiles(const IncFsControl* control, IncFsFileId ids[],
-                                         size_t* bufferSize) {
-    if (!control || !bufferSize) {
-        return -EINVAL;
-    }
-    if (!(features() & Features::v2)) {
-        return -ENOTSUP;
-    }
-    const auto root = rootForCmd(control->cmd);
-    if (root.empty()) {
-        return -EINVAL;
-    }
-    size_t index = 0;
-    int error = 0;
-    const auto res = forEachFileIn(path::join(root, INCFS_INCOMPLETE_NAME), [&](const char* name) {
-        if (index >= *bufferSize) {
-            error = -E2BIG;
-        } else {
-            ids[index] = IncFs_FileIdFromString(name);
-        }
-        ++index;
-        return true;
-    });
-    if (res < 0) {
-        return res;
-    }
-    *bufferSize = index;
-    return error ? error : 0;
-}
-
-IncFsErrorCode IncFs_ForEachFile(const IncFsControl* control, void* context, FileCallback cb) {
-    if (!control || !cb) {
-        return -EINVAL;
-    }
-    const auto root = rootForCmd(control->cmd);
-    if (root.empty()) {
-        return -EINVAL;
-    }
-    return forEachFileIn(path::join(root, INCFS_INDEX_NAME), [&](const char* name) {
-        return cb(context, control, IncFs_FileIdFromString(name));
-    });
-}
-
-IncFsErrorCode IncFs_ForEachIncompleteFile(const IncFsControl* control, void* context,
-                                           FileCallback cb) {
-    if (!control || !cb) {
-        return -EINVAL;
-    }
-    if (!(features() & Features::v2)) {
-        return -ENOTSUP;
-    }
-    const auto root = rootForCmd(control->cmd);
-    if (root.empty()) {
-        return -EINVAL;
-    }
-    return forEachFileIn(path::join(root, INCFS_INCOMPLETE_NAME), [&](const char* name) {
-        return cb(context, control, IncFs_FileIdFromString(name));
-    });
-}
-
-IncFsErrorCode IncFs_WaitForLoadingComplete(const IncFsControl* control, int32_t timeoutMs) {
-    if (!control) {
-        return -EINVAL;
-    }
-    if (!(features() & Features::v2)) {
-        return -ENOTSUP;
-    }
-
-    using namespace std::chrono;
-    auto hrTimeout = steady_clock::duration(milliseconds(timeoutMs));
-
-    const auto root = rootForCmd(control->cmd);
-    if (root.empty()) {
-        return -EINVAL;
-    }
-
-    ab::unique_fd fd(inotify_init1(IN_NONBLOCK | IN_CLOEXEC));
-    if (!fd.ok()) {
-        return -EFAULT;
-    }
-
-    // first create all the watches, and only then list existing files to prevent races
-    auto dirPath = path::join(root, INCFS_INCOMPLETE_NAME);
-    int watchFd = inotify_add_watch(fd.get(), dirPath.c_str(), IN_DELETE);
-    if (watchFd < 0) {
-        return -errno;
-    }
-
-    size_t count = 0;
-    auto res = IncFs_ListIncompleteFiles(control, nullptr, &count);
-    if (!res) {
-        return 0;
-    }
-    if (res != -E2BIG) {
-        return res;
-    }
-
-    while (hrTimeout > hrTimeout.zero()) {
-        const auto startTs = steady_clock::now();
-
-        pollfd pfd = {fd.get(), POLLIN, 0};
-        const auto res = ::poll(&pfd, 1, duration_cast<milliseconds>(hrTimeout).count());
-        if (res == 0) {
-            return -ETIMEDOUT;
-        }
-        if (res < 0) {
-            const auto error = errno;
-            if (error != EINTR) {
-                PLOG(ERROR) << "poll() failed";
-                return -error;
-            }
-        } else {
-            // empty the inotify fd first to not miss any new deletions,
-            // then check if the directory is empty.
-            char buffer[sizeof(inotify_event) + NAME_MAX + 1];
-            for (;;) {
-                auto err = TEMP_FAILURE_RETRY(::read(fd.get(), buffer, sizeof(buffer)));
-                if (err < 0) {
-                    if (errno == EAGAIN) { // no new events
-                        break;
-                    }
-                    return -errno;
-                }
-            }
-
-            size_t count = 0;
-            auto res = IncFs_ListIncompleteFiles(control, nullptr, &count);
-            if (!res) {
-                return 0;
-            }
-            if (res != -E2BIG) {
-                return res;
-            }
-        }
-        hrTimeout -= steady_clock::now() - startTs;
-    }
-
-    return -ETIMEDOUT;
-}
-
-IncFsErrorCode IncFs_WaitForFsWrittenBlocksChange(const IncFsControl* control, int32_t timeoutMs,
-                                                  IncFsSize* count) {
-    if (!control || !count) {
-        return -EINVAL;
-    }
-    if (!(features() & Features::v2)) {
-        return -ENOTSUP;
-    }
-
-    using namespace std::chrono;
-    auto hrTimeout = steady_clock::duration(milliseconds(timeoutMs));
-
-    while (hrTimeout > hrTimeout.zero()) {
-        const auto startTs = steady_clock::now();
-
-        pollfd pfd = {control->blocksWritten, POLLIN, 0};
-        const auto res = ::poll(&pfd, 1, duration_cast<milliseconds>(hrTimeout).count());
-        if (res > 0) {
-            break;
-        }
-        if (res == 0) {
-            return -ETIMEDOUT;
-        }
-        const auto error = errno;
-        if (error != EINTR) {
-            PLOG(ERROR) << "poll() failed";
-            return -error;
-        }
-        hrTimeout -= steady_clock::now() - startTs;
-    }
-
-    char str[32];
-    auto size = ::read(control->blocksWritten, str, sizeof(str));
-    if (size < 0) {
-        const auto error = errno;
-        PLOG(ERROR) << "read() failed";
-        return -error;
-    }
-    const auto res = std::from_chars(str, str + size, *count);
-    if (res.ec != std::errc{}) {
-        return res.ec == std::errc::invalid_argument ? -EINVAL : -ERANGE;
-    }
-
-    return 0;
-}
-
-static IncFsErrorCode reserveSpace(const char* backingPath, IncFsSize size) {
-    auto fd = ab::unique_fd(::open(backingPath, O_WRONLY | O_CLOEXEC));
-    if (fd < 0) {
-        return -errno;
-    }
-    struct stat st = {};
-    if (::fstat(fd.get(), &st)) {
-        return -errno;
-    }
-    if (size == kIncFsTrimReservedSpace) {
-        if (::ftruncate(fd.get(), st.st_size)) {
-            return -errno;
-        }
-    } else {
-        // Add 1.5% of the size for the hash tree and the blockmap, and some more blocks
-        // for fixed overhead.
-        // hash tree is ~33 bytes / page, and blockmap is 10 bytes / page
-        // no need to round to a page size as filesystems already do that.
-        const auto backingSize = IncFsSize(size * 1.015) + INCFS_DATA_FILE_BLOCK_SIZE * 4;
-        if (backingSize < st.st_size) {
-            return -EPERM;
-        }
-        if (::fallocate(fd.get(), FALLOC_FL_KEEP_SIZE, 0, backingSize)) {
-            return -errno;
-        }
-    }
-    return 0;
-}
-
-IncFsErrorCode IncFs_ReserveSpaceByPath(const IncFsControl* control, const char* path,
-                                        IncFsSize size) {
-    if (!control || (size != kIncFsTrimReservedSpace && size < 0)) {
-        return -EINVAL;
-    }
-    const auto [pathRoot, backingRoot, subpath] = registry().detailsFor(path);
-    const auto root = rootForCmd(control->cmd);
-    if (root.empty() || root != pathRoot) {
-        return -EINVAL;
-    }
-    return reserveSpace(path::join(backingRoot, subpath).c_str(), size);
-}
-
-IncFsErrorCode IncFs_ReserveSpaceById(const IncFsControl* control, IncFsFileId id, IncFsSize size) {
-    if (!control || (size != kIncFsTrimReservedSpace && size < 0)) {
-        return -EINVAL;
-    }
-    const auto root = rootForCmd(control->cmd);
-    if (root.empty()) {
-        return -EINVAL;
-    }
-    auto path = indexPath(root, id);
-    const auto [pathRoot, backingRoot, subpath] = registry().detailsFor(path);
-    if (root != pathRoot) {
-        return -EINVAL;
-    }
-    return reserveSpace(path::join(backingRoot, subpath).c_str(), size);
-}
-
-template <class IntType>
-static int readIntFromFile(std::string_view rootDir, std::string_view subPath, IntType& result) {
-    std::string content;
-    if (!ab::ReadFileToString(path::join(rootDir, subPath), &content)) {
-        PLOG(ERROR) << "IncFs_GetMetrics: failed to read file: " << rootDir << "/" << subPath;
-        return -errno;
-    }
-    const auto res = std::from_chars(content.data(), content.data() + content.size(), result);
-    if (res.ec != std::errc()) {
-        return -static_cast<int>(res.ec);
-    }
-    return 0;
-}
-
-IncFsErrorCode IncFs_GetMetrics(const char* sysfsName, IncFsMetrics* metrics) {
-    if (!sysfsName || !*sysfsName) {
-        return -EINVAL;
-    }
-
-    const auto kSysfsMetricsDir =
-            ab::StringPrintf("/sys/fs/%s/instances/%s", INCFS_NAME, sysfsName);
-
-    int err;
-    if (err = readIntFromFile(kSysfsMetricsDir, "reads_delayed_min", metrics->readsDelayedMin);
-        err != 0) {
-        return err;
-    }
-    if (err = readIntFromFile(kSysfsMetricsDir, "reads_delayed_min_us", metrics->readsDelayedMinUs);
-        err != 0) {
-        return err;
-    }
-    if (err = readIntFromFile(kSysfsMetricsDir, "reads_delayed_pending",
-                              metrics->readsDelayedPending);
-        err != 0) {
-        return err;
-    }
-    if (err = readIntFromFile(kSysfsMetricsDir, "reads_delayed_pending_us",
-                              metrics->readsDelayedPendingUs);
-        err != 0) {
-        return err;
-    }
-    if (err = readIntFromFile(kSysfsMetricsDir, "reads_failed_hash_verification",
-                              metrics->readsFailedHashVerification);
-        err != 0) {
-        return err;
-    }
-    if (err = readIntFromFile(kSysfsMetricsDir, "reads_failed_other", metrics->readsFailedOther);
-        err != 0) {
-        return err;
-    }
-    if (err = readIntFromFile(kSysfsMetricsDir, "reads_failed_timed_out",
-                              metrics->readsFailedTimedOut);
-        err != 0) {
-        return err;
-    }
-    return 0;
-}
-
-IncFsErrorCode IncFs_GetLastReadError(const IncFsControl* control,
-                                      IncFsLastReadError* lastReadError) {
-    if (!control) {
-        return -EINVAL;
-    }
-    if (!(features() & Features::v2)) {
-        return -ENOTSUP;
-    }
-    incfs_get_last_read_error_args args = {};
-    auto res = ::ioctl(control->cmd, INCFS_IOC_GET_LAST_READ_ERROR, &args);
-    if (res < 0) {
-        PLOG(ERROR) << "[incfs] IncFs_GetLastReadError failed.";
-        return -errno;
-    }
-    *lastReadError = IncFsLastReadError{
-            .timestampUs = args.time_us_out,
-            .block = static_cast<IncFsBlockIndex>(args.page_out),
-            .errorNo = args.errno_out,
-            .uid = static_cast<IncFsUid>(args.uid_out),
-    };
-    static_assert(sizeof(args.file_id_out.bytes) == sizeof(lastReadError->id.data));
-    memcpy(lastReadError->id.data, args.file_id_out.bytes, sizeof(args.file_id_out.bytes));
-    return 0;
-}
-
 MountRegistry& android::incfs::defaultMountRegistry() {
     return registry();
 }
diff --git a/incfs/incfsdump/dump.cpp b/incfs/incfsdump/dump.cpp
index 4959062..e6c49b6 100644
--- a/incfs/incfsdump/dump.cpp
+++ b/incfs/incfsdump/dump.cpp
@@ -47,6 +47,7 @@
 #include <string_view>
 
 using namespace std::literals;
+namespace ab = android::base;
 
 namespace {
 
@@ -198,7 +199,7 @@
 class Dump {
 public:
     Dump(std::string_view backingFile)
-          : mBackingFile(android::base::Basename(std::string(backingFile))), mIn(backingFile) {}
+          : mBackingFile(ab::Basename(std::string(backingFile))), mIn(backingFile) {}
 
     void run() {
         if (!mIn) {
diff --git a/incfs/include/MountRegistry.h b/incfs/include/MountRegistry.h
index 1ff320f..f8cfe4d 100644
--- a/incfs/include/MountRegistry.h
+++ b/incfs/include/MountRegistry.h
@@ -35,12 +35,8 @@
 
 class MountRegistry final {
 public:
-    struct Bind {
-        std::string subdir;
-        int rootIndex;
-    };
     // std::less<> enables heterogeneous lookups, e.g. by a string_view
-    using BindMap = std::map<std::string, Bind, std::less<>>;
+    using BindMap = std::map<std::string, std::pair<std::string, int>, std::less<>>;
 
     class Mounts final {
         struct Root {
@@ -84,7 +80,7 @@
         bool empty() const { return roots.empty(); }
 
         std::string_view rootFor(std::string_view path) const;
-        std::pair<const Root*, std::string> rootAndSubpathFor(std::string_view path) const;
+        std::pair<std::string_view, std::string> rootAndSubpathFor(std::string_view path) const;
 
         void swap(Mounts& other);
         void clear();
@@ -92,6 +88,7 @@
         void addRoot(std::string_view root, std::string_view backingDir);
         void removeRoot(std::string_view root);
         void addBind(std::string_view what, std::string_view where);
+        void moveBind(std::string_view src, std::string_view dest);
         void removeBind(std::string_view what);
 
     private:
@@ -106,14 +103,6 @@
 
     std::string rootFor(std::string_view path);
     std::pair<std::string, std::string> rootAndSubpathFor(std::string_view path);
-
-    struct Details {
-        std::string root;
-        std::string backing;
-        std::string subpath;
-    };
-    Details detailsFor(std::string_view path);
-
     Mounts copyMounts();
 
     void reload();
diff --git a/incfs/include/incfs.h b/incfs/include/incfs.h
index 5dfe060..79016d8 100644
--- a/incfs/include/incfs.h
+++ b/incfs/include/incfs.h
@@ -20,7 +20,6 @@
 #include <array>
 #include <chrono>
 #include <functional>
-#include <optional>
 #include <string>
 #include <string_view>
 #include <utility>
@@ -40,8 +39,6 @@
 enum Features {
     none = INCFS_FEATURE_NONE,
     core = INCFS_FEATURE_CORE,
-    v2 = INCFS_FEATURE_V2,
-    mappingFilesProgressFixed = INCFS_FEATURE_MAPPING_FILES_PROGRESS_FIXED,
 };
 
 enum class HashAlgorithm {
@@ -52,7 +49,6 @@
 enum class CompressionKind {
     none = INCFS_COMPRESSION_KIND_NONE,
     lz4 = INCFS_COMPRESSION_KIND_LZ4,
-    zstd = INCFS_COMPRESSION_KIND_ZSTD,
 };
 
 enum class BlockKind {
@@ -101,12 +97,9 @@
     IncFsFd cmd() const;
     IncFsFd pendingReads() const;
     IncFsFd logs() const;
-    IncFsFd blocksWritten() const;
-
+    operator IncFsControl*() const { return mControl; };
     void close();
 
-    operator IncFsControl*() const { return mControl; }
-
     using Fds = std::array<UniqueFd, IncFsFdType::FDS_COUNT>;
     [[nodiscard]] Fds releaseFds();
 
@@ -182,37 +175,28 @@
 using BlockIndex = IncFsBlockIndex;
 using ErrorCode = IncFsErrorCode;
 using Fd = IncFsFd;
-using Uid = IncFsUid;
 using ReadInfo = IncFsReadInfo;
-using ReadInfoWithUid = IncFsReadInfoWithUid;
 using RawMetadata = ByteBuffer;
 using RawSignature = ByteBuffer;
 using MountOptions = IncFsMountOptions;
 using DataBlock = IncFsDataBlock;
 using NewFileParams = IncFsNewFileParams;
-using NewMappedFileParams = IncFsNewMappedFileParams;
-using BlockCounts = IncFsBlockCounts;
-using UidReadTimeouts = IncFsUidReadTimeouts;
-using Metrics = IncFsMetrics;
-using LastReadError = IncFsLastReadError;
 
 constexpr auto kDefaultReadTimeout = std::chrono::milliseconds(INCFS_DEFAULT_READ_TIMEOUT_MS);
 constexpr int kBlockSize = INCFS_DATA_FILE_BLOCK_SIZE;
 const auto kInvalidFileId = kIncFsInvalidFileId;
-const auto kNoUid = kIncFsNoUid;
 
 bool enabled();
 Features features();
 bool isValidFileId(FileId fileId);
 std::string toString(FileId fileId);
 IncFsFileId toFileId(std::string_view str);
-bool isIncFsFd(int fd);
 bool isIncFsPath(std::string_view path);
 
 UniqueControl mount(std::string_view backingPath, std::string_view targetDir,
                     IncFsMountOptions options);
 UniqueControl open(std::string_view dir);
-UniqueControl createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs, IncFsFd blocksWritten);
+UniqueControl createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs);
 
 ErrorCode setOptions(const Control& control, MountOptions newOptions);
 
@@ -223,8 +207,6 @@
 
 ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId fileId,
                    NewFileParams params);
-ErrorCode makeMappedFile(const Control& control, std::string_view path, int mode,
-                         NewMappedFileParams params);
 ErrorCode makeDir(const Control& control, std::string_view path, int mode = 0555);
 ErrorCode makeDirs(const Control& control, std::string_view path, int mode = 0555);
 
@@ -244,10 +226,6 @@
                                std::vector<ReadInfo>* pendingReadsBuffer);
 WaitResult waitForPageReads(const Control& control, std::chrono::milliseconds timeout,
                             std::vector<ReadInfo>* pageReadsBuffer);
-WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
-                               std::vector<ReadInfoWithUid>* pendingReadsBuffer);
-WaitResult waitForPageReads(const Control& control, std::chrono::milliseconds timeout,
-                            std::vector<ReadInfoWithUid>* pageReadsBuffer);
 
 UniqueFd openForSpecialOps(const Control& control, FileId fileId);
 UniqueFd openForSpecialOps(const Control& control, std::string_view path);
@@ -257,33 +235,8 @@
 std::pair<ErrorCode, FilledRanges> getFilledRanges(int fd, FilledRanges::RangeBuffer&& buffer);
 std::pair<ErrorCode, FilledRanges> getFilledRanges(int fd, FilledRanges&& resumeFrom);
 
-ErrorCode setUidReadTimeouts(const Control& control, Span<const UidReadTimeouts> timeouts);
-std::optional<std::vector<UidReadTimeouts>> getUidReadTimeouts(const Control& control);
-
-std::optional<BlockCounts> getBlockCount(const Control& control, FileId fileId);
-std::optional<BlockCounts> getBlockCount(const Control& control, std::string_view path);
-
-std::optional<std::vector<FileId>> listIncompleteFiles(const Control& control);
-
-template <class Callback>
-ErrorCode forEachFile(const Control& control, Callback&& cb);
-template <class Callback>
-ErrorCode forEachIncompleteFile(const Control& control, Callback&& cb);
-
-WaitResult waitForLoadingComplete(const Control& control, std::chrono::milliseconds timeout);
-
 enum class LoadingState { Full, MissingBlocks };
 LoadingState isFullyLoaded(int fd);
-LoadingState isFullyLoaded(const Control& control, std::string_view path);
-LoadingState isFullyLoaded(const Control& control, FileId fileId);
-LoadingState isEverythingFullyLoaded(const Control& control);
-
-static const auto kTrimReservedSpace = kIncFsTrimReservedSpace;
-ErrorCode reserveSpace(const Control& control, std::string_view path, Size size);
-ErrorCode reserveSpace(const Control& control, FileId id, Size size);
-
-std::optional<Metrics> getMetrics(std::string_view sysfsName);
-std::optional<LastReadError> getLastReadError(const Control& control);
 
 // Some internal secret API as well that's not backed by C API yet.
 class MountRegistry;
diff --git a/incfs/include/incfs_inline.h b/incfs/include/incfs_inline.h
index f3d1e89..bcb7f15 100644
--- a/incfs/include/incfs_inline.h
+++ b/incfs/include/incfs_inline.h
@@ -28,14 +28,14 @@
 constexpr char kSizeAttrName[] = INCFS_XATTR_SIZE_NAME;
 constexpr char kMetadataAttrName[] = INCFS_XATTR_METADATA_NAME;
 
+constexpr char kIndexDir[] = ".index";
+
 namespace details {
 
 class CStrWrapper {
 public:
     CStrWrapper(std::string_view sv) {
-        if (!sv.data()) {
-            mCstr = "";
-        } else if (sv[sv.size()] == '\0') {
+        if (sv[sv.size()] == '\0') {
             mCstr = sv.data();
         } else {
             mCopy.emplace(sv);
@@ -70,10 +70,6 @@
     return Features(IncFs_Features());
 }
 
-inline bool isIncFsFd(int fd) {
-    return IncFs_IsIncFsFd(fd);
-}
-
 inline bool isIncFsPath(std::string_view path) {
     return IncFs_IsIncFsPath(details::c_str(path));
 }
@@ -116,10 +112,6 @@
     return IncFs_GetControlFd(mControl, LOGS);
 }
 
-inline IncFsFd UniqueControl::blocksWritten() const {
-    return IncFs_GetControlFd(mControl, BLOCKS_WRITTEN);
-}
-
 inline UniqueControl::Fds UniqueControl::releaseFds() {
     Fds result;
     IncFsFd fds[result.size()];
@@ -141,9 +133,8 @@
     return UniqueControl(control);
 }
 
-inline UniqueControl createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs,
-                                   IncFsFd blocksWritten) {
-    return UniqueControl(IncFs_CreateControl(cmd, pendingReads, logs, blocksWritten));
+inline UniqueControl createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs) {
+    return UniqueControl(IncFs_CreateControl(cmd, pendingReads, logs));
 }
 
 inline ErrorCode setOptions(const Control& control, MountOptions newOptions) {
@@ -174,10 +165,6 @@
                           NewFileParams params) {
     return IncFs_MakeFile(control, details::c_str(path), mode, fileId, params);
 }
-inline ErrorCode makeMappedFile(const Control& control, std::string_view path, int mode,
-                                NewMappedFileParams params) {
-    return IncFs_MakeMappedFile(control, details::c_str(path), mode, params);
-}
 inline ErrorCode makeDir(const Control& control, std::string_view path, int mode) {
     return IncFs_MakeDir(control, details::c_str(path), mode);
 }
@@ -238,15 +225,15 @@
     return IncFs_Unlink(control, details::c_str(path));
 }
 
-template <class ReadInfoStruct, class Impl>
-WaitResult waitForReads(const Control& control, std::chrono::milliseconds timeout,
-                        std::vector<ReadInfoStruct>* pendingReadsBuffer, size_t defaultBufferSize,
-                        Impl impl) {
+inline WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
+                                      std::vector<ReadInfo>* pendingReadsBuffer) {
+    static constexpr auto kDefaultBufferSize = INCFS_DEFAULT_PENDING_READ_BUFFER_SIZE;
     if (pendingReadsBuffer->empty()) {
-        pendingReadsBuffer->resize(defaultBufferSize);
+        pendingReadsBuffer->resize(kDefaultBufferSize);
     }
     size_t size = pendingReadsBuffer->size();
-    IncFsErrorCode err = impl(control, timeout.count(), pendingReadsBuffer->data(), &size);
+    IncFsErrorCode err =
+            IncFs_WaitForPendingReads(control, timeout.count(), pendingReadsBuffer->data(), &size);
     pendingReadsBuffer->resize(size);
     switch (err) {
         case 0:
@@ -257,32 +244,24 @@
     return WaitResult(err);
 }
 
-inline WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
-                                      std::vector<ReadInfo>* pendingReadsBuffer) {
-    return waitForReads(control, timeout, pendingReadsBuffer,
-                        INCFS_DEFAULT_PENDING_READ_BUFFER_SIZE, IncFs_WaitForPendingReads);
-}
-
-inline WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
-                                      std::vector<ReadInfoWithUid>* pendingReadsBuffer) {
-    return waitForReads(control, timeout, pendingReadsBuffer,
-                        INCFS_DEFAULT_PENDING_READ_BUFFER_SIZE, IncFs_WaitForPendingReadsWithUid);
-}
-
 inline WaitResult waitForPageReads(const Control& control, std::chrono::milliseconds timeout,
                                    std::vector<ReadInfo>* pageReadsBuffer) {
     static constexpr auto kDefaultBufferSize =
             INCFS_DEFAULT_PAGE_READ_BUFFER_PAGES * PAGE_SIZE / sizeof(ReadInfo);
-    return waitForReads(control, timeout, pageReadsBuffer, kDefaultBufferSize,
-                        IncFs_WaitForPageReads);
-}
-
-inline WaitResult waitForPageReads(const Control& control, std::chrono::milliseconds timeout,
-                                   std::vector<ReadInfoWithUid>* pageReadsBuffer) {
-    static constexpr auto kDefaultBufferSize =
-            INCFS_DEFAULT_PAGE_READ_BUFFER_PAGES * PAGE_SIZE / sizeof(ReadInfoWithUid);
-    return waitForReads(control, timeout, pageReadsBuffer, kDefaultBufferSize,
-                        IncFs_WaitForPageReadsWithUid);
+    if (pageReadsBuffer->empty()) {
+        pageReadsBuffer->resize(kDefaultBufferSize);
+    }
+    size_t size = pageReadsBuffer->size();
+    IncFsErrorCode err =
+            IncFs_WaitForPageReads(control, timeout.count(), pageReadsBuffer->data(), &size);
+    pageReadsBuffer->resize(size);
+    switch (err) {
+        case 0:
+            return WaitResult::HaveData;
+        case -ETIMEDOUT:
+            return WaitResult::Timeout;
+    }
+    return WaitResult(err);
 }
 
 inline UniqueFd openForSpecialOps(const Control& control, FileId fileId) {
@@ -337,7 +316,8 @@
     return {res, FilledRanges(std::move(buffer), rawRanges)};
 }
 
-inline LoadingState toLoadingState(IncFsErrorCode res) {
+inline LoadingState isFullyLoaded(int fd) {
+    auto res = IncFs_IsFullyLoaded(fd);
     switch (res) {
         case 0:
             return LoadingState::Full;
@@ -348,138 +328,6 @@
     }
 }
 
-inline LoadingState isFullyLoaded(int fd) {
-    return toLoadingState(IncFs_IsFullyLoaded(fd));
-}
-inline LoadingState isFullyLoaded(const Control& control, std::string_view path) {
-    return toLoadingState(IncFs_IsFullyLoadedByPath(control, details::c_str(path)));
-}
-inline LoadingState isFullyLoaded(const Control& control, FileId fileId) {
-    return toLoadingState(IncFs_IsFullyLoadedById(control, fileId));
-}
-
-inline LoadingState isEverythingFullyLoaded(const Control& control) {
-    return toLoadingState(IncFs_IsEverythingFullyLoaded(control));
-}
-
-inline std::optional<std::vector<FileId>> listIncompleteFiles(const Control& control) {
-    std::vector<FileId> ids(32);
-    size_t count = ids.size();
-    auto err = IncFs_ListIncompleteFiles(control, ids.data(), &count);
-    if (err == -E2BIG) {
-        ids.resize(count);
-        err = IncFs_ListIncompleteFiles(control, ids.data(), &count);
-    }
-    if (err) {
-        errno = -err;
-        return {};
-    }
-    ids.resize(count);
-    return std::move(ids);
-}
-
-template <class Callback>
-inline ErrorCode forEachFile(const Control& control, Callback&& cb) {
-    struct Context {
-        const Control& c;
-        const Callback& cb;
-    } context = {control, cb};
-    return IncFs_ForEachFile(control, &context, [](void* pcontext, const IncFsControl*, FileId id) {
-        const auto context = (Context*)pcontext;
-        return context->cb(context->c, id);
-    });
-}
-template <class Callback>
-inline ErrorCode forEachIncompleteFile(const Control& control, Callback&& cb) {
-    struct Context {
-        const Control& c;
-        const Callback& cb;
-    } context = {control, cb};
-    return IncFs_ForEachIncompleteFile(control, &context,
-                                       [](void* pcontext, const IncFsControl*, FileId id) {
-                                           const auto context = (Context*)pcontext;
-                                           return context->cb(context->c, id);
-                                       });
-}
-
-inline WaitResult waitForLoadingComplete(const Control& control,
-                                         std::chrono::milliseconds timeout) {
-    const auto res = IncFs_WaitForLoadingComplete(control, timeout.count());
-    switch (res) {
-        case 0:
-            return WaitResult::HaveData;
-        case -ETIMEDOUT:
-            return WaitResult::Timeout;
-        default:
-            return WaitResult(res);
-    }
-}
-
-inline std::optional<BlockCounts> getBlockCount(const Control& control, FileId fileId) {
-    BlockCounts counts;
-    auto res = IncFs_GetFileBlockCountById(control, fileId, &counts);
-    if (res) {
-        errno = -res;
-        return {};
-    }
-    return counts;
-}
-
-inline std::optional<BlockCounts> getBlockCount(const Control& control, std::string_view path) {
-    BlockCounts counts;
-    auto res = IncFs_GetFileBlockCountByPath(control, details::c_str(path), &counts);
-    if (res) {
-        errno = -res;
-        return {};
-    }
-    return counts;
-}
-
-inline ErrorCode setUidReadTimeouts(const Control& control, Span<const UidReadTimeouts> timeouts) {
-    return IncFs_SetUidReadTimeouts(control, timeouts.data(), timeouts.size());
-}
-
-inline std::optional<std::vector<UidReadTimeouts>> getUidReadTimeouts(const Control& control) {
-    std::vector<UidReadTimeouts> timeouts(32);
-    size_t count = timeouts.size();
-    auto res = IncFs_GetUidReadTimeouts(control, timeouts.data(), &count);
-    if (res == -E2BIG) {
-        timeouts.resize(count);
-        res = IncFs_GetUidReadTimeouts(control, timeouts.data(), &count);
-    }
-    if (res) {
-        errno = -res;
-        return {};
-    }
-    timeouts.resize(count);
-    return std::move(timeouts);
-}
-
-inline ErrorCode reserveSpace(const Control& control, std::string_view path, Size size) {
-    return IncFs_ReserveSpaceByPath(control, details::c_str(path), size);
-}
-inline ErrorCode reserveSpace(const Control& control, FileId id, Size size) {
-    return IncFs_ReserveSpaceById(control, id, size);
-}
-
-inline std::optional<Metrics> getMetrics(std::string_view sysfsName) {
-    Metrics metrics;
-    if (const auto res = IncFs_GetMetrics(details::c_str(sysfsName), &metrics); res < 0) {
-        errno = -res;
-        return {};
-    }
-    return metrics;
-}
-
-inline std::optional<LastReadError> getLastReadError(const Control& control) {
-    LastReadError lastReadError;
-    if (const auto res = IncFs_GetLastReadError(control, &lastReadError); res < 0) {
-        errno = -res;
-        return {};
-    }
-    return lastReadError;
-}
-
 } // namespace android::incfs
 
 inline bool operator==(const IncFsFileId& l, const IncFsFileId& r) {
diff --git a/incfs/include/incfs_ndk.h b/incfs/include/incfs_ndk.h
index 4862f39..0d9e8a6 100644
--- a/incfs/include/incfs_ndk.h
+++ b/incfs/include/incfs_ndk.h
@@ -43,10 +43,7 @@
 
 typedef enum {
     INCFS_FEATURE_NONE = 0,
-    INCFS_FEATURE_CORE = 1 << 0,
-    INCFS_FEATURE_V2 = 1 << 1,
-    INCFS_FEATURE_MAPPING_FILES_PROGRESS_FIXED = 1 << 2,
-
+    INCFS_FEATURE_CORE = 1,
 } IncFsFeatures;
 
 typedef int IncFsErrorCode;
@@ -54,9 +51,6 @@
 typedef int32_t IncFsBlockIndex;
 typedef int IncFsFd;
 typedef struct IncFsControl IncFsControl;
-typedef int IncFsUid;
-
-static const IncFsUid kIncFsNoUid = -1;
 
 typedef struct {
     const char* data;
@@ -67,7 +61,6 @@
     CMD,
     PENDING_READS,
     LOGS,
-    BLOCKS_WRITTEN,
     FDS_COUNT,
 } IncFsFdType;
 
@@ -92,13 +85,11 @@
     int32_t defaultReadTimeoutMs;
     int32_t readLogBufferPages;
     int32_t readLogDisableAfterTimeoutMs;
-    const char* sysfsName;
 } IncFsMountOptions;
 
 typedef enum {
     INCFS_COMPRESSION_KIND_NONE,
     INCFS_COMPRESSION_KIND_LZ4,
-    INCFS_COMPRESSION_KIND_ZSTD,
 } IncFsCompressionKind;
 
 typedef enum {
@@ -122,12 +113,6 @@
 } IncFsNewFileParams;
 
 typedef struct {
-    IncFsFileId sourceId;
-    IncFsSize sourceOffset;
-    IncFsSize size;
-} IncFsNewMappedFileParams;
-
-typedef struct {
     IncFsFileId id;
     uint64_t bootClockTsUs;
     IncFsBlockIndex block;
@@ -135,14 +120,6 @@
 } IncFsReadInfo;
 
 typedef struct {
-    IncFsFileId id;
-    uint64_t bootClockTsUs;
-    IncFsBlockIndex block;
-    uint32_t serialNo;
-    IncFsUid uid;
-} IncFsReadInfoWithUid;
-
-typedef struct {
     IncFsBlockIndex begin;
     IncFsBlockIndex end;
 } IncFsBlockRange;
@@ -155,40 +132,6 @@
     IncFsBlockIndex endIndex;
 } IncFsFilledRanges;
 
-typedef struct {
-    IncFsSize totalDataBlocks;
-    IncFsSize filledDataBlocks;
-    IncFsSize totalHashBlocks;
-    IncFsSize filledHashBlocks;
-} IncFsBlockCounts;
-
-typedef struct {
-    IncFsUid uid;
-    uint32_t minTimeUs;
-    uint32_t minPendingTimeUs;
-    uint32_t maxPendingTimeUs;
-} IncFsUidReadTimeouts;
-
-typedef struct {
-    uint32_t readsDelayedMin;
-    uint64_t readsDelayedMinUs;
-    uint32_t readsDelayedPending;
-    uint64_t readsDelayedPendingUs;
-    uint32_t readsFailedHashVerification;
-    uint32_t readsFailedOther;
-    uint32_t readsFailedTimedOut;
-    uint64_t reserved;
-    uint64_t reserved1;
-} IncFsMetrics;
-
-typedef struct {
-    IncFsFileId id;
-    uint64_t timestampUs;
-    IncFsBlockIndex block;
-    uint32_t errorNo;
-    IncFsUid uid;
-} IncFsLastReadError;
-
 // All functions return -errno in case of failure.
 // All IncFsFd functions return >=0 in case of success.
 // All IncFsFileId functions return invalid IncFsFileId on error.
@@ -197,7 +140,6 @@
 bool IncFs_IsEnabled();
 IncFsFeatures IncFs_Features();
 
-bool IncFs_IsIncFsFd(int fd);
 bool IncFs_IsIncFsPath(const char* path);
 
 static inline bool IncFs_IsValidFileId(IncFsFileId fileId) {
@@ -212,8 +154,7 @@
 IncFsControl* IncFs_Mount(const char* backingPath, const char* targetDir,
                           IncFsMountOptions options);
 IncFsControl* IncFs_Open(const char* dir);
-IncFsControl* IncFs_CreateControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs,
-                                  IncFsFd blocksWritten);
+IncFsControl* IncFs_CreateControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs);
 void IncFs_DeleteControl(IncFsControl* control);
 IncFsFd IncFs_GetControlFd(const IncFsControl* control, IncFsFdType type);
 IncFsSize IncFs_ReleaseControlFds(IncFsControl* control, IncFsFd out[], IncFsSize outSize);
@@ -227,9 +168,6 @@
 
 IncFsErrorCode IncFs_MakeFile(const IncFsControl* control, const char* path, int32_t mode,
                               IncFsFileId id, IncFsNewFileParams params);
-IncFsErrorCode IncFs_MakeMappedFile(const IncFsControl* control, const char* path, int32_t mode,
-                                    IncFsNewMappedFileParams params);
-
 IncFsErrorCode IncFs_MakeDir(const IncFsControl* control, const char* path, int32_t mode);
 IncFsErrorCode IncFs_MakeDirs(const IncFsControl* control, const char* path, int32_t mode);
 
@@ -255,45 +193,11 @@
 IncFsErrorCode IncFs_WaitForPageReads(const IncFsControl* control, int32_t timeoutMs,
                                       IncFsReadInfo buffer[], size_t* bufferSize);
 
-IncFsErrorCode IncFs_WaitForPendingReadsWithUid(const IncFsControl* control, int32_t timeoutMs,
-                                                IncFsReadInfoWithUid buffer[], size_t* bufferSize);
-IncFsErrorCode IncFs_WaitForPageReadsWithUid(const IncFsControl* control, int32_t timeoutMs,
-                                             IncFsReadInfoWithUid buffer[], size_t* bufferSize);
-
-IncFsErrorCode IncFs_WaitForFsWrittenBlocksChange(const IncFsControl* control, int32_t timeoutMs,
-                                                  IncFsSize* count);
-
 IncFsFd IncFs_OpenForSpecialOpsByPath(const IncFsControl* control, const char* path);
 IncFsFd IncFs_OpenForSpecialOpsById(const IncFsControl* control, IncFsFileId id);
 
 IncFsErrorCode IncFs_WriteBlocks(const IncFsDataBlock blocks[], size_t blocksCount);
 
-IncFsErrorCode IncFs_SetUidReadTimeouts(const IncFsControl* control,
-                                        const IncFsUidReadTimeouts timeouts[], size_t count);
-IncFsErrorCode IncFs_GetUidReadTimeouts(const IncFsControl* control,
-                                        IncFsUidReadTimeouts timeoutsBuffer[], size_t* bufferSize);
-
-IncFsErrorCode IncFs_GetFileBlockCountByPath(const IncFsControl* control, const char* path,
-                                             IncFsBlockCounts* blockCount);
-IncFsErrorCode IncFs_GetFileBlockCountById(const IncFsControl* control, IncFsFileId id,
-                                           IncFsBlockCounts* blockCount);
-
-IncFsErrorCode IncFs_ListIncompleteFiles(const IncFsControl* control, IncFsFileId ids[],
-                                         size_t* bufferSize);
-
-// Calls a passed callback for each file on the mounted filesystem, or, in the second case,
-// for each incomplete file (only for v2 IncFS).
-// Callback can stop the iteration early by returning |false|.
-// Return codes:
-// >=0      - number of files iterated,
-// <0       - -errno
-typedef bool (*FileCallback)(void* context, const IncFsControl* control, IncFsFileId fileId);
-IncFsErrorCode IncFs_ForEachFile(const IncFsControl* control, void* context, FileCallback cb);
-IncFsErrorCode IncFs_ForEachIncompleteFile(const IncFsControl* control, void* context,
-                                           FileCallback cb);
-
-IncFsErrorCode IncFs_WaitForLoadingComplete(const IncFsControl* control, int32_t timeoutMs);
-
 // Gets a collection of filled ranges in the file from IncFS. Uses the |outBuffer| memory, it has
 // to be big enough to fit all the ranges the caller is expecting.
 // Return codes:
@@ -309,38 +213,6 @@
 //  -ENODATA - some blocks are missing,
 //  <0       - error from the syscall.
 IncFsErrorCode IncFs_IsFullyLoaded(int fd);
-IncFsErrorCode IncFs_IsFullyLoadedByPath(const IncFsControl* control, const char* path);
-IncFsErrorCode IncFs_IsFullyLoadedById(const IncFsControl* control, IncFsFileId fileId);
-
-// Check if all files on the mount are fully loaded. Return codes:
-//  0        - fully loaded,
-//  -ENODATA - some blocks are missing,
-//  <0       - error from the syscall.
-IncFsErrorCode IncFs_IsEverythingFullyLoaded(const IncFsControl* control);
-
-// Reserve |size| bytes for the file. Trims reserved space to the current file size when |size = -1|
-static const IncFsSize kIncFsTrimReservedSpace = -1;
-IncFsErrorCode IncFs_ReserveSpaceByPath(const IncFsControl* control, const char* path,
-                                        IncFsSize size);
-IncFsErrorCode IncFs_ReserveSpaceById(const IncFsControl* control, IncFsFileId id, IncFsSize size);
-
-// Gets the metrics of a mount by specifying the corresponding sysfs subpath.
-// Return codes:
-// =0       - success
-// <0       - -errno
-IncFsErrorCode IncFs_GetMetrics(const char* sysfsName, IncFsMetrics* metrics);
-
-// Gets information about the last read error of a mount.
-// Return codes:
-// =0       - success
-// <0       - -errno
-// When there is no read error, still returns success. Fields in IncFsLastReadError will be all 0.
-// Possible values of IncFsLastReadError.errorNo:
-//   -ETIME for read timeout;
-//   -EBADMSG for hash verification failure;
-//   Other negative values for other types of errors.
-IncFsErrorCode IncFs_GetLastReadError(const IncFsControl* control,
-                                      IncFsLastReadError* lastReadError);
 
 __END_DECLS
 
diff --git a/incfs/kernel-headers/linux/incrementalfs.h b/incfs/kernel-headers/linux/incrementalfs.h
index d164cd9..b9f4c7a 100644
--- a/incfs/kernel-headers/linux/incrementalfs.h
+++ b/incfs/kernel-headers/linux/incrementalfs.h
@@ -18,7 +18,7 @@
 
 /* ===== constants ===== */
 #define INCFS_NAME "incremental-fs"
-#define INCFS_MAGIC_NUMBER (unsigned long)(0x5346434e49ul)
+#define INCFS_MAGIC_NUMBER (0x5346434e49ul)
 #define INCFS_DATA_FILE_BLOCK_SIZE 4096
 #define INCFS_HEADER_VER 1
 
@@ -28,15 +28,11 @@
 #define INCFS_MAX_HASH_SIZE 32
 #define INCFS_MAX_FILE_ATTR_SIZE 512
 
-#define INCFS_INDEX_NAME ".index"
-#define INCFS_INCOMPLETE_NAME ".incomplete"
 #define INCFS_PENDING_READS_FILENAME ".pending_reads"
 #define INCFS_LOG_FILENAME ".log"
-#define INCFS_BLOCKS_WRITTEN_FILENAME ".blocks_written"
 #define INCFS_XATTR_ID_NAME (XATTR_USER_PREFIX "incfs.id")
 #define INCFS_XATTR_SIZE_NAME (XATTR_USER_PREFIX "incfs.size")
 #define INCFS_XATTR_METADATA_NAME (XATTR_USER_PREFIX "incfs.metadata")
-#define INCFS_XATTR_VERITY_NAME (XATTR_USER_PREFIX "incfs.verity")
 
 #define INCFS_MAX_SIGNATURE_SIZE 8096
 #define INCFS_SIGNATURE_VERSION 2
@@ -46,10 +42,7 @@
 
 /* ===== ioctl requests on the command dir ===== */
 
-/*
- * Create a new file
- * May only be called on .pending_reads file
- */
+/* Create a new file */
 #define INCFS_IOC_CREATE_FILE \
 	_IOWR(INCFS_IOCTL_BASE_CODE, 30, struct incfs_new_file_args)
 
@@ -99,73 +92,9 @@
 #define INCFS_IOC_GET_FILLED_BLOCKS                                            \
 	_IOR(INCFS_IOCTL_BASE_CODE, 34, struct incfs_get_filled_blocks_args)
 
-/*
- * Creates a new mapped file
- * May only be called on .pending_reads file
- */
-#define INCFS_IOC_CREATE_MAPPED_FILE \
-	_IOWR(INCFS_IOCTL_BASE_CODE, 35, struct incfs_create_mapped_file_args)
-
-/*
- * Get number of blocks, total and filled
- * May only be called on .pending_reads file
- */
-#define INCFS_IOC_GET_BLOCK_COUNT \
-	_IOR(INCFS_IOCTL_BASE_CODE, 36, struct incfs_get_block_count_args)
-
-/*
- * Get per UID read timeouts
- * May only be called on .pending_reads file
- */
-#define INCFS_IOC_GET_READ_TIMEOUTS \
-	_IOR(INCFS_IOCTL_BASE_CODE, 37, struct incfs_get_read_timeouts_args)
-
-/*
- * Set per UID read timeouts
- * May only be called on .pending_reads file
- */
-#define INCFS_IOC_SET_READ_TIMEOUTS \
-	_IOW(INCFS_IOCTL_BASE_CODE, 38, struct incfs_set_read_timeouts_args)
-
-/*
- * Get last read error
- * May only be called on .pending_reads file
- */
-#define INCFS_IOC_GET_LAST_READ_ERROR \
-	_IOW(INCFS_IOCTL_BASE_CODE, 39, struct incfs_get_last_read_error_args)
-
-/* ===== sysfs feature flags ===== */
-/*
- * Each flag is represented by a file in /sys/fs/incremental-fs/features
- * If the file exists the feature is supported
- * Also the file contents will be the line "supported"
- */
-
-/*
- * Basic flag stating that the core incfs file system is available
- */
-#define INCFS_FEATURE_FLAG_COREFS "corefs"
-
-/*
- * zstd compression support
- */
-#define INCFS_FEATURE_FLAG_ZSTD "zstd"
-
-/*
- * v2 feature set support. Covers:
- *   INCFS_IOC_CREATE_MAPPED_FILE
- *   INCFS_IOC_GET_BLOCK_COUNT
- *   INCFS_IOC_GET_READ_TIMEOUTS/INCFS_IOC_SET_READ_TIMEOUTS
- *   .blocks_written status file
- *   .incomplete folder
- *   report_uid mount option
- */
-#define INCFS_FEATURE_FLAG_V2 "v2"
-
 enum incfs_compression_alg {
 	COMPRESSION_NONE = 0,
-	COMPRESSION_LZ4 = 1,
-	COMPRESSION_ZSTD = 2,
+	COMPRESSION_LZ4 = 1
 };
 
 enum incfs_block_flags {
@@ -180,8 +109,6 @@
 /*
  * Description of a pending read. A pending read - a read call by
  * a userspace program for which the filesystem currently doesn't have data.
- *
- * Reads from .pending_reads and .log return an array of these structure
  */
 struct incfs_pending_read_info {
 	/* Id of a file that is being read from. */
@@ -198,32 +125,6 @@
 };
 
 /*
- * Description of a pending read. A pending read - a read call by
- * a userspace program for which the filesystem currently doesn't have data.
- *
- * This version of incfs_pending_read_info is used whenever the file system is
- * mounted with the report_uid flag
- */
-struct incfs_pending_read_info2 {
-	/* Id of a file that is being read from. */
-	incfs_uuid_t file_id;
-
-	/* A number of microseconds since system boot to the read. */
-	__aligned_u64 timestamp_us;
-
-	/* Index of a file block that is being read. */
-	__u32 block_index;
-
-	/* A serial number of this pending read. */
-	__u32 serial_number;
-
-	/* The UID of the reading process */
-	__u32 uid;
-
-	__u32 reserved;
-};
-
-/*
  * Description of a data or hash block to add to a data file.
  */
 struct incfs_fill_block {
@@ -420,7 +321,7 @@
 	/* Actual number of blocks in file */
 	__u32 total_blocks_out;
 
-	/* The  number of data blocks in file */
+	/* The number of data blocks in file */
 	__u32 data_blocks_out;
 
 	/* Number of bytes written to range buffer */
@@ -430,154 +331,4 @@
 	__u32 index_out;
 };
 
-/*
- * Create a new mapped file
- * Argument for INCFS_IOC_CREATE_MAPPED_FILE
- */
-struct incfs_create_mapped_file_args {
-	/*
-	 * Total size of the new file.
-	 */
-	__aligned_u64 size;
-
-	/*
-	 * File mode. Permissions and dir flag.
-	 */
-	__u16 mode;
-
-	__u16 reserved1;
-
-	__u32 reserved2;
-
-	/*
-	 * A pointer to a null-terminated relative path to the incfs mount
-	 * point
-	 * Max length: PATH_MAX
-	 *
-	 * Equivalent to: char *directory_path;
-	 */
-	__aligned_u64 directory_path;
-
-	/*
-	 * A pointer to a null-terminated file name.
-	 * Max length: PATH_MAX
-	 *
-	 * Equivalent to: char *file_name;
-	 */
-	__aligned_u64 file_name;
-
-	/* Id of source file to map. */
-	incfs_uuid_t source_file_id;
-
-	/*
-	 * Offset in source file to start mapping. Must be a multiple of
-	 * INCFS_DATA_FILE_BLOCK_SIZE
-	 */
-	__aligned_u64 source_offset;
-};
-
-/*
- * Get information about the blocks in this file
- * Argument for INCFS_IOC_GET_BLOCK_COUNT
- */
-struct incfs_get_block_count_args {
-	/* Total number of data blocks in the file */
-	__u32 total_data_blocks_out;
-
-	/* Number of filled data blocks in the file */
-	__u32 filled_data_blocks_out;
-
-	/* Total number of hash blocks in the file */
-	__u32 total_hash_blocks_out;
-
-	/* Number of filled hash blocks in the file */
-	__u32 filled_hash_blocks_out;
-};
-
-/* Description of timeouts for one UID */
-struct incfs_per_uid_read_timeouts {
-	/* UID to apply these timeouts to */
-	__u32 uid;
-
-	/*
-	 * Min time in microseconds to read any block. Note that this doesn't
-	 * apply to reads which are satisfied from the page cache.
-	 */
-	__u32 min_time_us;
-
-	/*
-	 * Min time in microseconds to satisfy a pending read. Any pending read
-	 * which is filled before this time will be delayed so that the total
-	 * read time >= this value.
-	 */
-	__u32 min_pending_time_us;
-
-	/*
-	 * Max time in microseconds to satisfy a pending read before the read
-	 * times out. If set to U32_MAX, defaults to mount options
-	 * read_timeout_ms * 1000. Must be >= min_pending_time_us
-	 */
-	__u32 max_pending_time_us;
-};
-
-/*
- * Get the read timeouts array
- * Argument for INCFS_IOC_GET_READ_TIMEOUTS
- */
-struct incfs_get_read_timeouts_args {
-	/*
-	 * A pointer to a buffer to fill with the current timeouts
-	 *
-	 * Equivalent to struct incfs_per_uid_read_timeouts *
-	 */
-	__aligned_u64 timeouts_array;
-
-	/* Size of above buffer in bytes */
-	__u32 timeouts_array_size;
-
-	/* Size used in bytes, or size needed if -ENOMEM returned */
-	__u32 timeouts_array_size_out;
-};
-
-/*
- * Set the read timeouts array
- * Arguments for INCFS_IOC_SET_READ_TIMEOUTS
- */
-struct incfs_set_read_timeouts_args {
-	/*
-	 * A pointer to an array containing the new timeouts
-	 * This will replace any existing timeouts
-	 *
-	 * Equivalent to struct incfs_per_uid_read_timeouts *
-	 */
-	__aligned_u64 timeouts_array;
-
-	/* Size of above array in bytes. Must be < 256 */
-	__u32 timeouts_array_size;
-};
-
-/*
- * Get last read error struct
- * Arguments for INCFS_IOC_GET_LAST_READ_ERROR
- */
-struct incfs_get_last_read_error_args {
-	/* File id of last file that had a read error */
-	incfs_uuid_t	file_id_out;
-
-	/* Time of last read error, in us, from CLOCK_MONOTONIC */
-	__u64	time_us_out;
-
-	/* Index of page that was being read at last read error */
-	__u32	page_out;
-
-	/* errno of last read error */
-	__u32	errno_out;
-
-	/* uid of last read error */
-	__u32	uid_out;
-
-	__u32	reserved1;
-	__u64	reserved2;
-};
-
-#endif /* _UAPI_LINUX_INCREMENTALFS_H */
\ No newline at end of file
+#endif /* _UAPI_LINUX_INCREMENTALFS_H */
diff --git a/incfs/path.cpp b/incfs/path.cpp
index f6f87ae..8781571 100644
--- a/incfs/path.cpp
+++ b/incfs/path.cpp
@@ -121,19 +121,23 @@
     snprintf(fdNameBuffer, std::size(fdNameBuffer), fdNameFormat, fd);
 
     std::string res;
-    // We used to call lstat() here to preallocate the buffer to the exact required size; turns out
-    // that call is significantly more expensive than anything else, so doing a couple extra
-    // iterations is worth the savings.
-    auto bufSize = 256;
+    // lstat() is supposed to return us exactly the needed buffer size, but
+    // somehow it may also return a smaller (but still >0) st_size field.
+    // That's why let's only use it for the initial estimate.
+    struct stat st = {};
+    if (::lstat(fdNameBuffer, &st) || st.st_size == 0) {
+        st.st_size = PATH_MAX;
+    }
+    auto bufSize = st.st_size;
     for (;;) {
-        res.resize(bufSize - 1, '\0');
+        res.resize(bufSize + 1, '\0');
         auto size = ::readlink(fdNameBuffer, &res[0], res.size());
         if (size < 0) {
             PLOG(ERROR) << "readlink failed for " << fdNameBuffer;
             return {};
         }
-        if (size >= ssize_t(res.size())) {
-            // can't tell if the name is exactly that long, or got truncated - just repeat the call.
+        if (size > bufSize) {
+            // File got renamed in between lstat() and readlink() calls? Retry.
             bufSize *= 2;
             continue;
         }
@@ -145,14 +149,13 @@
     }
 }
 
-static void preparePathComponent(std::string_view& path, bool trimAll) {
-    // need to check for double front slash as a single one has a separate meaning in front
-    while (!path.empty() && path.front() == '/' &&
-           (trimAll || (path.size() > 1 && path[1] == '/'))) {
-        path.remove_prefix(1);
+static void preparePathComponent(std::string_view& path, bool trimFront) {
+    if (trimFront) {
+        while (!path.empty() && path.front() == '/') {
+            path.remove_prefix(1);
+        }
     }
-    // for the back we don't care about double-vs-single slash difference
-    while (path.size() > !trimAll && path.back() == '/') {
+    while (!path.empty() && path.back() == '/') {
         path.remove_suffix(1);
     }
 }
@@ -175,7 +178,7 @@
 }
 
 void details::appendNextPath(std::string& res, std::string_view path) {
-    preparePathComponent(path, !res.empty());
+    preparePathComponent(path, true);
     if (path.empty()) {
         return;
     }
@@ -185,6 +188,41 @@
     res += path;
 }
 
+std::string_view baseName(std::string_view path) {
+    if (path.empty()) {
+        return {};
+    }
+    if (path == "/"sv) {
+        return "/"sv;
+    }
+    auto pos = path.rfind('/');
+    while (!path.empty() && pos == path.size() - 1) {
+        path.remove_suffix(1);
+        pos = path.rfind('/');
+    }
+    if (pos == path.npos) {
+        return path.empty() ? "/"sv : path;
+    }
+    return path.substr(pos + 1);
+}
+
+std::string_view dirName(std::string_view path) {
+    if (path.empty()) {
+        return {};
+    }
+    if (path == "/"sv) {
+        return "/"sv;
+    }
+    const auto pos = path.rfind('/');
+    if (pos == 0) {
+        return "/"sv;
+    }
+    if (pos == path.npos) {
+        return "."sv;
+    }
+    return path.substr(0, pos);
+}
+
 std::pair<std::string_view, std::string_view> splitDirBase(std::string& full) {
     auto res = std::pair(dirName(full), baseName(full));
     if (res.first.data() == full.data()) {
diff --git a/incfs/include/path.h b/incfs/path.h
similarity index 62%
rename from incfs/include/path.h
rename to incfs/path.h
index 325eb1d..f312d17 100644
--- a/incfs/include/path.h
+++ b/incfs/path.h
@@ -48,43 +48,8 @@
 std::string_view relativize(std::string_view parent, std::string&& nested) = delete;
 
 // Note: some system headers #define 'dirname' and 'basename' as macros
-
-inline std::string_view baseName(std::string_view path) {
-    using namespace std::literals;
-    if (path.empty()) {
-        return {};
-    }
-    if (path == "/"sv) {
-        return "/"sv;
-    }
-    auto pos = path.rfind('/');
-    while (!path.empty() && pos == path.size() - 1) {
-        path.remove_suffix(1);
-        pos = path.rfind('/');
-    }
-    if (pos == path.npos) {
-        return path.empty() ? "/"sv : path;
-    }
-    return path.substr(pos + 1);
-}
-
-inline std::string_view dirName(std::string_view path) {
-    using namespace std::literals;
-    if (path.empty()) {
-        return {};
-    }
-    if (path == "/"sv) {
-        return "/"sv;
-    }
-    const auto pos = path.rfind('/');
-    if (pos == 0) {
-        return "/"sv;
-    }
-    if (pos == path.npos) {
-        return "."sv;
-    }
-    return path.substr(0, pos);
-}
+std::string_view dirName(std::string_view path);
+std::string_view baseName(std::string_view path);
 
 // Split the |full| path into its directory and basename components.
 // This modifies the input string to null-terminate the output directory
@@ -95,32 +60,20 @@
 bool endsWith(std::string_view path, std::string_view prefix);
 
 inline auto openDir(const char* path) {
-    struct closer {
-        void operator()(DIR* d) const { ::closedir(d); }
-    };
-    auto dir = std::unique_ptr<DIR, closer>(::opendir(path));
+    auto dir = std::unique_ptr<DIR, decltype(&closedir)>(::opendir(path), &::closedir);
     return dir;
 }
 
 template <class... Paths>
-std::string join(std::string&& first, std::string_view second, Paths&&... paths) {
-    std::string& result = first;
+std::string join(std::string_view first, std::string_view second, Paths&&... paths) {
+    std::string result;
     {
         using std::size;
         result.reserve(first.size() + second.size() + 1 + (sizeof...(paths) + ... + size(paths)));
     }
-    (details::appendNextPath(result, second), ...,
-     details::appendNextPath(result, std::forward<Paths>(paths)));
+    result.assign(first);
+    (details::appendNextPath(result, second), ..., details::appendNextPath(result, paths));
     return result;
 }
 
-template <class... Paths>
-std::string join(std::string_view first, std::string_view second, Paths&&... paths) {
-    return join(std::string(), first, second, std::forward<Paths>(paths)...);
-}
-template <class... Paths>
-std::string join(const char* first, std::string_view second, Paths&&... paths) {
-    return path::join(std::string_view(first), second, std::forward<Paths>(paths)...);
-}
-
 } // namespace android::incfs::path
diff --git a/incfs/tests/MountRegistry_test.cpp b/incfs/tests/MountRegistry_test.cpp
index bb3ba49..2b82eb0 100644
--- a/incfs/tests/MountRegistry_test.cpp
+++ b/incfs/tests/MountRegistry_test.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include "MountRegistry.h"
-
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
@@ -23,11 +21,10 @@
 #include <sys/select.h>
 #include <unistd.h>
 
-#include <iterator>
 #include <optional>
 #include <thread>
 
-#include "incfs.h"
+#include "MountRegistry.h"
 #include "path.h"
 
 using namespace android::incfs;
@@ -75,97 +72,9 @@
     ASSERT_STREQ("/root", r().rootFor("/bind").data());
     ASSERT_STREQ("/root", r().rootFor("/bind2").data());
     ASSERT_STREQ("/root", r().rootFor("/other/bind/dir").data());
-    ASSERT_EQ("/root"s, r().rootAndSubpathFor("/root").first->path);
-    ASSERT_EQ(""s, r().rootAndSubpathFor("/root").second);
-    ASSERT_EQ("/root"s, r().rootAndSubpathFor("/bind").first->path);
-    ASSERT_EQ("1"s, r().rootAndSubpathFor("/bind").second);
-    ASSERT_EQ("/root"s, r().rootAndSubpathFor("/bind2").first->path);
-    ASSERT_EQ("2/3"s, r().rootAndSubpathFor("/bind2").second);
-    ASSERT_EQ("/root"s, r().rootAndSubpathFor("/bind2/blah").first->path);
-    ASSERT_EQ("2/3/blah"s, r().rootAndSubpathFor("/bind2/blah").second);
-    ASSERT_EQ("/root"s, r().rootAndSubpathFor("/other/bind/blah").first->path);
-    ASSERT_EQ("2/3/blah"s, r().rootAndSubpathFor("/other/bind/blah").second);
-}
-
-TEST_F(MountRegistryTest, MultiRoot) {
-    r().addRoot("/root", "/backing");
-    r().addBind("/root", "/bind");
-    ASSERT_STREQ("/root", r().rootFor("/root").data());
-    ASSERT_STREQ("/root", r().rootFor("/bind").data());
-    ASSERT_STREQ("/root", r().rootFor("/bind/2").data());
-}
-
-static MountRegistry::Mounts makeFrom(std::string_view str) {
-    TemporaryFile f;
-    EXPECT_TRUE(android::base::WriteFully(f.fd, str.data(), str.size()));
-    EXPECT_EQ(0, lseek(f.fd, 0, SEEK_SET)); // rewind
-
-    MountRegistry::Mounts m;
-    EXPECT_TRUE(m.loadFrom(f.fd, INCFS_NAME));
-    return std::move(m);
-}
-
-TEST_F(MountRegistryTest, MultiRootLoad) {
-    constexpr char mountsFile[] =
-            R"(4605 34 0:154 / /mnt/installer/0/0000000000000000000000000000CAFEF00D2019 rw,nosuid,nodev,noexec,noatime shared:45 master:43 - fuse /dev/fuse rw,lazytime,user_id=0,group_id=0,allow_other
-4561 35 0:154 / /mnt/androidwritable/0/0000000000000000000000000000CAFEF00D2019 rw,nosuid,nodev,noexec,noatime shared:44 master:43 - fuse /dev/fuse rw,lazytime,user_id=0,group_id=0,allow_other
-4560 99 0:154 / /storage/0000000000000000000000000000CAFEF00D2019 rw,nosuid,nodev,noexec,noatime master:43 - fuse /dev/fuse rw,lazytime,user_id=0,group_id=0,allow_other
-4650 30 0:44 /MyFiles /mnt/pass_through/0/0000000000000000000000000000CAFEF00D2019 rw,nosuid,nodev,noexec,relatime shared:31 - 9p media rw,sync,dirsync,access=client,trans=virtio
-3181 79 0:146 / /data/incremental/MT_data_app_vmdl703/mount rw,nosuid,nodev,noatime shared:46 - incremental-fs /data/incremental/MT_data_app_vmdl703/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0
-3182 77 0:146 / /var/run/mount/data/mount/data/incremental/MT_data_app_vmdl703/mount rw,nosuid,nodev,noatime shared:46 - incremental-fs /data/incremental/MT_data_app_vmdl703/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0
-)";
-
-    auto m = makeFrom(mountsFile);
-
-    EXPECT_EQ(size_t(1), m.size());
-    EXPECT_STREQ("/data/incremental/MT_data_app_vmdl703/mount",
-                 m.rootFor("/data/incremental/MT_data_app_vmdl703/mount/123/2").data());
-    EXPECT_STREQ("/data/incremental/MT_data_app_vmdl703/mount",
-                 m.rootFor("/var/run/mount/data/mount/data/incremental/MT_data_app_vmdl703/mount/"
-                           "some/thing")
-                         .data());
-}
-
-TEST_F(MountRegistryTest, MultiRootLoadReversed) {
-    constexpr char mountsFile[] =
-            R"(4605 34 0:154 / /mnt/installer/0/0000000000000000000000000000CAFEF00D2019 rw,nosuid,nodev,noexec,noatime shared:45 master:43 - fuse /dev/fuse rw,lazytime,user_id=0,group_id=0,allow_other
-4561 35 0:154 / /mnt/androidwritable/0/0000000000000000000000000000CAFEF00D2019 rw,nosuid,nodev,noexec,noatime shared:44 master:43 - fuse /dev/fuse rw,lazytime,user_id=0,group_id=0,allow_other
-4560 99 0:154 / /storage/0000000000000000000000000000CAFEF00D2019 rw,nosuid,nodev,noexec,noatime master:43 - fuse /dev/fuse rw,lazytime,user_id=0,group_id=0,allow_other
-4650 30 0:44 /MyFiles /mnt/pass_through/0/0000000000000000000000000000CAFEF00D2019 rw,nosuid,nodev,noexec,relatime shared:31 - 9p media rw,sync,dirsync,access=client,trans=virtio
-3182 77 0:146 / /var/run/mount/data/mount/data/incremental/MT_data_app_vmdl703/mount rw,nosuid,nodev,noatime shared:46 - incremental-fs /data/incremental/MT_data_app_vmdl703/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0
-3181 79 0:146 / /data/incremental/MT_data_app_vmdl703/mount rw,nosuid,nodev,noatime shared:46 - incremental-fs /data/incremental/MT_data_app_vmdl703/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0
-)";
-
-    auto m = makeFrom(mountsFile);
-
-    EXPECT_EQ(size_t(1), m.size());
-    EXPECT_STREQ("/data/incremental/MT_data_app_vmdl703/mount",
-                 m.rootFor("/data/incremental/MT_data_app_vmdl703/mount/123/2").data());
-    EXPECT_STREQ("/data/incremental/MT_data_app_vmdl703/mount",
-                 m.rootFor("/var/run/mount/data/mount/data/incremental/MT_data_app_vmdl703/mount/"
-                           "some/thing")
-                         .data());
-}
-
-TEST_F(MountRegistryTest, LoadInvalid) {
-    constexpr char mountsFile[] =
-            R"(9465 93 0:281 // /data/incremental1 shared:56 - incremental-fs /data/incremental2 rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-9529 93 0:281 /st_232_0 /data/app/vmdl1998506227.tmp rw,nosuid,nodev,noatime shared:56 - incremental-fs /data/incremental/MT_data_app_vmdl199/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-9657 93 0:282 /st_233_0 /data/app/vmdl2034419270.tmp rw,nosuid,nodev,noatime shared:57 - incremental-fs /data/incremental/MT_data_app_vmdl203/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-9721 93 0:283 / /data/incremental/MT_data_app_vmdl154/mount rw,nosuid,nodev,noatime shared:58 - incremental-fs /data/incremental/MT_data_app_vmdl154/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-9785 93 0:283 /st_234_0 /data/app/vmdl1545425783.tmp rw,nosuid,nodev,noatime shared:58 - incremental-fs /data/incremental/MT_data_app_vmdl154/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-9849 93 0:284 / /data/incremental/MT_data_app_vmdl209/mount rw,nosuid,nodev,noatime shared:59 - incremental-fs /data/incremental/MT_data_app_vmdl209/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-9913 93 0:284 /st_235_0 /data/app/vmdl2099748756.tmp rw,nosuid,nodev,noatime shared:59 - incremental-fs /data/incremental/MT_data_app_vmdl209/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-4007 93 0:269 /st_240_1 /data/app/~~I499PLubwcOVbJaEFqpHHQ== rw,nosuid,nodev,noatime shared:44 - incremental-fs /data/incremental/MT_data_app_vmdl158/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-5285 93 0:270 /st_241_1 /data/app/~~CvgMdGm9eNJpvdq-62Jktg== rw,nosuid,nodev,noatime shared:45 - incremental-fs /data/incremental/MT_data_app_vmdl943/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-8786 93 0:271 /st_242_1 /data/app/~~_oNudLuBvqtSE78VoMVY5Q== rw,nosuid,nodev,noatime shared:46 - incremental-fs /data/incremental/MT_data_app_vmdl144/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-10358 93 0:272 /st_243_1 /data/app/~~o5-RadxV4DUe-mgPyv9SkQ== rw,nosuid,nodev,noatime shared:47 - incremental-fs /data/incremental/MT_data_app_vmdl642/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-10422 93 0:131 /st_244_1 /data/app/~~rTnKswx1F427UguGO9nDRA== rw,nosuid,nodev,noatime shared:48 - incremental-fs /data/incremental/MT_data_app_vmdl336/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-10486 93 0:132 /st_245_1 /data/app/~~ZIoVqPDBjLBeajD4thHsYA== rw,nosuid,nodev,noatime shared:49 - incremental-fs /data/incremental/MT_data_app_vmdl993/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-10550 93 0:133 /st_246_1 /data/app/~~2qjtCtx5rqPW2Hwlrciu2w== rw,nosuid,nodev,noatime shared:50 - incremental-fs /data/incremental/MT_data_app_vmdl827/backing_store rw,seclabel,read_timeout_ms=10000,readahead=0,report_uid
-)";
-
-    auto m = makeFrom(mountsFile);
-    // only two of the mounts in this file are valid
-    EXPECT_EQ(size_t(2), m.size());
+    ASSERT_EQ(std::pair("/root"sv, ""s), r().rootAndSubpathFor("/root"));
+    ASSERT_EQ(std::pair("/root"sv, "1"s), r().rootAndSubpathFor("/bind"));
+    ASSERT_EQ(std::pair("/root"sv, "2/3"s), r().rootAndSubpathFor("/bind2"));
+    ASSERT_EQ(std::pair("/root"sv, "2/3/blah"s), r().rootAndSubpathFor("/bind2/blah"));
+    ASSERT_EQ(std::pair("/root"sv, "2/3/blah"s), r().rootAndSubpathFor("/other/bind/blah"));
 }
diff --git a/incfs/tests/hardening_benchmark.cpp b/incfs/tests/hardening_benchmark.cpp
deleted file mode 100644
index 8e4f047..0000000
--- a/incfs/tests/hardening_benchmark.cpp
+++ /dev/null
@@ -1,165 +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/file.h>
-#include <android-base/mapped_file.h>
-#include <benchmark/benchmark.h>
-#include <unistd.h>
-
-#include "incfs_support/access.h"
-#include "incfs_support/signal_handling.h"
-#include "util/map_ptr.h"
-
-static std::unique_ptr<TemporaryFile> makeFile() {
-    auto tmp = std::unique_ptr<TemporaryFile>(new TemporaryFile());
-    char c = 1;
-    write(tmp->fd, &c, sizeof(c));
-    return tmp;
-}
-
-static std::pair<std::unique_ptr<TemporaryFile>, std::unique_ptr<android::base::MappedFile>>
-makeEmptyFileMapping() {
-    auto tmp = makeFile();
-    // mmap() only works for non-empty files, but it's "ok" to resize it back to empty afterwards
-    auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
-    ftruncate(tmp->fd, 0);
-    return {std::move(tmp), std::move(mapping)};
-}
-
-static void TestEmpty(benchmark::State& state) {
-    int val = 0;
-    for (auto _ : state) {
-        benchmark::DoNotOptimize(val += 1);
-    }
-}
-BENCHMARK(TestEmpty);
-
-static void TestSignal(benchmark::State& state) {
-    auto tmp = makeFile();
-    auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
-
-    int val;
-    for (auto _ : state) {
-        SCOPED_SIGBUS_HANDLER({ break; });
-        val += *mapping->data();
-    }
-}
-BENCHMARK(TestSignal);
-
-static void TestRead(benchmark::State& state) {
-    auto tmp = makeFile();
-    int val = 0;
-    for (auto _ : state) {
-        char c;
-        pread(tmp->fd, &c, sizeof(c), 0);
-        val += c;
-    }
-}
-BENCHMARK(TestRead);
-
-static void TestMapPtrRaw(benchmark::State& state) {
-    auto tmp = makeFile();
-    android::incfs::IncFsFileMap map;
-    map.CreateForceVerification(tmp->fd, 0, 1, tmp->path, true);
-    int val = 0;
-    const uint8_t* prev_block = nullptr;
-    for (auto _ : state) {
-        auto start = static_cast<const uint8_t*>(map.unsafe_data());
-        auto end = start + map.length();
-        val += map.Verify(start, end, &prev_block);
-    }
-}
-BENCHMARK(TestMapPtrRaw);
-
-static void TestMapPtr(benchmark::State& state) {
-    auto tmp = makeFile();
-    android::incfs::IncFsFileMap map;
-    map.CreateForceVerification(tmp->fd, 0, 1, tmp->path, true);
-    int val = 0;
-    for (auto _ : state) {
-        val += map.data<char>().verify();
-    }
-}
-BENCHMARK(TestMapPtr);
-
-static void TestAccess(benchmark::State& state) {
-    auto tmp = makeFile();
-    auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
-    int val = 0;
-    for (auto _ : state) {
-        incfs::access(mapping->data(), [&](auto ptr) { val += *ptr; });
-    }
-}
-BENCHMARK(TestAccess);
-
-static void TestAccessFast(benchmark::State& state) {
-    auto tmp = makeFile();
-    auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
-    int val = 0;
-    incfs::access(mapping->data(), [&](auto ptr) {
-        for (auto _ : state) {
-            val += *ptr;
-        }
-    });
-}
-BENCHMARK(TestAccessFast);
-
-static void TestAccessVal(benchmark::State& state) {
-    auto tmp = makeFile();
-    auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
-    int val = 0;
-    for (auto _ : state) {
-        incfs::access(mapping->data(), [&](auto ptr) { return val += *ptr; });
-    }
-}
-BENCHMARK(TestAccessVal);
-
-static void TestAccessNested(benchmark::State& state) {
-    auto tmp = makeFile();
-    auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
-    int val = 0;
-    incfs::access(nullptr, [&](auto) {
-        for (auto _ : state) {
-            incfs::access(mapping->data(), [&](auto ptr) { val += *ptr; });
-        }
-    });
-}
-BENCHMARK(TestAccessNested);
-
-static void TestAccessDoubleNested(benchmark::State& state) {
-    auto tmp = makeFile();
-    auto mapping = android::base::MappedFile::FromFd(tmp->fd, 0, 1, PROT_READ);
-    int val = 0;
-    incfs::access(nullptr, [&](auto) {
-        incfs::access(nullptr, [&](auto) {
-            for (auto _ : state) {
-                incfs::access(mapping->data(), [&](auto ptr) { val += *ptr; });
-            }
-        });
-    });
-}
-BENCHMARK(TestAccessDoubleNested);
-
-static void TestAccessError(benchmark::State& state) {
-    auto [tmp, mapping] = makeEmptyFileMapping();
-    int val = 0;
-    for (auto _ : state) {
-        incfs::access(mapping->data(), [&](auto ptr) { val += *ptr; });
-    }
-}
-BENCHMARK(TestAccessError);
-
-BENCHMARK_MAIN();
diff --git a/incfs/tests/incfs_test.cpp b/incfs/tests/incfs_test.cpp
index 94bbdcd..1dc419f 100644
--- a/incfs/tests/incfs_test.cpp
+++ b/incfs/tests/incfs_test.cpp
@@ -14,20 +14,27 @@
  * limitations under the License.
  */
 
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <sys/select.h>
+#include "incfs.h"
 
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+#include <selinux/selinux.h>
+#include <sys/select.h>
 #include <unistd.h>
 
 #include <optional>
 #include <thread>
 
-#include "IncFsTestBase.h"
+#include "path.h"
 
 using namespace android::incfs;
 using namespace std::literals;
-namespace ab = android::base;
+
+static bool exists(std::string_view path) {
+    return access(path.data(), F_OK) == 0;
+}
 
 struct ScopedUnmount {
     std::string path_;
@@ -35,16 +42,90 @@
     ~ScopedUnmount() { unmount(path_); }
 };
 
-class IncFsTest : public IncFsTestBase {
+class IncFsTest : public ::testing::Test {
 protected:
-    virtual int32_t getReadTimeout() {
-        return std::chrono::duration_cast<std::chrono::milliseconds>(kDefaultReadTimeout).count();
+    virtual void SetUp() {
+        tmp_dir_for_mount_.emplace();
+        mount_dir_path_ = tmp_dir_for_mount_->path;
+        tmp_dir_for_image_.emplace();
+        image_dir_path_ = tmp_dir_for_image_->path;
+        ASSERT_TRUE(exists(image_dir_path_));
+        ASSERT_TRUE(exists(mount_dir_path_));
+        if (!enabled()) {
+            GTEST_SKIP() << "test not supported: IncFS is not enabled";
+        } else {
+            control_ =
+                    mount(image_dir_path_, mount_dir_path_,
+                          MountOptions{.readLogBufferPages = 4,
+                                       .defaultReadTimeoutMs = std::chrono::duration_cast<
+                                                                       std::chrono::milliseconds>(
+                                                                       kDefaultReadTimeout)
+                                                                       .count()});
+            ASSERT_TRUE(control_.cmd() >= 0) << "Expected >= 0 got " << control_.cmd();
+            ASSERT_TRUE(control_.pendingReads() >= 0);
+            ASSERT_TRUE(control_.logs() >= 0);
+            checkRestoreconResult(mountPath(INCFS_PENDING_READS_FILENAME));
+            checkRestoreconResult(mountPath(INCFS_LOG_FILENAME));
+        }
+    }
+
+    static void checkRestoreconResult(std::string_view path) {
+        char* ctx = nullptr;
+        ASSERT_NE(-1, getfilecon(path.data(), &ctx));
+        ASSERT_EQ("u:object_r:shell_data_file:s0", std::string(ctx));
+        freecon(ctx);
+    }
+
+    virtual void TearDown() {
+        unmount(mount_dir_path_);
+        tmp_dir_for_image_.reset();
+        tmp_dir_for_mount_.reset();
+        EXPECT_FALSE(exists(image_dir_path_));
+        EXPECT_FALSE(exists(mount_dir_path_));
+    }
+
+    template <class... Paths>
+    std::string mountPath(Paths&&... paths) const {
+        return path::join(mount_dir_path_, std::forward<Paths>(paths)...);
+    }
+
+    static IncFsFileId fileId(uint64_t i) {
+        IncFsFileId id = {};
+        static_assert(sizeof(id) >= sizeof(i));
+        memcpy(&id, &i, sizeof(i));
+        return id;
     }
 
     static IncFsSpan metadata(std::string_view sv) {
         return {.data = sv.data(), .size = IncFsSize(sv.size())};
     }
 
+    int makeFileWithHash(int id) {
+        // calculate the required size for two leaf hash blocks
+        constexpr auto size =
+                (INCFS_DATA_FILE_BLOCK_SIZE / INCFS_MAX_HASH_SIZE + 1) * INCFS_DATA_FILE_BLOCK_SIZE;
+
+        // assemble a signature/hashing data for it
+        struct __attribute__((packed)) Signature {
+            uint32_t version = INCFS_SIGNATURE_VERSION;
+            uint32_t hashingSize = sizeof(hashing);
+            struct __attribute__((packed)) Hashing {
+                uint32_t algo = INCFS_HASH_TREE_SHA256;
+                uint8_t log2Blocksize = 12;
+                uint32_t saltSize = 0;
+                uint32_t rootHashSize = INCFS_MAX_HASH_SIZE;
+                char rootHash[INCFS_MAX_HASH_SIZE] = {};
+            } hashing;
+            uint32_t signingSize = 0;
+        } signature;
+
+        int res = makeFile(control_, mountPath(test_file_name_), 0555, fileId(id),
+                           {.size = size,
+                            .signature = {.data = (char*)&signature, .size = sizeof(signature)}});
+        EXPECT_EQ(0, res);
+        return res ? -1 : size;
+    }
+
     static int sizeToPages(int size) {
         return (size + INCFS_DATA_FILE_BLOCK_SIZE - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
     }
@@ -105,100 +186,14 @@
         ASSERT_EQ((int)std::size(blocks), writeBlocks({blocks, std::size(blocks)}));
     }
 
-    void writeBlock(int pageIndex) {
-        auto fd = openForSpecialOps(control_, fileId(1));
-        ASSERT_GE(fd.get(), 0);
-
-        std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE);
-        auto block = DataBlock{
-                .fileFd = fd.get(),
-                .pageIndex = pageIndex,
-                .compression = INCFS_COMPRESSION_KIND_NONE,
-                .dataSize = (uint32_t)data.size(),
-                .data = data.data(),
-        };
-        ASSERT_EQ(1, writeBlocks({&block, 1}));
-    }
-
-    template <class ReadStruct>
-    void testWriteBlockAndPageRead() {
-        const auto id = fileId(1);
-        ASSERT_TRUE(control_.logs() >= 0);
-        ASSERT_EQ(0,
-                  makeFile(control_, mountPath(test_file_name_), 0555, id,
-                           {.size = test_file_size_}));
-        writeBlock(/*pageIndex=*/0);
-
-        std::thread wait_page_read_thread([&]() {
-            std::vector<ReadStruct> reads;
-            auto res = waitForPageReads(control_, std::chrono::seconds(5), &reads);
-            ASSERT_EQ(WaitResult::HaveData, res) << (int)res;
-            ASSERT_FALSE(reads.empty());
-            EXPECT_EQ(0, memcmp(&id, &reads[0].id, sizeof(id)));
-            EXPECT_EQ(0, int(reads[0].block));
-            if constexpr (std::is_same_v<ReadStruct, ReadInfoWithUid>) {
-                if (features() & Features::v2) {
-                    EXPECT_NE(kIncFsNoUid, int(reads[0].uid));
-                } else {
-                    EXPECT_EQ(kIncFsNoUid, int(reads[0].uid));
-                }
-            }
-        });
-
-        const auto file_path = mountPath(test_file_name_);
-        const android::base::unique_fd readFd(
-                open(file_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
-        ASSERT_TRUE(readFd >= 0);
-        char buf[INCFS_DATA_FILE_BLOCK_SIZE];
-        ASSERT_TRUE(android::base::ReadFully(readFd, buf, sizeof(buf)));
-        wait_page_read_thread.join();
-    }
-
-    template <class PendingRead>
-    void testWaitForPendingReads() {
-        const auto id = fileId(1);
-        ASSERT_EQ(0,
-                  makeFile(control_, mountPath(test_file_name_), 0555, id,
-                           {.size = test_file_size_}));
-
-        std::thread wait_pending_read_thread([&]() {
-            std::vector<PendingRead> pending_reads;
-            ASSERT_EQ(WaitResult::HaveData,
-                      waitForPendingReads(control_, std::chrono::seconds(10), &pending_reads));
-            ASSERT_GT(pending_reads.size(), 0u);
-            EXPECT_EQ(0, memcmp(&id, &pending_reads[0].id, sizeof(id)));
-            EXPECT_EQ(0, (int)pending_reads[0].block);
-            if constexpr (std::is_same_v<PendingRead, ReadInfoWithUid>) {
-                if (features() & Features::v2) {
-                    EXPECT_NE(kIncFsNoUid, int(pending_reads[0].uid));
-                } else {
-                    EXPECT_EQ(kIncFsNoUid, int(pending_reads[0].uid));
-                }
-            }
-
-            auto fd = openForSpecialOps(control_, fileId(1));
-            ASSERT_GE(fd.get(), 0);
-
-            std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE);
-            auto block = DataBlock{
-                    .fileFd = fd.get(),
-                    .pageIndex = 0,
-                    .compression = INCFS_COMPRESSION_KIND_NONE,
-                    .dataSize = (uint32_t)data.size(),
-                    .data = data.data(),
-            };
-            ASSERT_EQ(1, writeBlocks({&block, 1}));
-        });
-
-        const auto file_path = mountPath(test_file_name_);
-        const android::base::unique_fd fd(open(file_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
-        ASSERT_GE(fd.get(), 0);
-        char buf[INCFS_DATA_FILE_BLOCK_SIZE];
-        ASSERT_TRUE(android::base::ReadFully(fd, buf, sizeof(buf)));
-        wait_pending_read_thread.join();
-    }
-
+    std::string mount_dir_path_;
+    std::optional<TemporaryDir> tmp_dir_for_mount_;
+    std::string image_dir_path_;
+    std::optional<TemporaryDir> tmp_dir_for_image_;
+    inline static const std::string_view test_file_name_ = "test.txt"sv;
+    inline static const std::string_view test_dir_name_ = "test_dir"sv;
     inline static const int test_file_size_ = INCFS_DATA_FILE_BLOCK_SIZE;
+    Control control_;
 };
 
 TEST_F(IncFsTest, GetIncfsFeatures) {
@@ -222,32 +217,14 @@
     ASSERT_TRUE(isIncFsPath(tmp_dir_to_bind.path));
 }
 
-TEST_F(IncFsTest, FalseIncfsPathFile) {
-    TemporaryFile test_file;
-    ASSERT_FALSE(isIncFsFd(test_file.fd));
-    ASSERT_FALSE(isIncFsPath(test_file.path));
-}
-
-TEST_F(IncFsTest, TrueIncfsPathForBindMountFile) {
-    ASSERT_EQ(0,
-              makeFile(control_, mountPath(test_file_name_), 0555, fileId(1),
-                       {.size = test_file_size_}));
-    const auto file_path = mountPath(test_file_name_);
-    const android::base::unique_fd fd(open(file_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
-    ASSERT_GE(fd.get(), 0);
-    ASSERT_TRUE(isIncFsFd(fd.get()));
-    ASSERT_TRUE(isIncFsPath(file_path));
-}
-
 TEST_F(IncFsTest, Control) {
     ASSERT_TRUE(control_);
     EXPECT_GE(IncFs_GetControlFd(control_, CMD), 0);
     EXPECT_GE(IncFs_GetControlFd(control_, PENDING_READS), 0);
     EXPECT_GE(IncFs_GetControlFd(control_, LOGS), 0);
-    EXPECT_EQ((features() & Features::v2) != 0, IncFs_GetControlFd(control_, BLOCKS_WRITTEN) >= 0);
 
     auto fds = control_.releaseFds();
-    EXPECT_GE(fds.size(), size_t(4));
+    EXPECT_GE(fds.size(), size_t(3));
     EXPECT_GE(fds[0].get(), 0);
     EXPECT_GE(fds[1].get(), 0);
     EXPECT_GE(fds[2].get(), 0);
@@ -255,28 +232,26 @@
     EXPECT_LT(IncFs_GetControlFd(control_, CMD), 0);
     EXPECT_LT(IncFs_GetControlFd(control_, PENDING_READS), 0);
     EXPECT_LT(IncFs_GetControlFd(control_, LOGS), 0);
-    EXPECT_LT(IncFs_GetControlFd(control_, BLOCKS_WRITTEN), 0);
 
     control_.close();
     EXPECT_FALSE(control_);
 
-    auto control = IncFs_CreateControl(fds[0].release(), fds[1].release(), fds[2].release(), -1);
+    auto control = IncFs_CreateControl(fds[0].release(), fds[1].release(), fds[2].release());
     ASSERT_TRUE(control);
     EXPECT_GE(IncFs_GetControlFd(control, CMD), 0);
     EXPECT_GE(IncFs_GetControlFd(control, PENDING_READS), 0);
     EXPECT_GE(IncFs_GetControlFd(control, LOGS), 0);
-    IncFsFd rawFds[4];
+    IncFsFd rawFds[3];
     EXPECT_EQ(-EINVAL, IncFs_ReleaseControlFds(nullptr, rawFds, 3));
     EXPECT_EQ(-EINVAL, IncFs_ReleaseControlFds(control, nullptr, 3));
     EXPECT_EQ(-ERANGE, IncFs_ReleaseControlFds(control, rawFds, 2));
-    EXPECT_EQ(4, IncFs_ReleaseControlFds(control, rawFds, 4));
+    EXPECT_EQ(3, IncFs_ReleaseControlFds(control, rawFds, 3));
     EXPECT_GE(rawFds[0], 0);
     EXPECT_GE(rawFds[1], 0);
     EXPECT_GE(rawFds[2], 0);
     ::close(rawFds[0]);
     ::close(rawFds[1]);
     ::close(rawFds[2]);
-    if (rawFds[3] >= 0) ::close(rawFds[3]);
     IncFs_DeleteControl(control);
 }
 
@@ -328,7 +303,7 @@
 
 TEST_F(IncFsTest, RootInvalidControl) {
     const TemporaryFile tmp_file;
-    auto control{createControl(tmp_file.fd, -1, -1, -1)};
+    auto control{createControl(tmp_file.fd, -1, -1)};
     ASSERT_EQ("", root(control)) << "Error: " << errno;
 }
 
@@ -371,39 +346,6 @@
     ASSERT_EQ(0, (int)s.st_size);
 }
 
-TEST_F(IncFsTest, MakeMappedFile) {
-    ASSERT_EQ(0, makeDir(control_, mountPath(test_dir_name_)));
-
-    constexpr auto file_size = INCFS_DATA_FILE_BLOCK_SIZE * 2;
-    constexpr auto mapped_file_offset = file_size / 2;
-    constexpr auto mapped_file_size = file_size / 3;
-
-    const auto file_path = mountPath(test_dir_name_, test_file_name_);
-    ASSERT_FALSE(exists(file_path));
-    ASSERT_EQ(0,
-              makeFile(control_, file_path, 0111, fileId(1),
-                       {.size = file_size, .metadata = metadata("md")}));
-    struct stat s = {};
-    ASSERT_EQ(0, stat(file_path.c_str(), &s));
-    ASSERT_EQ(file_size, (int)s.st_size);
-
-    const auto mapped_file_path = mountPath(test_dir_name_, test_mapped_file_name_);
-    ASSERT_FALSE(exists(mapped_file_path));
-    ASSERT_EQ(0,
-              makeMappedFile(control_, mapped_file_path, 0111,
-                             {.sourceId = fileId(1),
-                              .sourceOffset = mapped_file_offset,
-                              .size = mapped_file_size}));
-    s = {};
-    ASSERT_EQ(0, stat(mapped_file_path.c_str(), &s));
-    ASSERT_EQ(mapped_file_size, (int)s.st_size);
-
-    // Check fileId for the source file.
-    ASSERT_EQ(fileId(1), getFileId(control_, file_path));
-    // Check that there is no fileId for the mapped file.
-    ASSERT_EQ(kIncFsInvalidFileId, getFileId(control_, mapped_file_path));
-}
-
 TEST_F(IncFsTest, GetFileId) {
     auto id = fileId(1);
     ASSERT_EQ(0,
@@ -447,19 +389,73 @@
 }
 
 TEST_F(IncFsTest, WriteBlocksAndPageRead) {
-    ASSERT_NO_FATAL_FAILURE(testWriteBlockAndPageRead<ReadInfo>());
-}
+    const auto id = fileId(1);
+    ASSERT_TRUE(control_.logs() >= 0);
+    ASSERT_EQ(0,
+              makeFile(control_, mountPath(test_file_name_), 0555, id, {.size = test_file_size_}));
+    auto fd = openForSpecialOps(control_, fileId(1));
+    ASSERT_GE(fd.get(), 0);
 
-TEST_F(IncFsTest, WriteBlocksAndPageReadWithUid) {
-    ASSERT_NO_FATAL_FAILURE(testWriteBlockAndPageRead<ReadInfoWithUid>());
+    std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE);
+    auto block = DataBlock{
+            .fileFd = fd.get(),
+            .pageIndex = 0,
+            .compression = INCFS_COMPRESSION_KIND_NONE,
+            .dataSize = (uint32_t)data.size(),
+            .data = data.data(),
+    };
+    ASSERT_EQ(1, writeBlocks({&block, 1}));
+
+    std::thread wait_page_read_thread([&]() {
+        std::vector<ReadInfo> reads;
+        ASSERT_EQ(WaitResult::HaveData,
+                  waitForPageReads(control_, std::chrono::seconds(5), &reads));
+        ASSERT_FALSE(reads.empty());
+        ASSERT_EQ(0, memcmp(&id, &reads[0].id, sizeof(id)));
+        ASSERT_EQ(0, int(reads[0].block));
+    });
+
+    const auto file_path = mountPath(test_file_name_);
+    const android::base::unique_fd readFd(open(file_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
+    ASSERT_TRUE(readFd >= 0);
+    char buf[INCFS_DATA_FILE_BLOCK_SIZE];
+    ASSERT_TRUE(android::base::ReadFully(readFd, buf, sizeof(buf)));
+    wait_page_read_thread.join();
 }
 
 TEST_F(IncFsTest, WaitForPendingReads) {
-    ASSERT_NO_FATAL_FAILURE(testWaitForPendingReads<ReadInfo>());
-}
+    const auto id = fileId(1);
+    ASSERT_EQ(0,
+              makeFile(control_, mountPath(test_file_name_), 0555, id, {.size = test_file_size_}));
 
-TEST_F(IncFsTest, WaitForPendingReadsWithUid) {
-    ASSERT_NO_FATAL_FAILURE(testWaitForPendingReads<ReadInfoWithUid>());
+    std::thread wait_pending_read_thread([&]() {
+        std::vector<ReadInfo> pending_reads;
+        ASSERT_EQ(WaitResult::HaveData,
+                  waitForPendingReads(control_, std::chrono::seconds(10), &pending_reads));
+        ASSERT_GT(pending_reads.size(), 0u);
+        ASSERT_EQ(0, memcmp(&id, &pending_reads[0].id, sizeof(id)));
+        ASSERT_EQ(0, (int)pending_reads[0].block);
+
+        auto fd = openForSpecialOps(control_, fileId(1));
+        ASSERT_GE(fd.get(), 0);
+
+        std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE);
+        auto block = DataBlock{
+                .fileFd = fd.get(),
+                .pageIndex = 0,
+                .compression = INCFS_COMPRESSION_KIND_NONE,
+                .dataSize = (uint32_t)data.size(),
+                .data = data.data(),
+        };
+        ASSERT_EQ(1, writeBlocks({&block, 1}));
+    });
+
+    const auto file_path = mountPath(test_file_name_);
+    const android::base::unique_fd fd(open(file_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
+    ASSERT_GE(fd.get(), 0);
+    char buf[INCFS_DATA_FILE_BLOCK_SIZE];
+    ASSERT_TRUE(android::base::ReadFully(fd, buf, sizeof(buf)));
+    wait_pending_read_thread.join();
 }
 
 TEST_F(IncFsTest, GetFilledRangesBad) {
@@ -509,7 +505,6 @@
     EXPECT_EQ(0, filledRanges.hashRangesCount);
 
     EXPECT_EQ(-ENODATA, IncFs_IsFullyLoaded(fd.get()));
-    EXPECT_EQ(-ENODATA, IncFs_IsEverythingFullyLoaded(control_));
 
     // write one block
     std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE);
@@ -543,7 +538,6 @@
     EXPECT_EQ(0, filledRanges.hashRangesCount);
 
     EXPECT_EQ(-ENODATA, IncFs_IsFullyLoaded(fd.get()));
-    EXPECT_EQ(-ENODATA, IncFs_IsEverythingFullyLoaded(control_));
 
     // append one more block next to the first one
     block.pageIndex = 1;
@@ -572,7 +566,6 @@
     EXPECT_EQ(0, filledRanges.hashRangesCount);
 
     EXPECT_EQ(-ENODATA, IncFs_IsFullyLoaded(fd.get()));
-    EXPECT_EQ(-ENODATA, IncFs_IsEverythingFullyLoaded(control_));
 
     // now create a gap between filled blocks
     block.pageIndex = 3;
@@ -613,7 +606,6 @@
     EXPECT_EQ(0, filledRanges.hashRangesCount);
 
     EXPECT_EQ(-ENODATA, IncFs_IsFullyLoaded(fd.get()));
-    EXPECT_EQ(-ENODATA, IncFs_IsEverythingFullyLoaded(control_));
 
     // at last fill the whole file and make sure we report it as having a single range
     block.pageIndex = 2;
@@ -641,7 +633,6 @@
     EXPECT_EQ(0, filledRanges.hashRangesCount);
 
     EXPECT_EQ(0, IncFs_IsFullyLoaded(fd.get()));
-    EXPECT_EQ(0, IncFs_IsEverythingFullyLoaded(control_));
 }
 
 TEST_F(IncFsTest, GetFilledRangesSmallBuffer) {
@@ -773,7 +764,6 @@
     EXPECT_EQ(size_t(1), ranges3.hashRanges()[1].size());
 
     EXPECT_EQ(LoadingState::MissingBlocks, isFullyLoaded(fd.get()));
-    EXPECT_EQ(LoadingState::MissingBlocks, isEverythingFullyLoaded(control_));
 
     {
         std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE);
@@ -793,705 +783,4 @@
         }
     }
     EXPECT_EQ(LoadingState::Full, isFullyLoaded(fd.get()));
-    EXPECT_EQ(LoadingState::Full, isEverythingFullyLoaded(control_));
-}
-
-TEST_F(IncFsTest, BlocksWritten) {
-    if (!(features() & Features::v2)) {
-        GTEST_SKIP() << "test not supported: IncFS is too old";
-        return;
-    }
-    const auto id = fileId(1);
-    ASSERT_EQ(0,
-              makeFile(control_, mountPath(test_file_name_), 0555, id, {.size = test_file_size_}));
-
-    IncFsSize blocksWritten = 0;
-    ASSERT_EQ(0, IncFs_WaitForFsWrittenBlocksChange(control_, 0, &blocksWritten));
-    EXPECT_EQ(0, blocksWritten);
-
-    auto fd = openForSpecialOps(control_, fileId(1));
-    ASSERT_GE(fd.get(), 0);
-
-    std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE);
-    auto block = DataBlock{
-            .fileFd = fd.get(),
-            .pageIndex = 0,
-            .compression = INCFS_COMPRESSION_KIND_NONE,
-            .dataSize = (uint32_t)data.size(),
-            .data = data.data(),
-    };
-    ASSERT_EQ(1, writeBlocks({&block, 1}));
-
-    ASSERT_EQ(0, IncFs_WaitForFsWrittenBlocksChange(control_, 0, &blocksWritten));
-    EXPECT_EQ(1, blocksWritten);
-}
-
-TEST_F(IncFsTest, Timeouts) {
-    if (!(features() & Features::v2)) {
-        GTEST_SKIP() << "test not supported: IncFS is too old";
-        return;
-    }
-
-    IncFsUidReadTimeouts timeouts[2] = {{1, 1000, 2000, 3000}, {2, 1000, 3000, 4000}};
-
-    EXPECT_EQ(0, IncFs_SetUidReadTimeouts(control_, timeouts, std::size(timeouts)));
-
-    IncFsUidReadTimeouts outTimeouts[3];
-
-    size_t outSize = 1;
-    EXPECT_EQ(-E2BIG, IncFs_GetUidReadTimeouts(control_, outTimeouts, &outSize));
-    EXPECT_EQ(size_t(2), outSize);
-
-    outSize = 3;
-    EXPECT_EQ(0, IncFs_GetUidReadTimeouts(control_, outTimeouts, &outSize));
-    EXPECT_EQ(size_t(2), outSize);
-
-    EXPECT_EQ(0, memcmp(timeouts, outTimeouts, 2 * sizeof(timeouts[0])));
-}
-
-TEST_F(IncFsTest, CompletionNoFiles) {
-    if (!(features() & Features::v2)) {
-        GTEST_SKIP() << "test not supported: IncFS is too old";
-        return;
-    }
-
-    size_t count = 0;
-    EXPECT_EQ(0, IncFs_ListIncompleteFiles(control_, nullptr, &count));
-    EXPECT_EQ(size_t(0), count);
-    EXPECT_EQ(0, IncFs_WaitForLoadingComplete(control_, 0));
-}
-
-TEST_F(IncFsTest, CompletionOneFile) {
-    if (!(features() & Features::v2)) {
-        GTEST_SKIP() << "test not supported: IncFS is too old";
-        return;
-    }
-
-    const auto id = fileId(1);
-    ASSERT_EQ(0,
-              makeFile(control_, mountPath(test_file_name_), 0555, id, {.size = test_file_size_}));
-
-    size_t count = 0;
-    EXPECT_EQ(-E2BIG, IncFs_ListIncompleteFiles(control_, nullptr, &count));
-    EXPECT_EQ(size_t(1), count);
-    EXPECT_EQ(-ETIMEDOUT, IncFs_WaitForLoadingComplete(control_, 0));
-
-    IncFsFileId ids[2];
-    count = 2;
-    EXPECT_EQ(0, IncFs_ListIncompleteFiles(control_, ids, &count));
-    EXPECT_EQ(size_t(1), count);
-    EXPECT_EQ(id, ids[0]);
-
-    auto fd = openForSpecialOps(control_, id);
-    ASSERT_GE(fd.get(), 0);
-    std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE);
-    auto block = DataBlock{
-            .fileFd = fd.get(),
-            .pageIndex = 0,
-            .compression = INCFS_COMPRESSION_KIND_NONE,
-            .dataSize = (uint32_t)data.size(),
-            .data = data.data(),
-    };
-    ASSERT_EQ(1, writeBlocks({&block, 1}));
-
-    count = 2;
-    EXPECT_EQ(0, IncFs_ListIncompleteFiles(control_, ids, &count));
-    EXPECT_EQ(size_t(0), count);
-    EXPECT_EQ(0, IncFs_WaitForLoadingComplete(control_, 0));
-}
-
-TEST_F(IncFsTest, CompletionMultiple) {
-    if (!(features() & Features::v2)) {
-        GTEST_SKIP() << "test not supported: IncFS is too old";
-        return;
-    }
-
-    const auto id = fileId(1);
-    ASSERT_EQ(0,
-              makeFile(control_, mountPath(test_file_name_), 0555, id, {.size = test_file_size_}));
-
-    size_t count = 0;
-    EXPECT_EQ(-E2BIG, IncFs_ListIncompleteFiles(control_, nullptr, &count));
-    EXPECT_EQ(size_t(1), count);
-    EXPECT_EQ(-ETIMEDOUT, IncFs_WaitForLoadingComplete(control_, 0));
-
-    // fill the existing file but add another one
-    const auto id2 = fileId(2);
-    ASSERT_EQ(0, makeFile(control_, mountPath("test2"), 0555, id2, {.size = test_file_size_}));
-
-    IncFsFileId ids[2];
-    count = 2;
-    EXPECT_EQ(0, IncFs_ListIncompleteFiles(control_, ids, &count));
-    EXPECT_EQ(size_t(2), count);
-    EXPECT_EQ(id, ids[0]);
-    EXPECT_EQ(id2, ids[1]);
-
-    auto fd = openForSpecialOps(control_, id);
-    ASSERT_GE(fd.get(), 0);
-    std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE);
-    auto block = DataBlock{
-            .fileFd = fd.get(),
-            .pageIndex = 0,
-            .compression = INCFS_COMPRESSION_KIND_NONE,
-            .dataSize = (uint32_t)data.size(),
-            .data = data.data(),
-    };
-    ASSERT_EQ(1, writeBlocks({&block, 1}));
-
-    count = 2;
-    EXPECT_EQ(0, IncFs_ListIncompleteFiles(control_, ids, &count));
-    EXPECT_EQ(size_t(1), count);
-    EXPECT_EQ(id2, ids[0]);
-    EXPECT_EQ(-ETIMEDOUT, IncFs_WaitForLoadingComplete(control_, 0));
-}
-
-TEST_F(IncFsTest, CompletionWait) {
-    if (!(features() & Features::v2)) {
-        GTEST_SKIP() << "test not supported: IncFS is too old";
-        return;
-    }
-
-    ASSERT_EQ(0,
-              makeFile(control_, mountPath("test1"), 0555, fileId(1),
-                       {.size = INCFS_DATA_FILE_BLOCK_SIZE}));
-    ASSERT_EQ(0,
-              makeFile(control_, mountPath("test2"), 0555, fileId(2),
-                       {.size = INCFS_DATA_FILE_BLOCK_SIZE}));
-    ASSERT_EQ(0,
-              makeFile(control_, mountPath("test3"), 0555, fileId(3),
-                       {.size = INCFS_DATA_FILE_BLOCK_SIZE}));
-
-    std::atomic<int> res = -1;
-    auto waiter = std::thread([&] { res = IncFs_WaitForLoadingComplete(control_, 5 * 1000); });
-
-    std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE);
-
-    {
-        auto fd = openForSpecialOps(control_, fileId(1));
-        ASSERT_GE(fd.get(), 0);
-        auto block = DataBlock{
-                .fileFd = fd.get(),
-                .pageIndex = 0,
-                .compression = INCFS_COMPRESSION_KIND_NONE,
-                .dataSize = (uint32_t)data.size(),
-                .data = data.data(),
-        };
-        ASSERT_EQ(1, writeBlocks({&block, 1}));
-    }
-    ASSERT_TRUE(res == -1);
-
-    {
-        auto fd = openForSpecialOps(control_, fileId(3));
-        ASSERT_GE(fd.get(), 0);
-        auto block = DataBlock{
-                .fileFd = fd.get(),
-                .pageIndex = 0,
-                .compression = INCFS_COMPRESSION_KIND_NONE,
-                .dataSize = (uint32_t)data.size(),
-                .data = data.data(),
-        };
-        ASSERT_EQ(1, writeBlocks({&block, 1}));
-    }
-    ASSERT_TRUE(res == -1);
-
-    {
-        auto fd = openForSpecialOps(control_, fileId(2));
-        ASSERT_GE(fd.get(), 0);
-        auto block = DataBlock{
-                .fileFd = fd.get(),
-                .pageIndex = 0,
-                .compression = INCFS_COMPRESSION_KIND_NONE,
-                .dataSize = (uint32_t)data.size(),
-                .data = data.data(),
-        };
-        ASSERT_EQ(1, writeBlocks({&block, 1}));
-    }
-
-    waiter.join();
-
-    auto listIncomplete = [&] {
-        IncFsFileId ids[3];
-        size_t count = 3;
-        if (IncFs_ListIncompleteFiles(control_, ids, &count) != 0) {
-            return "error listing incomplete files"s;
-        }
-        auto res = ab::StringPrintf("[%d]", int(count));
-        for (size_t i = 0; i < count; ++i) {
-            ab::StringAppendF(&res, " %s", toString(ids[i]).c_str());
-        }
-        return res;
-    };
-    EXPECT_EQ(0, res) << "Incomplete files: " << listIncomplete();
-}
-
-TEST_F(IncFsTest, GetBlockCounts) {
-    if (!(features() & Features::v2)) {
-        GTEST_SKIP() << "test not supported: IncFS is too old";
-        return;
-    }
-
-    const auto id = fileId(1);
-    ASSERT_EQ(0,
-              makeFile(control_, mountPath(test_file_name_), 0555, id,
-                       {.size = 20 * INCFS_DATA_FILE_BLOCK_SIZE + 3}));
-
-    IncFsBlockCounts counts = {};
-    EXPECT_EQ(0,
-              IncFs_GetFileBlockCountByPath(control_, mountPath(test_file_name_).c_str(), &counts));
-    EXPECT_EQ(21, counts.totalDataBlocks);
-    EXPECT_EQ(0, counts.filledDataBlocks);
-    EXPECT_EQ(0, counts.totalHashBlocks);
-    EXPECT_EQ(0, counts.filledHashBlocks);
-
-    EXPECT_EQ(0, IncFs_GetFileBlockCountById(control_, id, &counts));
-    EXPECT_EQ(21, counts.totalDataBlocks);
-    EXPECT_EQ(0, counts.filledDataBlocks);
-    EXPECT_EQ(0, counts.totalHashBlocks);
-    EXPECT_EQ(0, counts.filledHashBlocks);
-
-    auto fd = openForSpecialOps(control_, id);
-    ASSERT_GE(fd.get(), 0);
-    std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE);
-    auto block = DataBlock{
-            .fileFd = fd.get(),
-            .pageIndex = 3,
-            .compression = INCFS_COMPRESSION_KIND_NONE,
-            .dataSize = (uint32_t)data.size(),
-            .data = data.data(),
-    };
-    ASSERT_EQ(1, writeBlocks({&block, 1}));
-
-    EXPECT_EQ(0,
-              IncFs_GetFileBlockCountByPath(control_, mountPath(test_file_name_).c_str(), &counts));
-    EXPECT_EQ(21, counts.totalDataBlocks);
-    EXPECT_EQ(1, counts.filledDataBlocks);
-    EXPECT_EQ(0, counts.totalHashBlocks);
-    EXPECT_EQ(0, counts.filledHashBlocks);
-
-    EXPECT_EQ(0, IncFs_GetFileBlockCountById(control_, id, &counts));
-    EXPECT_EQ(21, counts.totalDataBlocks);
-    EXPECT_EQ(1, counts.filledDataBlocks);
-    EXPECT_EQ(0, counts.totalHashBlocks);
-    EXPECT_EQ(0, counts.filledHashBlocks);
-}
-
-TEST_F(IncFsTest, GetBlockCountsHash) {
-    if (!(features() & Features::v2)) {
-        GTEST_SKIP() << "test not supported: IncFS is too old";
-        return;
-    }
-
-    auto size = makeFileWithHash(1);
-    ASSERT_GT(size, 0);
-
-    IncFsBlockCounts counts = {};
-    EXPECT_EQ(0,
-              IncFs_GetFileBlockCountByPath(control_, mountPath(test_file_name_).c_str(), &counts));
-    EXPECT_EQ(sizeToPages(size), counts.totalDataBlocks);
-    EXPECT_EQ(0, counts.filledDataBlocks);
-    EXPECT_EQ(3, counts.totalHashBlocks);
-    EXPECT_EQ(0, counts.filledHashBlocks);
-
-    ASSERT_NO_FATAL_FAILURE(writeTestRanges(1, size));
-
-    EXPECT_EQ(0,
-              IncFs_GetFileBlockCountByPath(control_, mountPath(test_file_name_).c_str(), &counts));
-    EXPECT_EQ(sizeToPages(size), counts.totalDataBlocks);
-    EXPECT_EQ(4, counts.filledDataBlocks);
-    EXPECT_EQ(3, counts.totalHashBlocks);
-    EXPECT_EQ(2, counts.filledHashBlocks);
-}
-
-TEST_F(IncFsTest, ReserveSpace) {
-    auto size = makeFileWithHash(1);
-    ASSERT_GT(size, 0);
-
-    EXPECT_EQ(-ENOENT,
-              IncFs_ReserveSpaceByPath(control_, mountPath("1"s += test_file_name_).c_str(), size));
-    EXPECT_EQ(0, IncFs_ReserveSpaceByPath(control_, mountPath(test_file_name_).c_str(), size));
-    EXPECT_EQ(0, IncFs_ReserveSpaceByPath(control_, mountPath(test_file_name_).c_str(), 2 * size));
-    EXPECT_EQ(0, IncFs_ReserveSpaceByPath(control_, mountPath(test_file_name_).c_str(), 2 * size));
-    EXPECT_EQ(0,
-              IncFs_ReserveSpaceByPath(control_, mountPath(test_file_name_).c_str(),
-                                       kTrimReservedSpace));
-    EXPECT_EQ(0,
-              IncFs_ReserveSpaceByPath(control_, mountPath(test_file_name_).c_str(),
-                                       kTrimReservedSpace));
-
-    EXPECT_EQ(-ENOENT, IncFs_ReserveSpaceById(control_, fileId(2), size));
-    EXPECT_EQ(0, IncFs_ReserveSpaceById(control_, fileId(1), size));
-    EXPECT_EQ(0, IncFs_ReserveSpaceById(control_, fileId(1), 2 * size));
-    EXPECT_EQ(0, IncFs_ReserveSpaceById(control_, fileId(1), 2 * size));
-    EXPECT_EQ(0, IncFs_ReserveSpaceById(control_, fileId(1), kTrimReservedSpace));
-    EXPECT_EQ(0, IncFs_ReserveSpaceById(control_, fileId(1), kTrimReservedSpace));
-}
-
-TEST_F(IncFsTest, ForEachFile) {
-    const auto incompleteSupported = (features() & Features::v2) != 0;
-    EXPECT_EQ(-EINVAL, IncFs_ForEachFile(nullptr, nullptr, nullptr));
-    EXPECT_EQ(-EINVAL, IncFs_ForEachIncompleteFile(nullptr, nullptr, nullptr));
-    EXPECT_EQ(-EINVAL, IncFs_ForEachFile(control_, nullptr, nullptr));
-    EXPECT_EQ(-EINVAL, IncFs_ForEachIncompleteFile(control_, nullptr, nullptr));
-    EXPECT_EQ(0, IncFs_ForEachFile(control_, nullptr, [](auto, auto, auto) { return true; }));
-    EXPECT_EQ(incompleteSupported ? 0 : -ENOTSUP,
-              IncFs_ForEachIncompleteFile(control_, nullptr,
-                                          [](auto, auto, auto) { return true; }));
-    EXPECT_EQ(0, IncFs_ForEachFile(control_, this, [](auto, auto, auto) { return true; }));
-    EXPECT_EQ(incompleteSupported ? 0 : -ENOTSUP,
-              IncFs_ForEachIncompleteFile(control_, this, [](auto, auto, auto) { return true; }));
-
-    int res = makeFile(control_, mountPath("incomplete.txt"), 0555, fileId(1),
-                       {.metadata = metadata("md")});
-    ASSERT_EQ(res, 0);
-
-    EXPECT_EQ(1, IncFs_ForEachFile(control_, this, [](auto, auto context, auto id) {
-                  auto self = (IncFsTest*)context;
-                  EXPECT_EQ(self->fileId(1), id);
-                  return true;
-              }));
-    EXPECT_EQ(incompleteSupported ? 0 : -ENOTSUP,
-              IncFs_ForEachIncompleteFile(control_, this, [](auto, auto, auto) { return true; }));
-
-    auto size = makeFileWithHash(2);
-    ASSERT_GT(size, 0);
-
-    EXPECT_EQ(1, IncFs_ForEachFile(control_, this, [](auto, auto context, auto id) {
-                  auto self = (IncFsTest*)context;
-                  EXPECT_TRUE(id == self->fileId(1) || id == self->fileId(2));
-                  return false;
-              }));
-    EXPECT_EQ(2, IncFs_ForEachFile(control_, this, [](auto, auto context, auto id) {
-                  auto self = (IncFsTest*)context;
-                  EXPECT_TRUE(id == self->fileId(1) || id == self->fileId(2));
-                  return true;
-              }));
-    EXPECT_EQ(incompleteSupported ? 1 : -ENOTSUP,
-              IncFs_ForEachIncompleteFile(control_, this, [](auto, auto context, auto id) {
-                  auto self = (IncFsTest*)context;
-                  EXPECT_EQ(self->fileId(2), id);
-                  return true;
-              }));
-}
-
-TEST(CStrWrapperTest, EmptyStringView) {
-    ASSERT_STREQ("", details::c_str({}).get());
-    ASSERT_STREQ("", details::c_str({nullptr, 0}).get());
-}
-
-class IncFsGetMetricsTest : public IncFsTestBase {
-protected:
-    int32_t getReadTimeout() override { return 100 /* 0.1 second */; }
-};
-
-TEST_F(IncFsGetMetricsTest, MetricsWithNoEvents) {
-    if (!(features() & Features::v2)) {
-        GTEST_SKIP() << "test not supported: IncFS is too old";
-        return;
-    }
-    IncFsLastReadError lastReadError = {.id = fileId(-1),
-                                        .timestampUs = static_cast<uint64_t>(-1),
-                                        .block = static_cast<IncFsBlockIndex>(-1),
-                                        .errorNo = static_cast<uint32_t>(-1),
-                                        .uid = static_cast<IncFsUid>(-1)};
-    EXPECT_EQ(0, IncFs_GetLastReadError(control_, &lastReadError));
-    // All fields should be zero
-    EXPECT_EQ(FileId{}, lastReadError.id);
-    EXPECT_EQ(0, (int)lastReadError.timestampUs);
-    EXPECT_EQ(0, (int)lastReadError.block);
-    EXPECT_EQ(0, (int)lastReadError.errorNo);
-    EXPECT_EQ(0, (int)lastReadError.uid);
-
-    IncFsMetrics incfsMetrics = {10, 10, 10, 10, 10, 10, 10, 10, 10};
-    EXPECT_EQ(0, IncFs_GetMetrics(metrics_key_.c_str(), &incfsMetrics));
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedMin);
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedMinUs);
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedPending);
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedPendingUs);
-    EXPECT_EQ(0, (int)incfsMetrics.readsFailedHashVerification);
-    EXPECT_EQ(0, (int)incfsMetrics.readsFailedOther);
-    EXPECT_EQ(0, (int)incfsMetrics.readsFailedTimedOut);
-}
-
-TEST_F(IncFsGetMetricsTest, MetricsWithReadsTimeOut) {
-    if (!(features() & Features::v2)) {
-        GTEST_SKIP() << "test not supported: IncFS is too old";
-        return;
-    }
-    const auto id = fileId(1);
-    ASSERT_EQ(0,
-              makeFile(control_, mountPath(test_file_name_), 0555, id,
-                       {.size = INCFS_DATA_FILE_BLOCK_SIZE}));
-
-    const auto file_path = mountPath(test_file_name_);
-    const android::base::unique_fd fd(open(file_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
-    ASSERT_GE(fd.get(), 0);
-    // Read should timeout immediately
-    char buf[INCFS_DATA_FILE_BLOCK_SIZE];
-    EXPECT_FALSE(android::base::ReadFully(fd, buf, sizeof(buf)));
-    IncFsLastReadError lastReadError = {.id = fileId(-1),
-                                        .timestampUs = static_cast<uint64_t>(-1),
-                                        .block = static_cast<IncFsBlockIndex>(-1),
-                                        .errorNo = static_cast<uint32_t>(-1),
-                                        .uid = static_cast<IncFsUid>(-1)};
-    EXPECT_EQ(0, IncFs_GetLastReadError(control_, &lastReadError));
-    EXPECT_EQ(id, lastReadError.id);
-    EXPECT_TRUE(lastReadError.timestampUs > 0);
-    EXPECT_EQ(0, (int)lastReadError.block);
-    EXPECT_EQ(-ETIME, (int)lastReadError.errorNo);
-    EXPECT_EQ((int)getuid(), (int)lastReadError.uid);
-
-    IncFsMetrics incfsMetrics = {10, 10, 10, 10, 10, 10, 10, 10, 10};
-    EXPECT_EQ(0, IncFs_GetMetrics(metrics_key_.c_str(), &incfsMetrics));
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedMin);
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedMinUs);
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedPending);
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedPendingUs);
-    EXPECT_EQ(0, (int)incfsMetrics.readsFailedHashVerification);
-    EXPECT_EQ(0, (int)incfsMetrics.readsFailedOther);
-    EXPECT_EQ(1, (int)incfsMetrics.readsFailedTimedOut);
-}
-
-TEST_F(IncFsGetMetricsTest, MetricsWithHashFailure) {
-    if (!(features() & Features::v2)) {
-        GTEST_SKIP() << "test not supported: IncFS is too old";
-        return;
-    }
-    auto size = makeFileWithHash(1);
-    ASSERT_GT(size, 0);
-    // Make data and hash mismatch
-    const auto id = fileId(1);
-    char data[INCFS_DATA_FILE_BLOCK_SIZE]{static_cast<char>(-1)};
-    char hashData[INCFS_DATA_FILE_BLOCK_SIZE]{};
-    auto wfd = openForSpecialOps(control_, id);
-    ASSERT_GE(wfd.get(), 0);
-    DataBlock blocks[] = {{
-                                  .fileFd = wfd.get(),
-                                  .pageIndex = 0,
-                                  .compression = INCFS_COMPRESSION_KIND_NONE,
-                                  .dataSize = INCFS_DATA_FILE_BLOCK_SIZE,
-                                  .data = data,
-                          },
-                          {
-                                  .fileFd = wfd.get(),
-                                  // first hash page
-                                  .pageIndex = 0,
-                                  .compression = INCFS_COMPRESSION_KIND_NONE,
-                                  .dataSize = INCFS_DATA_FILE_BLOCK_SIZE,
-                                  .kind = INCFS_BLOCK_KIND_HASH,
-                                  .data = hashData,
-                          },
-                          {
-                                  .fileFd = wfd.get(),
-                                  .pageIndex = 2,
-                                  .compression = INCFS_COMPRESSION_KIND_NONE,
-                                  .dataSize = INCFS_DATA_FILE_BLOCK_SIZE,
-                                  .kind = INCFS_BLOCK_KIND_HASH,
-                                  .data = hashData,
-                          }};
-    ASSERT_EQ((int)std::size(blocks), writeBlocks({blocks, std::size(blocks)}));
-    const auto file_path = mountPath(test_file_name_);
-    const android::base::unique_fd fd(open(file_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
-    ASSERT_GE(fd.get(), 0);
-    // Read should fail at reading the first block due to hash failure
-    char buf[INCFS_DATA_FILE_BLOCK_SIZE];
-    EXPECT_FALSE(android::base::ReadFully(fd, buf, sizeof(buf)));
-    IncFsLastReadError lastReadError = {.id = fileId(-1),
-                                        .timestampUs = static_cast<uint64_t>(-1),
-                                        .block = static_cast<IncFsBlockIndex>(-1),
-                                        .errorNo = static_cast<uint32_t>(-1),
-                                        .uid = static_cast<IncFsUid>(-1)};
-    EXPECT_EQ(0, IncFs_GetLastReadError(control_, &lastReadError));
-    EXPECT_EQ(0, std::strcmp(lastReadError.id.data, id.data));
-    EXPECT_TRUE(lastReadError.timestampUs > 0);
-    EXPECT_EQ(0, (int)lastReadError.block);
-    EXPECT_EQ(-EBADMSG, (int)lastReadError.errorNo);
-    EXPECT_EQ((int)getuid(), (int)lastReadError.uid);
-
-    IncFsMetrics incfsMetrics = {10, 10, 10, 10, 10, 10, 10, 10, 10};
-    EXPECT_EQ(0, IncFs_GetMetrics(metrics_key_.c_str(), &incfsMetrics));
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedMin);
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedMinUs);
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedPending);
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedPendingUs);
-    EXPECT_EQ(1, (int)incfsMetrics.readsFailedHashVerification);
-    EXPECT_EQ(0, (int)incfsMetrics.readsFailedOther);
-    EXPECT_EQ(0, (int)incfsMetrics.readsFailedTimedOut);
-}
-
-TEST_F(IncFsGetMetricsTest, MetricsWithReadsDelayed) {
-    if (!(features() & Features::v2)) {
-        GTEST_SKIP() << "test not supported: IncFS is too old";
-        return;
-    }
-    const auto id = fileId(1);
-    int testFileSize = INCFS_DATA_FILE_BLOCK_SIZE;
-    int waitBeforeWriteUs = 10000;
-    ASSERT_EQ(0, makeFile(control_, mountPath(test_file_name_), 0555, id, {.size = testFileSize}));
-    std::thread wait_before_write_thread([&]() {
-        std::vector<ReadInfoWithUid> pending_reads;
-        ASSERT_EQ(WaitResult::HaveData,
-                  waitForPendingReads(control_, std::chrono::seconds(1), &pending_reads));
-        // Additional wait is needed for the kernel jiffies counter to increment
-        usleep(waitBeforeWriteUs);
-        auto fd = openForSpecialOps(control_, fileId(1));
-        ASSERT_GE(fd.get(), 0);
-        std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE);
-        auto block = DataBlock{
-                .fileFd = fd.get(),
-                .pageIndex = 0,
-                .compression = INCFS_COMPRESSION_KIND_NONE,
-                .dataSize = (uint32_t)data.size(),
-                .data = data.data(),
-        };
-        ASSERT_EQ(1, writeBlocks({&block, 1}));
-    });
-
-    const auto file_path = mountPath(test_file_name_);
-    const android::base::unique_fd fd(open(file_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
-    ASSERT_GE(fd.get(), 0);
-    char buf[testFileSize];
-    EXPECT_TRUE(android::base::ReadFully(fd, buf, sizeof(buf)));
-    wait_before_write_thread.join();
-
-    IncFsLastReadError lastReadError = {.id = fileId(-1), 1, 1, 1, 1};
-    EXPECT_EQ(0, IncFs_GetLastReadError(control_, &lastReadError));
-    EXPECT_EQ(FileId{}, lastReadError.id);
-    EXPECT_EQ(0, (int)lastReadError.timestampUs);
-    EXPECT_EQ(0, (int)lastReadError.block);
-    EXPECT_EQ(0, (int)lastReadError.errorNo);
-    EXPECT_EQ(0, (int)lastReadError.uid);
-
-    IncFsMetrics incfsMetrics = {10, 10, 10, 10, 10, 10, 10, 10, 10};
-    EXPECT_EQ(0, IncFs_GetMetrics(metrics_key_.c_str(), &incfsMetrics));
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedMin);
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedMinUs);
-    EXPECT_EQ(1, (int)incfsMetrics.readsDelayedPending);
-    EXPECT_TRUE((int)incfsMetrics.readsDelayedPendingUs > 0);
-    EXPECT_EQ(0, (int)incfsMetrics.readsFailedHashVerification);
-    EXPECT_EQ(0, (int)incfsMetrics.readsFailedOther);
-    EXPECT_EQ(0, (int)incfsMetrics.readsFailedTimedOut);
-}
-
-TEST_F(IncFsGetMetricsTest, MetricsWithReadsDelayedPerUidTimeout) {
-    if (!(features() & Features::v2)) {
-        GTEST_SKIP() << "test not supported: IncFS is too old";
-        return;
-    }
-    const auto id = fileId(1);
-    int testFileSize = INCFS_DATA_FILE_BLOCK_SIZE;
-    ASSERT_EQ(0, makeFile(control_, mountPath(test_file_name_), 0555, id, {.size = testFileSize}));
-
-    auto fdToFill = openForSpecialOps(control_, fileId(1));
-    ASSERT_GE(fdToFill.get(), 0);
-    std::vector<char> data(INCFS_DATA_FILE_BLOCK_SIZE);
-    auto block = DataBlock{
-            .fileFd = fdToFill.get(),
-            .pageIndex = 0,
-            .compression = INCFS_COMPRESSION_KIND_NONE,
-            .dataSize = (uint32_t)data.size(),
-            .data = data.data(),
-    };
-    ASSERT_EQ(1, writeBlocks({&block, 1}));
-
-    // Set per-uid read timeout then read
-    uint32_t readTimeoutUs = 1000000;
-    IncFsUidReadTimeouts timeouts[1] = {
-            {static_cast<IncFsUid>(getuid()), readTimeoutUs, readTimeoutUs, readTimeoutUs}};
-    ASSERT_EQ(0, IncFs_SetUidReadTimeouts(control_, timeouts, std::size(timeouts)));
-    const auto file_path = mountPath(test_file_name_);
-    const android::base::unique_fd fd(open(file_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
-    char buf[testFileSize];
-    ASSERT_GE(fd.get(), 0);
-    ASSERT_TRUE(android::base::ReadFully(fd, buf, sizeof(buf)));
-
-    IncFsLastReadError lastReadError = {.id = fileId(-1), 1, 1, 1, 1};
-    EXPECT_EQ(0, IncFs_GetLastReadError(control_, &lastReadError));
-    EXPECT_EQ(FileId{}, lastReadError.id);
-    EXPECT_EQ(0, (int)lastReadError.timestampUs);
-    EXPECT_EQ(0, (int)lastReadError.block);
-    EXPECT_EQ(0, (int)lastReadError.errorNo);
-    EXPECT_EQ(0, (int)lastReadError.uid);
-
-    IncFsMetrics incfsMetrics = {10, 10, 10, 10, 10, 10, 10, 10, 10};
-    EXPECT_EQ(0, IncFs_GetMetrics(metrics_key_.c_str(), &incfsMetrics));
-    EXPECT_EQ(1, (int)incfsMetrics.readsDelayedMin);
-    EXPECT_EQ(readTimeoutUs, (uint32_t)incfsMetrics.readsDelayedMinUs);
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedPending);
-    EXPECT_EQ(0, (int)incfsMetrics.readsDelayedPendingUs);
-    EXPECT_EQ(0, (int)incfsMetrics.readsFailedHashVerification);
-    EXPECT_EQ(0, (int)incfsMetrics.readsFailedOther);
-    EXPECT_EQ(0, (int)incfsMetrics.readsFailedTimedOut);
-}
-
-inline bool operator==(const BlockCounts& lhs, const BlockCounts& rhs) {
-    return lhs.totalDataBlocks == rhs.totalDataBlocks &&
-            lhs.filledDataBlocks == rhs.filledDataBlocks &&
-            lhs.totalHashBlocks == rhs.totalHashBlocks &&
-            lhs.filledHashBlocks == rhs.filledHashBlocks;
-}
-
-TEST_F(IncFsTest, LoadingProgress) {
-    ASSERT_EQ(0, makeDir(control_, mountPath(test_dir_name_)));
-
-    constexpr auto file_size = INCFS_DATA_FILE_BLOCK_SIZE * 2;
-    constexpr auto mapped_file_offset = file_size / 2;
-    constexpr auto mapped_file_size = file_size / 3;
-
-    const auto file_id = fileId(1);
-
-    const auto file_path = mountPath(test_dir_name_, test_file_name_);
-    ASSERT_FALSE(exists(file_path));
-    ASSERT_EQ(0,
-              makeFile(control_, file_path, 0111, file_id,
-                       {.size = file_size, .metadata = metadata("md")}));
-    struct stat s = {};
-    ASSERT_EQ(0, stat(file_path.c_str(), &s));
-    ASSERT_EQ(file_size, (int)s.st_size);
-
-    const auto mapped_file_path = mountPath(test_dir_name_, test_mapped_file_name_);
-    ASSERT_FALSE(exists(mapped_file_path));
-    ASSERT_EQ(0,
-              makeMappedFile(control_, mapped_file_path, 0111,
-                             {.sourceId = file_id,
-                              .sourceOffset = mapped_file_offset,
-                              .size = mapped_file_size}));
-    s = {};
-    ASSERT_EQ(0, stat(mapped_file_path.c_str(), &s));
-    ASSERT_EQ(mapped_file_size, (int)s.st_size);
-
-    // Check fully loaded first.
-    ASSERT_EQ(LoadingState::MissingBlocks, isFullyLoaded(control_, file_path));
-    ASSERT_EQ(LoadingState::MissingBlocks, isFullyLoaded(control_, file_id));
-    ASSERT_EQ((LoadingState)-ENOTSUP, isFullyLoaded(control_, mapped_file_path));
-
-    // Next is loading progress.
-    ASSERT_EQ(BlockCounts{.totalDataBlocks = 2}, *getBlockCount(control_, file_path));
-    ASSERT_EQ(BlockCounts{.totalDataBlocks = 2}, *getBlockCount(control_, file_id));
-    ASSERT_FALSE(getBlockCount(control_, mapped_file_path));
-
-    // Now write a page #0.
-    ASSERT_NO_FATAL_FAILURE(writeBlock(0));
-
-    // Recheck everything.
-    ASSERT_EQ(LoadingState::MissingBlocks, isFullyLoaded(control_, file_path));
-    ASSERT_EQ(LoadingState::MissingBlocks, isFullyLoaded(control_, file_id));
-    ASSERT_EQ((LoadingState)-ENOTSUP, isFullyLoaded(control_, mapped_file_path));
-
-    BlockCounts onePage{.totalDataBlocks = 2, .filledDataBlocks = 1};
-    ASSERT_EQ(onePage, *getBlockCount(control_, file_path));
-    ASSERT_EQ(onePage, *getBlockCount(control_, file_id));
-    ASSERT_FALSE(getBlockCount(control_, mapped_file_path));
-
-    // Now write a page #1.
-    ASSERT_NO_FATAL_FAILURE(writeBlock(1));
-
-    // Check for fully loaded.
-    ASSERT_EQ(LoadingState::Full, isFullyLoaded(control_, file_path));
-    ASSERT_EQ(LoadingState::Full, isFullyLoaded(control_, file_id));
-    ASSERT_EQ((LoadingState)-ENOTSUP, isFullyLoaded(control_, mapped_file_path));
-
-    BlockCounts twoPages{.totalDataBlocks = 2, .filledDataBlocks = 2};
-    ASSERT_EQ(twoPages, *getBlockCount(control_, file_path));
-    ASSERT_EQ(twoPages, *getBlockCount(control_, file_id));
-    ASSERT_FALSE(getBlockCount(control_, mapped_file_path));
 }
diff --git a/incfs/tests/include/IncFsTestBase.h b/incfs/tests/include/IncFsTestBase.h
deleted file mode 100644
index 8c61d64..0000000
--- a/incfs/tests/include/IncFsTestBase.h
+++ /dev/null
@@ -1,126 +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 <android-base/logging.h>
-#include <android-base/unique_fd.h>
-#include <gtest/gtest.h>
-#include <selinux/selinux.h>
-
-#include "incfs.h"
-#include "path.h"
-
-namespace android::incfs {
-
-static bool exists(std::string_view path) {
-    return access(path.data(), F_OK) == 0;
-}
-
-class IncFsTestBase : public ::testing::Test {
-protected:
-    virtual void SetUp() {
-        tmp_dir_for_mount_.emplace();
-        mount_dir_path_ = tmp_dir_for_mount_->path;
-        tmp_dir_for_image_.emplace();
-        image_dir_path_ = tmp_dir_for_image_->path;
-        ASSERT_TRUE(exists(image_dir_path_));
-        ASSERT_TRUE(exists(mount_dir_path_));
-        if (!enabled()) {
-            GTEST_SKIP() << "test not supported: IncFS is not enabled";
-        } else {
-            metrics_key_ = path::baseName(image_dir_path_);
-            control_ = mount(image_dir_path_, mount_dir_path_,
-                             MountOptions{.readLogBufferPages = 4,
-                                          .defaultReadTimeoutMs = getReadTimeout(),
-                                          .sysfsName = metrics_key_.c_str()});
-            ASSERT_TRUE(control_.cmd() >= 0) << "Expected >= 0 got " << control_.cmd();
-            ASSERT_TRUE(control_.pendingReads() >= 0);
-            ASSERT_TRUE(control_.logs() >= 0);
-            checkRestoreconResult(mountPath(INCFS_PENDING_READS_FILENAME));
-            checkRestoreconResult(mountPath(INCFS_LOG_FILENAME));
-        }
-    }
-
-    virtual void TearDown() {
-        unmount(mount_dir_path_);
-        tmp_dir_for_image_.reset();
-        tmp_dir_for_mount_.reset();
-        EXPECT_FALSE(exists(image_dir_path_));
-        EXPECT_FALSE(exists(mount_dir_path_));
-    }
-
-    static void checkRestoreconResult(std::string_view path) {
-        char* ctx = nullptr;
-        ASSERT_NE(-1, getfilecon(path.data(), &ctx));
-        ASSERT_EQ("u:object_r:shell_data_file:s0", std::string(ctx));
-        freecon(ctx);
-    }
-
-    static IncFsFileId fileId(uint64_t i) {
-        IncFsFileId id = {};
-        static_assert(sizeof(id) >= sizeof(i));
-        memcpy(&id, &i, sizeof(i));
-        return id;
-    }
-
-    virtual int32_t getReadTimeout() {
-        return std::chrono::duration_cast<std::chrono::milliseconds>(kDefaultReadTimeout).count();
-    }
-
-    template <class... Paths>
-    std::string mountPath(Paths&&... paths) const {
-        return path::join(mount_dir_path_, std::forward<Paths>(paths)...);
-    }
-
-    virtual int makeFileWithHash(int id) {
-        // calculate the required size for two leaf hash blocks
-        constexpr auto size =
-                (INCFS_DATA_FILE_BLOCK_SIZE / INCFS_MAX_HASH_SIZE + 1) * INCFS_DATA_FILE_BLOCK_SIZE;
-
-        // assemble a signature/hashing data for it
-        struct __attribute__((packed)) Signature {
-            uint32_t version = INCFS_SIGNATURE_VERSION;
-            uint32_t hashingSize = sizeof(hashing);
-            struct __attribute__((packed)) Hashing {
-                uint32_t algo = INCFS_HASH_TREE_SHA256;
-                uint8_t log2Blocksize = 12;
-                uint32_t saltSize = 0;
-                uint32_t rootHashSize = INCFS_MAX_HASH_SIZE;
-                char rootHash[INCFS_MAX_HASH_SIZE] = {};
-            } hashing;
-            uint32_t signingSize = 0;
-        } signature;
-
-        int res = makeFile(control_, mountPath(test_file_name_), 0555, fileId(id),
-                           {.size = size,
-                            .signature = {.data = (char*)&signature, .size = sizeof(signature)}});
-        EXPECT_EQ(0, res);
-        return res ? -1 : size;
-    }
-
-    std::string mount_dir_path_;
-    std::optional<TemporaryDir> tmp_dir_for_mount_;
-    std::string image_dir_path_;
-    std::optional<TemporaryDir> tmp_dir_for_image_;
-    inline static const std::string_view test_file_name_ = "test.txt";
-    inline static const std::string_view test_mapped_file_name_ = "mapped.txt";
-    inline static const std::string_view test_dir_name_ = "test_dir";
-    std::string metrics_key_;
-    Control control_;
-};
-
-} // namespace android::incfs
diff --git a/incfs/tests/util/map_ptr_test.cpp b/incfs/tests/util/map_ptr_test.cpp
deleted file mode 100644
index ff9e466..0000000
--- a/incfs/tests/util/map_ptr_test.cpp
+++ /dev/null
@@ -1,328 +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/file.h>
-#include <sys/select.h>
-
-#include <setjmp.h>
-#include <unistd.h>
-
-#include "IncFsTestBase.h"
-
-#include "util/map_ptr.h"
-
-using namespace android::incfs;
-using namespace std::literals;
-
-constexpr int FILE_PAGES = 5U;
-constexpr int FILE_SIZE = INCFS_DATA_FILE_BLOCK_SIZE * FILE_PAGES;
-constexpr int FILE_MISSING_PAGE = 3U;
-
-class MapPtrTest : public IncFsTestBase {
-protected:
-    virtual void SetUp() override {
-        IncFsTestBase::SetUp();
-
-        const auto id = fileId(1);
-        ASSERT_TRUE(control_.logs() >= 0);
-        ASSERT_EQ(0, makeFile(control_, mountPath(test_file_name_), 0555, id, {.size = FILE_SIZE}));
-        auto fd = openForSpecialOps(control_, fileId(1));
-        ASSERT_GE(fd.get(), 0);
-
-        // Generate the file data.
-        std::vector<uint32_t> data(INCFS_DATA_FILE_BLOCK_SIZE);
-        for (int i = 0; i < FILE_SIZE; i++) {
-            data[i] = i;
-        }
-
-        // Write the file, but leave one page missing.
-        for (int p = 0; p < FILE_PAGES; p++) {
-            if (p == FILE_MISSING_PAGE) {
-                continue;
-            }
-            auto block = DataBlock{
-                    .fileFd = fd.get(),
-                    .pageIndex = p,
-                    .compression = INCFS_COMPRESSION_KIND_NONE,
-                    .dataSize = (uint32_t)INCFS_DATA_FILE_BLOCK_SIZE,
-                    .data = reinterpret_cast<const char *>(data.data()) +
-                            INCFS_DATA_FILE_BLOCK_SIZE * p,
-            };
-            ASSERT_EQ(1, writeBlocks({&block, 1}));
-        }
-
-        mount_path_ = mountPath(test_file_name_);
-    }
-
-    android::base::unique_fd GetFd() {
-        return android::base::unique_fd(open(mount_path_.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
-    }
-
-    int32_t getReadTimeout() override { return 1; }
-
-    std::unique_ptr<IncFsFileMap> GetFileMap(int fd, off64_t offset, size_t length) {
-        auto map = std::make_unique<IncFsFileMap>();
-        return map->Create(fd, offset, length, nullptr) ? std::move(map) : nullptr;
-    }
-
-private:
-    std::string mount_path_;
-};
-
-struct TwoValues {
-    uint32_t first;
-    uint32_t second;
-};
-
-TEST_F(MapPtrTest, ReadAtStart) {
-    auto fd = GetFd();
-    auto map = GetFileMap(fd.get(), 0U /* offset */, FILE_SIZE);
-    ASSERT_NE(nullptr, map);
-
-    auto p1 = map->data<uint32_t>();
-    ASSERT_TRUE(p1);
-    ASSERT_EQ(0U, p1.value());
-
-    auto p2 = map->data<TwoValues>();
-    ASSERT_TRUE(p2);
-    ASSERT_EQ(0U, p2->first);
-    ASSERT_EQ(1U, p2->second);
-}
-
-TEST_F(MapPtrTest, ReadNull) {
-    auto fd = GetFd();
-    auto map = GetFileMap(fd.get(), 0U /* offset */, FILE_SIZE);
-    ASSERT_NE(nullptr, map);
-
-    auto p1 = map->data<uint32_t>();
-    ASSERT_TRUE(p1);
-    ASSERT_EQ(0U, p1.value());
-
-    p1 = nullptr;
-    ASSERT_FALSE(p1);
-
-    p1 = map->data<uint32_t>();
-    ASSERT_TRUE(p1);
-    ASSERT_EQ(0U, p1.value());
-}
-
-TEST_F(MapPtrTest, ReadAtStartWithOffset) {
-    auto fd = GetFd();
-    auto map = GetFileMap(fd.get(), sizeof(uint32_t) * 4U /* offset */, FILE_SIZE);
-    ASSERT_NE(nullptr, map);
-
-    auto p1 = map->data<uint32_t>();
-    ASSERT_TRUE(p1);
-    ASSERT_EQ(4U, p1.value());
-
-    auto p2 = map->data<TwoValues>();
-    ASSERT_TRUE(p2);
-    ASSERT_EQ(4U, p2->first);
-    ASSERT_EQ(5U, p2->second);
-}
-
-TEST_F(MapPtrTest, PointerArithmetic) {
-    auto fd = GetFd();
-    auto map = GetFileMap(fd.get(), 0U /* offset */, FILE_SIZE);
-    ASSERT_NE(nullptr, map);
-
-    auto p1 = map->data<uint32_t>() + 11U;
-    ASSERT_TRUE(p1);
-    ASSERT_EQ(11U, p1.value());
-
-    auto p2 = p1 - 5U;
-    ASSERT_TRUE(p2);
-    ASSERT_EQ(6U, p2.value());
-
-    auto dis = p1 - p2;
-    ASSERT_EQ((ptrdiff_t)5U, dis);
-}
-
-TEST_F(MapPtrTest, PointerIncrement) {
-    auto fd = GetFd();
-    auto map = GetFileMap(fd.get(), 0U /* offset */, FILE_SIZE);
-    ASSERT_NE(nullptr, map);
-
-    auto p1 = map->data<uint32_t>();
-    ASSERT_TRUE(p1);
-    ASSERT_EQ(0U, p1.value());
-
-    auto p2 = p1++;
-    ASSERT_TRUE(p1);
-    ASSERT_TRUE(p2);
-    ASSERT_EQ(1U, p1.value());
-    ASSERT_EQ(0U, p2.value());
-
-    auto p3 = ++p2;
-    ASSERT_TRUE(p2);
-    ASSERT_TRUE(p3);
-    ASSERT_EQ(1U, p2.value());
-    ASSERT_EQ(1U, p3.value());
-}
-
-TEST_F(MapPtrTest, PointerComparison) {
-    auto fd = GetFd();
-    auto map = GetFileMap(fd.get(), 0U /* offset */, FILE_SIZE);
-    ASSERT_NE(nullptr, map);
-
-    auto p1 = map->data<uint32_t>();
-    ASSERT_TRUE(p1);
-    ASSERT_EQ(0U, p1.value());
-
-    auto p2 = p1;
-    ASSERT_TRUE(p1 == p2);
-    ASSERT_TRUE(p1 < p2 + 1U);
-    ASSERT_TRUE(p2 != p2 + 1U);
-}
-
-TEST_F(MapPtrTest, PointerConvert) {
-    auto fd = GetFd();
-    auto map = GetFileMap(fd.get(), 0U /* offset */, FILE_SIZE);
-    ASSERT_NE(nullptr, map);
-
-    auto p1 = (map->data<uint32_t>() + 11U).convert<TwoValues>();
-    ASSERT_TRUE(p1);
-    ASSERT_EQ(11U, p1->first);
-    ASSERT_EQ(12U, p1->second);
-}
-
-TEST_F(MapPtrTest, PointerOffset) {
-    auto fd = GetFd();
-    auto map = GetFileMap(fd.get(), 0U /* offset */, FILE_SIZE);
-    ASSERT_NE(nullptr, map);
-
-    auto p1 = map->data().offset(11U * sizeof(uint32_t)).convert<TwoValues>();
-    ASSERT_TRUE(p1);
-    ASSERT_EQ(11U, p1->first);
-    ASSERT_EQ(12U, p1->second);
-}
-
-TEST_F(MapPtrTest, Iterator) {
-    auto fd = GetFd();
-    auto map = GetFileMap(fd.get(), 0U /* offset */, FILE_SIZE);
-    ASSERT_NE(nullptr, map);
-
-    auto it = map->data<uint32_t>().iterator();
-    ASSERT_TRUE(*it);
-    ASSERT_EQ(0U, (*it).value());
-
-    auto it2 = it;
-    ASSERT_EQ(it, it2);
-
-    auto it3 = it++;
-    ASSERT_TRUE(*it3);
-    ASSERT_EQ(0U, (*it3).value());
-
-    ASSERT_NE(it, it2);
-    ASSERT_EQ(1, it - it2);
-    ASSERT_EQ(-1, it2 - it);
-
-    auto it4 = ++it;
-    ASSERT_TRUE(*it4);
-    ASSERT_EQ(2U, (*it4).value());
-
-    it += 10;
-    ASSERT_EQ(12U, (*it).value());
-}
-
-static jmp_buf buf;
-
-void sigbus_handler(int sig) {
-    if (sig == SIGBUS) {
-        siglongjmp(buf, 1);
-    } else {
-        FAIL();
-    }
-}
-
-#define ASSERT_SIGBUS(test)               \
-    do {                                  \
-        signal(SIGBUS, &sigbus_handler);  \
-        if (sigsetjmp(buf, 1) == 0) {     \
-            ASSERT_EQ(0U, (test));        \
-            FAIL() << "No signal raised"; \
-        }                                 \
-    } while (0)
-
-TEST_F(MapPtrTest, VerifyMissingPageFails) {
-    for (uint32_t off :
-         std::vector<uint32_t>{0U, INCFS_DATA_FILE_BLOCK_SIZE / 2 - 1,
-                               INCFS_DATA_FILE_BLOCK_SIZE / 2 + 1, INCFS_DATA_FILE_BLOCK_SIZE,
-                               INCFS_DATA_FILE_BLOCK_SIZE * 3 / 2 - 1,
-                               INCFS_DATA_FILE_BLOCK_SIZE * 3 / 2 + 1}) {
-        auto fd = GetFd();
-        auto map = GetFileMap(fd.get(), off /* offset */, FILE_SIZE);
-        ASSERT_NE(nullptr, map);
-
-        auto missing_page_start = INCFS_DATA_FILE_BLOCK_SIZE * FILE_MISSING_PAGE;
-        auto p1 = map->data().offset(missing_page_start - off).convert<uint32_t>();
-        ASSERT_FALSE(p1);
-        ASSERT_SIGBUS(p1.value());
-
-        const auto p2 = p1;
-        ASSERT_FALSE(p2);
-        ASSERT_SIGBUS(p2.value());
-
-        const auto p3 = p2 - 1U;
-        ASSERT_TRUE(p3);
-        ASSERT_EQ(3071U, p3.value());
-
-        auto p4 = p3;
-        ASSERT_TRUE(p4);
-        ASSERT_EQ(3071U, p4.value());
-
-        ASSERT_FALSE(p4 + 1U);
-        ASSERT_SIGBUS((p4 + 1U).value());
-
-        auto p5 = p4++;
-        ASSERT_TRUE(p5);
-        ASSERT_EQ(3071U, p5.value());
-        ASSERT_FALSE(p4);
-        ASSERT_SIGBUS(p4.value());
-
-        auto p6 = p3;
-        ASSERT_TRUE(p6);
-        ASSERT_EQ(3071U, p6.value());
-
-        auto p7 = ++p6;
-        ASSERT_FALSE(p7);
-        ASSERT_SIGBUS(p7.value());
-        ASSERT_FALSE(p6);
-        ASSERT_SIGBUS(p6.value());
-
-        auto missing_page_end = INCFS_DATA_FILE_BLOCK_SIZE * (FILE_MISSING_PAGE + 1);
-        auto p8 = map->data().offset(missing_page_end - off).convert<uint32_t>();
-        ASSERT_TRUE(p8);
-        ASSERT_EQ(4096U, p8.value());
-
-        ASSERT_FALSE(p8 - 1U);
-        ASSERT_SIGBUS((p8 - 1U).value());
-    }
-}
-
-TEST_F(MapPtrTest, GetDataAfterClose) {
-    std::unique_ptr<IncFsFileMap> map;
-    {
-        auto fd = GetFd();
-        map = GetFileMap(fd.get(), 0U /* offset */, FILE_SIZE);
-        ASSERT_NE(nullptr, map);
-    }
-
-    auto missing_page_start = INCFS_DATA_FILE_BLOCK_SIZE * FILE_MISSING_PAGE;
-    auto p1 = map->data().offset(missing_page_start).convert<uint32_t>();
-    ASSERT_FALSE(p1);
-    ASSERT_SIGBUS(p1.value());
-}
\ No newline at end of file
diff --git a/incfs/util/include/util/map_ptr.h b/incfs/util/include/util/map_ptr.h
deleted file mode 100644
index 304540f..0000000
--- a/incfs/util/include/util/map_ptr.h
+++ /dev/null
@@ -1,412 +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 <android-base/logging.h>
-#include <android-base/off64_t.h>
-
-#include <atomic>
-#include <iterator>
-#include <memory>
-#include <shared_mutex>
-#include <type_traits>
-#include <vector>
-
-#ifdef __ANDROID__
-#include <linux/incrementalfs.h>
-#endif
-
-namespace android {
-
-class FileMap;
-
-namespace incfs {
-
-// Controls whether not verifying the presence of data before de-referencing the pointer aborts
-// program execution.
-#define LIBINCFS_MAP_PTR_DEBUG false
-#if LIBINCFS_MAP_PTR_DEBUG
-#define LIBINCFS_MAP_PTR_DEBUG_CODE(x) x
-#else
-#define LIBINCFS_MAP_PTR_DEBUG_CODE(x)
-#endif
-
-template <typename T, bool Verified = false>
-struct map_ptr;
-
-// This class represents a memory-mapped, read-only file that may exist on an IncFs file system.
-//
-// Files stored on IncFs may not be fully present. This class is able to return a smart pointer
-// (map_ptr<T>) that is able to verify whether the contents of the pointer are fully present on
-// IncFs.
-//
-// This always uses MAP_SHARED.
-class IncFsFileMap final {
-public:
-    IncFsFileMap() noexcept;
-    IncFsFileMap(IncFsFileMap&&) noexcept;
-    IncFsFileMap& operator =(IncFsFileMap&&) noexcept;
-    ~IncFsFileMap() noexcept;
-
-    // Initializes the map. Does not take ownership of the file descriptor.
-    // Returns whether or not the file was able to be memory-mapped.
-    bool Create(int fd, off64_t offset, size_t length, const char* file_name);
-
-    // Same thing, but allows verification to be disabled when `verify` is `false`, and enabled when
-    // `verify` is true and the file resides on IncFs.
-    bool Create(int fd, off64_t offset, size_t length, const char* file_name, bool verify);
-
-    // Same thing, but allows verification to be disabled when `verify` is `false`, and enabled when
-    // `verify` is true regardless of whether the file resides on IncFs (used for benchmarks and
-    // testing).
-    bool CreateForceVerification(int fd, off64_t offset, size_t length, const char* file_name,
-                                 bool verify);
-
-    template <typename T = void>
-    map_ptr<T> data() const {
-        return map_ptr<T>(verification_enabled_ ? this : nullptr,
-                          reinterpret_cast<const T*>(unsafe_data()));
-    }
-
-    const void* unsafe_data() const;
-    size_t length() const;
-    off64_t offset() const;
-    const char* file_name() const;
-
-public:
-    // Returns whether the data range is entirely present on IncFs.
-    bool Verify(const uint8_t* const& data_start, const uint8_t* const& data_end,
-                const uint8_t** prev_verified_block) const;
-
-private:
-    DISALLOW_COPY_AND_ASSIGN(IncFsFileMap);
-
-    using bucket_t = uint8_t;
-    static constexpr size_t kBucketBits = sizeof(bucket_t) * 8U;
-
-    // File descriptor of the memory-mapped file (not owned).
-    int fd_ = -1;
-    bool verification_enabled_ = false;
-    size_t start_block_offset_ = 0;
-    const uint8_t* start_block_ptr_ = nullptr;
-
-    std::unique_ptr<android::FileMap> map_;
-
-    // Bitwise cache for storing whether a block has already been verified. This cache relies on
-    // IncFs not deleting blocks of a file that is currently memory mapped.
-    mutable std::vector<std::atomic<bucket_t>> loaded_blocks_;
-
-    template <typename, bool>
-    friend struct map_ptr;
-};
-
-// Variant of map_ptr that statically guarantees that the pointed to data is fully present and
-// reading data will not result in IncFs raising a SIGBUS.
-template <typename T>
-using verified_map_ptr = map_ptr<T, true>;
-
-// Smart pointer that is able to verify whether the contents of the pointer are fully present on
-// the file system before using the pointer. Files residing on IncFs may not be fully present.
-//
-// Before attempting to use the data represented by the smart pointer, the caller should always use
-// the bool operator to verify the presence of the data. The bool operator is not thread-safe. If
-// this pointer must be used in multiple threads concurrently, use verified_map_ptr instead.
-//
-// map_ptr created from raw pointers have less overhead than when created from IncFsFileMap.
-template <typename T, bool Verified>
-struct map_ptr final {
-private:
-    friend class IncFsFileMap;
-
-    // To access internals of map_ptr with a different type
-    template <typename, bool>
-    friend struct map_ptr;
-
-    template <typename T1>
-    using IsVoid = typename std::enable_if_t<std::is_void<T1>::value, int>;
-
-    template <typename T1>
-    using NotVoid = typename std::enable_if_t<!std::is_void<T1>::value, int>;
-
-    template <bool V>
-    using IsVerified = typename std::enable_if_t<V, int>;
-
-    template <bool V>
-    using IsUnverified = typename std::enable_if_t<!V, int>;
-
-public:
-    class const_iterator final {
-    public:
-        friend struct map_ptr<T, Verified>;
-        using iterator_category = std::random_access_iterator_tag;
-        using value_type = const map_ptr<T>;
-        using difference_type = std::ptrdiff_t;
-        using pointer = void;
-        using reference = value_type;
-
-        const_iterator() = default;
-        const_iterator(const const_iterator& it) = default;
-
-        bool operator==(const const_iterator& other) const { return safe_ptr_ == other.safe_ptr_; }
-        bool operator!=(const const_iterator& other) const { return safe_ptr_ != other.safe_ptr_; }
-        std::ptrdiff_t operator-(const const_iterator& other) const {
-            return safe_ptr_ - other.safe_ptr_;
-        }
-
-        const_iterator operator+(int n) const {
-            const_iterator other = *this;
-            other += n;
-            return other;
-        }
-
-        reference operator*() const { return safe_ptr_; }
-
-        const const_iterator& operator++() {
-            safe_ptr_++;
-            return *this;
-        }
-
-        const_iterator& operator+=(int n) {
-            safe_ptr_ = safe_ptr_ + n;
-            return *this;
-        }
-
-        const const_iterator operator++(int) {
-            const_iterator temp(*this);
-            safe_ptr_++;
-            return temp;
-        }
-
-    private:
-        explicit const_iterator(const map_ptr<T>& ptr) : safe_ptr_(ptr) {}
-        map_ptr<T> safe_ptr_;
-    };
-
-    // Default constructor
-    map_ptr() = default;
-
-    // Implicit conversion from raw pointer
-    map_ptr(const T* ptr) : map_ptr(nullptr, ptr, nullptr) {}
-
-    // Copy constructor
-    map_ptr(const map_ptr& other) = default;
-
-    // Implicit copy conversion from verified to unverified map_ptr<T>
-    template <bool V2, bool V1 = Verified, IsUnverified<V1> = 0, IsVerified<V2> = 0>
-    map_ptr(const map_ptr<T, V2>& other) : map_ptr(other.map_, other.ptr_, other.verified_block_) {}
-
-    // Move constructor
-    map_ptr(map_ptr&& other) noexcept = default;
-
-    // Implicit move conversion from verified to unverified map_ptr<T>
-    template <bool V2, bool V1 = Verified, IsUnverified<V1> = 0, IsVerified<V2> = 0>
-    map_ptr(map_ptr&& other) : map_ptr(other.map_, other.ptr_, other.verified_block_) {}
-
-    // Implicit conversion to unverified map_ptr<void>
-    template <typename U, bool V2, typename T1 = T, bool V1 = Verified, IsVoid<T1> = 0,
-              NotVoid<U> = 0, IsUnverified<V1> = 0>
-    map_ptr(const map_ptr<U, V2>& other)
-          : map_ptr(other.map_, reinterpret_cast<const void*>(other.ptr_), other.verified_block_) {}
-
-    // Implicit conversion from regular raw pointer
-    map_ptr& operator=(const T* ptr) {
-        ptr_ = ptr;
-        map_ = nullptr;
-        verified_block_ = nullptr;
-        LIBINCFS_MAP_PTR_DEBUG_CODE(verified_ = Verified);
-        return *this;
-    }
-
-    // Copy assignment operator
-    map_ptr& operator=(const map_ptr& other) = default;
-
-    // Copy assignment operator
-    template <bool V2, bool V1 = Verified, IsUnverified<V1> = 0, IsVerified<V2> = 0>
-    map_ptr& operator=(const map_ptr<T, V2>& other) {
-        ptr_ = other.ptr_;
-        map_ = other.map_;
-        verified_block_ = other.verified_block_;
-        LIBINCFS_MAP_PTR_DEBUG_CODE(verified_ = other.verified_);
-        return *this;
-    }
-
-    template <bool V2>
-    bool operator==(const map_ptr<T, V2>& other) const {
-        return ptr_ == other.ptr_;
-    }
-
-    template <bool V2>
-    bool operator!=(const map_ptr<T, V2>& other) const {
-        return ptr_ != other.ptr_;
-    }
-
-    template <bool V2>
-    bool operator<(const map_ptr<T, V2>& other) const {
-        return ptr_ < other.ptr_;
-    }
-
-    template <bool V2>
-    std::ptrdiff_t operator-(const map_ptr<T, V2>& other) const {
-        return ptr_ - other.ptr_;
-    }
-
-    template <typename U>
-    map_ptr<U> convert() const {
-        return map_ptr<U>(map_, reinterpret_cast<const U*>(ptr_), verified_block_);
-    }
-
-    // Retrieves a map_ptr<T> offset from an original map_ptr<U> by the specified number of `offset`
-    // bytes.
-    map_ptr<T> offset(std::ptrdiff_t offset) const {
-        return map_ptr<T>(map_,
-                          reinterpret_cast<const T*>(reinterpret_cast<const uint8_t*>(ptr_) +
-                                                     offset),
-                          verified_block_);
-    }
-
-    // Returns a raw pointer to the value of this pointer.
-    const T* unsafe_ptr() const { return ptr_; }
-
-    // Start T == void methods
-
-    template <typename T1 = T, IsVoid<T1> = 0>
-    operator bool() const {
-        return ptr_ != nullptr;
-    }
-
-    // End T == void methods
-    // Start T != void methods
-
-    template <typename T1 = T, NotVoid<T1> = 0, bool V1 = Verified, IsUnverified<V1> = 0>
-    operator bool() const {
-        return verify();
-    }
-
-    template <typename T1 = T, NotVoid<T1> = 0, bool V1 = Verified, IsVerified<V1> = 0>
-    operator bool() const {
-        return ptr_ != nullptr;
-    }
-
-    template <typename T1 = T, NotVoid<T1> = 0>
-    const_iterator iterator() const {
-        return const_iterator(*this);
-    }
-
-    template <typename T1 = T, NotVoid<T1> = 0>
-    const map_ptr<T1>& operator++() {
-        LIBINCFS_MAP_PTR_DEBUG_CODE(verified_ = false);
-        ++ptr_;
-        return *this;
-    }
-
-    template <typename T1 = T, NotVoid<T1> = 0>
-    const map_ptr<T1> operator++(int) {
-        map_ptr<T1> temp = *this;
-        LIBINCFS_MAP_PTR_DEBUG_CODE(verified_ = false);
-        ++ptr_;
-        return temp;
-    }
-
-    template <typename S, typename T1 = T, NotVoid<T1> = 0>
-    map_ptr<T1> operator+(const S n) const {
-        return map_ptr<T1>(map_, ptr_ + n, verified_block_);
-    }
-
-    template <typename S, typename T1 = T, NotVoid<T1> = 0>
-    map_ptr<T1> operator-(const S n) const {
-        return map_ptr<T1>(map_, ptr_ - n, verified_block_);
-    }
-
-    // Returns the value of the pointer.
-    // The caller should verify the presence of the pointer data before calling this method.
-    template <typename T1 = T, NotVoid<T1> = 0>
-    const T1& value() const {
-        LIBINCFS_MAP_PTR_DEBUG_CODE(
-                CHECK(verified_) << "Did not verify presence before de-referencing safe pointer");
-        return *ptr_;
-    }
-
-    // Returns a raw pointer to the value this pointer.
-    // The caller should verify the presence of the pointer data before calling this method.
-    template <typename T1 = T, NotVoid<T1> = 0>
-    const T1* operator->() const {
-        LIBINCFS_MAP_PTR_DEBUG_CODE(
-                CHECK(verified_) << "Did not verify presence before de-referencing safe pointer");
-        return ptr_;
-    }
-
-    // Verifies the presence of `n` elements of `T`.
-    //
-    // Returns true if the elements are completely present; otherwise, returns false.
-    template <typename T1 = T, NotVoid<T1> = 0, bool V1 = Verified, IsUnverified<V1> = 0>
-    bool verify(size_t n = 1) const {
-        if (ptr_ == nullptr) {
-            return false;
-        }
-
-#ifdef __ANDROID__
-        if (LIKELY(map_ == nullptr)) {
-            return ptr_ != nullptr;
-        }
-
-        const size_t verify_size = sizeof(T) * n;
-        LIBINCFS_MAP_PTR_DEBUG_CODE(if (sizeof(T) <= verify_size) verified_ = true;);
-
-        const auto data_start = reinterpret_cast<const uint8_t*>(ptr_);
-        const auto data_end = reinterpret_cast<const uint8_t*>(ptr_) + verify_size;
-
-        // If the data is entirely within the block beginning at the previous verified block
-        // pointer, then the data can safely be used.
-        if (LIKELY(data_start >= verified_block_ &&
-                   data_end <= verified_block_ + INCFS_DATA_FILE_BLOCK_SIZE)) {
-            return true;
-        }
-
-        if (LIKELY(map_->Verify(data_start, data_end, &verified_block_))) {
-            return true;
-        }
-
-        LIBINCFS_MAP_PTR_DEBUG_CODE(verified_ = false);
-        return false;
-#else
-        (void)n;
-        return true;
-#endif
-    }
-
-    // Returns a verified version of this pointer.
-    // The caller should verify the presence of the pointer data before calling this method.
-    template <typename T1 = T, NotVoid<T1> = 0>
-    verified_map_ptr<T1> verified() const {
-        return verified_map_ptr<T1>(map_, ptr_, verified_block_);
-    }
-
-private:
-    map_ptr(const IncFsFileMap* map, const T* ptr)
-          : ptr_(ptr), map_(map), verified_block_(nullptr) {}
-    map_ptr(const IncFsFileMap* map, const T* ptr, const uint8_t* verified_block)
-          : ptr_(ptr), map_(map), verified_block_(verified_block) {}
-
-    const T* ptr_ = nullptr;
-    mutable const IncFsFileMap* map_ = nullptr;
-    mutable const uint8_t* verified_block_;
-    LIBINCFS_MAP_PTR_DEBUG_CODE(mutable bool verified_ = Verified);
-};
-
-} // namespace incfs
-
-} // namespace android
\ No newline at end of file
diff --git a/incfs/util/map_ptr.cpp b/incfs/util/map_ptr.cpp
deleted file mode 100644
index f391506..0000000
--- a/incfs/util/map_ptr.cpp
+++ /dev/null
@@ -1,157 +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/file.h>
-#include <android-base/stringprintf.h>
-#include <utils/FileMap.h>
-
-#ifdef __ANDROID__
-#include "incfs_inline.h"
-#endif
-
-#include "util/map_ptr.h"
-
-namespace android::incfs {
-IncFsFileMap::IncFsFileMap() noexcept = default;
-IncFsFileMap::IncFsFileMap(IncFsFileMap&&) noexcept = default;
-IncFsFileMap& IncFsFileMap::operator =(IncFsFileMap&&) noexcept = default;
-IncFsFileMap::~IncFsFileMap() noexcept = default;
-
-const void* IncFsFileMap::unsafe_data() const {
-    return map_->getDataPtr();
-}
-
-size_t IncFsFileMap::length() const {
-    return map_->getDataLength();
-}
-
-off64_t IncFsFileMap::offset() const {
-    return map_->getDataOffset();
-}
-
-const char* IncFsFileMap::file_name() const {
-    return map_->getFileName();
-}
-
-bool IncFsFileMap::Create(int fd, off64_t offset, size_t length, const char* file_name) {
-    return Create(fd, offset, length, file_name, true /* verify */);
-}
-
-#ifdef __ANDROID__
-static bool IsVerificationEnabled(int fd) {
-    return isIncFsFd(fd) && isFullyLoaded(fd) != LoadingState::Full;
-}
-
-using data_block_index_t = uint32_t;
-
-static data_block_index_t get_block_index(const uint8_t* ptr, const uint8_t* start_block_ptr) {
-    return (ptr - start_block_ptr) / INCFS_DATA_FILE_BLOCK_SIZE;
-}
-
-bool IncFsFileMap::Create(int fd, off64_t offset, size_t length, const char* file_name,
-                          bool verify) {
-    return CreateForceVerification(fd, offset, length, file_name,
-                                   verify && IsVerificationEnabled(fd));
-}
-
-bool IncFsFileMap::CreateForceVerification(int fd, off64_t offset, size_t length,
-                                           const char* file_name, bool verify) {
-    map_ = std::make_unique<android::FileMap>();
-    if (!map_->create(file_name, fd, offset, length, true /* readOnly */)) {
-        return false;
-    }
-
-    fd_ = fd;
-    verification_enabled_ = verify;
-    if (verification_enabled_) {
-        // Initialize the block cache with enough buckets to hold all of the blocks within the
-        // memory-mapped region.
-        size_t offset_diff = offset % INCFS_DATA_FILE_BLOCK_SIZE;
-        size_t base_length_ = length + offset_diff;
-        start_block_offset_ = offset - offset_diff;
-        start_block_ptr_ = reinterpret_cast<const uint8_t*>(map_->getDataPtr()) - offset_diff;
-
-        const size_t bucket_count = (base_length_ / INCFS_DATA_FILE_BLOCK_SIZE) / kBucketBits;
-        loaded_blocks_ = std::vector<std::atomic<bucket_t> >(bucket_count + 1U);
-    }
-    return true;
-}
-
-bool IncFsFileMap::Verify(const uint8_t* const& data_start, const uint8_t* const& data_end,
-                          const uint8_t** prev_verified_block) const {
-    const data_block_index_t start_index = get_block_index(data_start, start_block_ptr_);
-    const data_block_index_t end_index = get_block_index(data_end - 1U, start_block_ptr_);
-
-    bool success = true;
-    // Retrieve the set of the required blocks that must be present in order to read the data
-    // safely.
-    for (data_block_index_t curr_index = start_index; curr_index <= end_index; ++curr_index) {
-        const size_t i = curr_index / kBucketBits;
-        const bucket_t present_bit = 1U << (curr_index % kBucketBits);
-        std::atomic<bucket_t>& bucket = loaded_blocks_[i];
-        if (LIKELY(bucket.load(std::memory_order_relaxed) & present_bit)) {
-            continue;
-        }
-
-        // Touch all of the blocks with pread to ensure that the region of data is fully present.
-        uint8_t value;
-        const off64_t read_offset = (curr_index * INCFS_DATA_FILE_BLOCK_SIZE) + start_block_offset_;
-        if (UNLIKELY(TEMP_FAILURE_RETRY(pread64(fd_, &value, 1U, read_offset)) <= 0)) {
-            success = false;
-            break;
-        }
-
-        bucket.fetch_or(present_bit, std::memory_order_relaxed);
-    }
-
-    if (UNLIKELY(!success)) {
-        // Log the region of the file that could not be fully loaded.
-        size_t start_offset = (data_start - start_block_ptr_) + map_->getDataOffset();
-        size_t end_offset = (data_end - start_block_ptr_) + map_->getDataOffset();
-        std::string location = file_name() ? base::StringPrintf("path %s", file_name())
-                                           : base::StringPrintf("fd %d", fd_);
-        const std::string message =
-                base::StringPrintf("region 0x%016zx - 0x%016zx of %s not fully loaded",
-                                   start_offset, end_offset, location.c_str());
-        LOG(WARNING) << message;
-        return false;
-    }
-
-    // Update the previous verified block pointer to optimize repeated verifies on the same block.
-    *prev_verified_block = start_block_ptr_ + (end_index * INCFS_DATA_FILE_BLOCK_SIZE);
-    return true;
-}
-
-#else
-bool IncFsFileMap::Create(int fd, off64_t offset, size_t length, const char* file_name,
-                          bool verify) {
-    return CreateForceVerification(fd, offset, length, file_name, verify);
-}
-
-bool IncFsFileMap::CreateForceVerification(int fd, off64_t offset, size_t length,
-                                           const char* file_name, bool /* verify */) {
-    map_ = std::make_unique<android::FileMap>();
-    return map_->create(file_name, fd, offset, length, true /* readOnly */);
-}
-
-bool IncFsFileMap::Verify(const uint8_t* const& /* data_start */,
-                          const uint8_t* const& /* data_end */,
-                          const uint8_t** /* prev_verified_block */) const {
-    return true;
-}
-#endif
-
-} // namespace android::incfs
\ No newline at end of file
diff --git a/libdataloader/Android.bp b/libdataloader/Android.bp
index eb9adf4..142a409 100644
--- a/libdataloader/Android.bp
+++ b/libdataloader/Android.bp
@@ -12,25 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package {
-    default_applicable_licenses: [
-        "system_incremental_delivery_libdataloader_license",
-    ],
-}
-
-// Added automatically by a large-scale-change
-// See: http://go/android-license-faq
-license {
-    name: "system_incremental_delivery_libdataloader_license",
-    visibility: [":__subpackages__"],
-    license_kinds: [
-        "SPDX-license-identifier-Apache-2.0",
-    ],
-    license_text: [
-        "NOTICE",
-    ],
-}
-
 cc_defaults {
     name: "libdataloader_defaults",
     cpp_std: "c++2a",
@@ -42,11 +23,9 @@
         "libbase",
         "libincfs",
         "liblog",
+        "libnativehelper",
         "libutils",
     ],
-    static_libs: [
-        "libnativehelper_lazy",
-    ],
     tidy: true,
     tidy_checks: [
         "android-*",
diff --git a/libdataloader/DataLoaderConnector.cpp b/libdataloader/DataLoaderConnector.cpp
index f5f82ea..5e41f4f 100644
--- a/libdataloader/DataLoaderConnector.cpp
+++ b/libdataloader/DataLoaderConnector.cpp
@@ -17,9 +17,7 @@
 
 #include <android-base/logging.h>
 #include <fcntl.h>
-#include <nativehelper/JNIPlatformHelp.h>
-#include <nativehelper/scoped_local_ref.h>
-#include <nativehelper/scoped_utf_chars.h>
+#include <nativehelper/JNIHelp.h>
 #include <sys/stat.h>
 #include <utils/Looper.h>
 
@@ -30,15 +28,12 @@
 #include "ManagedDataLoader.h"
 #include "dataloader.h"
 #include "incfs.h"
-#include "path.h"
 
 namespace {
 
+using namespace android::dataloader;
 using namespace std::literals;
 
-using ReadInfo = android::dataloader::ReadInfo;
-using ReadInfoWithUid = android::dataloader::ReadInfoWithUid;
-
 using FileId = android::incfs::FileId;
 using RawMetadata = android::incfs::RawMetadata;
 using UniqueControl = android::incfs::UniqueControl;
@@ -72,7 +67,6 @@
     jfieldID controlCmd;
     jfieldID controlPendingReads;
     jfieldID controlLog;
-    jfieldID controlBlocksWritten;
 
     jfieldID paramsType;
     jfieldID paramsPackageName;
@@ -117,6 +111,8 @@
         constants.DATA_LOADER_UNRECOVERABLE =
                 GetStaticIntFieldValueOrDie(env, listener, "DATA_LOADER_UNRECOVERABLE");
 
+        CHECK(constants.DATA_LOADER_UNRECOVERABLE == DATA_LOADER_UNRECOVERABLE);
+
         auto packageInstaller = (jclass)FindClassOrDie(env, "android/content/pm/PackageInstaller");
 
         constants.DATA_LOADER_TYPE_NONE =
@@ -162,8 +158,6 @@
         controlPendingReads = GetFieldIDOrDie(env, incControl, "pendingReads",
                                               "Landroid/os/ParcelFileDescriptor;");
         controlLog = GetFieldIDOrDie(env, incControl, "log", "Landroid/os/ParcelFileDescriptor;");
-        controlBlocksWritten = GetFieldIDOrDie(env, incControl, "blocksWritten",
-                                               "Landroid/os/ParcelFileDescriptor;");
 
         auto params = FindClassOrDie(env, "android/content/pm/DataLoaderParamsParcel");
         paramsType = GetFieldIDOrDie(env, params, "type", "I");
@@ -210,17 +204,6 @@
     return ids;
 }
 
-bool checkAndClearJavaException(JNIEnv* env, std::string_view method) {
-    if (!env->ExceptionCheck()) {
-        return false;
-    }
-
-    LOG(ERROR) << "Java exception during DataLoader::" << method;
-    env->ExceptionDescribe();
-    env->ExceptionClear();
-    return true;
-}
-
 bool reportStatusViaCallback(JNIEnv* env, jobject listener, jint storageId, jint status) {
     if (listener == nullptr) {
         ALOGE("No listener object to talk to IncrementalService. "
@@ -245,10 +228,12 @@
 using DataLoaderConnectorsMap = std::unordered_map<int, DataLoaderConnectorPtr>;
 
 struct Globals {
-    Globals() { managedDataLoaderFactory = new android::dataloader::ManagedDataLoaderFactory(); }
+    Globals() {
+        managedDataLoaderFactory = new details::DataLoaderFactoryImpl(
+                [](auto jvm, auto) { return std::make_unique<ManagedDataLoader>(jvm); });
+    }
 
     DataLoaderFactory* managedDataLoaderFactory = nullptr;
-    DataLoaderFactory* legacyDataLoaderFactory = nullptr;
     DataLoaderFactory* dataLoaderFactory = nullptr;
 
     std::mutex dataLoaderConnectorsLock;
@@ -260,8 +245,6 @@
     std::thread logLooperThread;
     std::vector<ReadInfo> pendingReads;
     std::vector<ReadInfo> pageReads;
-    std::vector<ReadInfoWithUid> pendingReadsWithUid;
-    std::vector<ReadInfoWithUid> pageReadsWithUid;
 };
 
 static Globals& globals() {
@@ -301,8 +284,7 @@
 
 static constexpr auto kPendingReadsBufferSize = 256;
 
-class DataLoaderConnector : public android::dataloader::FilesystemConnector,
-                            public android::dataloader::StatusListener {
+class DataLoaderConnector : public FilesystemConnector, public StatusListener {
 public:
     DataLoaderConnector(JNIEnv* env, jobject service, jint storageId, UniqueControl control,
                         jobject serviceConnector, jobject callbackControl, jobject listener)
@@ -318,68 +300,36 @@
     DataLoaderConnector(const DataLoaderConnector&) = delete;
     DataLoaderConnector(const DataLoaderConnector&&) = delete;
     virtual ~DataLoaderConnector() {
-        if (mDataLoader && mDataLoader->onDestroy) {
-            mDataLoader->onDestroy(mDataLoader);
-            checkAndClearJavaException(__func__);
-        }
-        mDataLoader = nullptr;
-
         JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
 
-        const auto& jni = jniIds(env);
-        reportStatusViaCallback(env, mListener, mStorageId, jni.constants.DATA_LOADER_DESTROYED);
-
         env->DeleteGlobalRef(mService);
         env->DeleteGlobalRef(mServiceConnector);
         env->DeleteGlobalRef(mCallbackControl);
         env->DeleteGlobalRef(mListener);
     } // to avoid delete-non-virtual-dtor
 
-    bool tryFactory(DataLoaderFactory* factory, bool withFeatures,
-                    const DataLoaderParamsPair& params, jobject managedParams) {
-        if (!factory) {
-            return true;
-        }
-
-        // Let's try the non-default first.
-        mDataLoader = factory->onCreate(factory, &params.ndkDataLoaderParams(), this, this, mJvm,
-                                        mService, managedParams);
-        if (checkAndClearJavaException(__func__)) {
-            return false;
-        }
-        if (!mDataLoader) {
-            return true;
-        }
-
-        mDataLoaderFeatures = withFeatures && mDataLoader->getFeatures
-                ? mDataLoader->getFeatures(mDataLoader)
-                : DATA_LOADER_FEATURE_NONE;
-        if (mDataLoaderFeatures & DATA_LOADER_FEATURE_UID) {
-            ALOGE("DataLoader supports UID");
-            CHECK(mDataLoader->onPageReadsWithUid);
-            CHECK(mDataLoader->onPendingReadsWithUid);
-        }
-        return true;
-    }
-
     bool onCreate(const DataLoaderParamsPair& params, jobject managedParams) {
         CHECK(mDataLoader == nullptr);
 
-        if (!mDataLoader &&
-            !tryFactory(globals().dataLoaderFactory, /*withFeatures=*/true, params,
-                        managedParams)) {
-            return false;
+        if (auto factory = globals().dataLoaderFactory) {
+            // Let's try the non-default first.
+            mDataLoader = factory->onCreate(factory, &params.ndkDataLoaderParams(), this, this,
+                                            mJvm, mService, managedParams);
+            if (checkAndClearJavaException(__func__)) {
+                return false;
+            }
         }
-        if (!mDataLoader &&
-            !tryFactory(globals().legacyDataLoaderFactory, /*withFeatures=*/false, params,
-                        managedParams)) {
-            return false;
+
+        if (!mDataLoader) {
+            // Didn't work, let's try the default.
+            auto factory = globals().managedDataLoaderFactory;
+            mDataLoader = factory->onCreate(factory, &params.ndkDataLoaderParams(), this, this,
+                                            mJvm, mService, managedParams);
+            if (checkAndClearJavaException(__func__)) {
+                return false;
+            }
         }
-        if (!mDataLoader &&
-            !tryFactory(globals().managedDataLoaderFactory, /*withFeatures=*/false, params,
-                        managedParams)) {
-            return false;
-        }
+
         if (!mDataLoader) {
             return false;
         }
@@ -388,7 +338,7 @@
     }
     bool onStart() {
         CHECK(mDataLoader);
-        bool result = !mDataLoader->onStart || mDataLoader->onStart(mDataLoader);
+        bool result = mDataLoader->onStart(mDataLoader);
         if (checkAndClearJavaException(__func__)) {
             result = false;
         }
@@ -404,21 +354,26 @@
         std::lock_guard{mPendingReadsLooperBusy}; // NOLINT
         std::lock_guard{mLogLooperBusy}; // NOLINT
 
-        if (mDataLoader->onStop) {
-            mDataLoader->onStop(mDataLoader);
-        }
+        mDataLoader->onStop(mDataLoader);
+        checkAndClearJavaException(__func__);
+    }
+    void onDestroy() {
+        CHECK(mDataLoader);
+        mDataLoader->onDestroy(mDataLoader);
         checkAndClearJavaException(__func__);
     }
 
-    bool onPrepareImage(const android::dataloader::DataLoaderInstallationFiles& addedFiles) {
+    bool onPrepareImage(const DataLoaderInstallationFiles& addedFiles) {
         CHECK(mDataLoader);
-        bool result = !mDataLoader->onPrepareImage ||
+        bool result =
                 mDataLoader->onPrepareImage(mDataLoader, addedFiles.data(), addedFiles.size());
+        if (checkAndClearJavaException(__func__)) {
+            result = false;
+        }
         return result;
     }
 
-    template <class ReadInfoType>
-    int onPendingReadsLooperEvent(std::vector<ReadInfoType>& pendingReads) {
+    int onPendingReadsLooperEvent(std::vector<ReadInfo>& pendingReads) {
         CHECK(mDataLoader);
         std::lock_guard lock{mPendingReadsLooperBusy};
         while (mRunning.load(std::memory_order_relaxed)) {
@@ -428,23 +383,11 @@
                 pendingReads.empty()) {
                 return 1;
             }
-            if constexpr (std::is_same_v<ReadInfoType, ReadInfo>) {
-                if (mDataLoader->onPendingReads) {
-                    mDataLoader->onPendingReads(mDataLoader, pendingReads.data(),
-                                                pendingReads.size());
-                }
-            } else {
-                if (mDataLoader->onPendingReadsWithUid) {
-                    mDataLoader->onPendingReadsWithUid(mDataLoader, pendingReads.data(),
-                                                       pendingReads.size());
-                }
-            }
+            mDataLoader->onPendingReads(mDataLoader, pendingReads.data(), pendingReads.size());
         }
         return 1;
     }
-
-    template <class ReadInfoType>
-    int onLogLooperEvent(std::vector<ReadInfoType>& pageReads) {
+    int onLogLooperEvent(std::vector<ReadInfo>& pageReads) {
         CHECK(mDataLoader);
         std::lock_guard lock{mLogLooperBusy};
         while (mRunning.load(std::memory_order_relaxed)) {
@@ -454,40 +397,11 @@
                 pageReads.empty()) {
                 return 1;
             }
-            if constexpr (std::is_same_v<ReadInfoType, ReadInfo>) {
-                if (mDataLoader->onPageReads) {
-                    mDataLoader->onPageReads(mDataLoader, pageReads.data(), pageReads.size());
-                }
-            } else {
-                if (mDataLoader->onPageReadsWithUid) {
-                    mDataLoader->onPageReadsWithUid(mDataLoader, pageReads.data(),
-                                                    pageReads.size());
-                }
-            }
+            mDataLoader->onPageReads(mDataLoader, pageReads.data(), pageReads.size());
         }
         return 1;
     }
 
-    int onPendingReadsLooperEvent(std::vector<ReadInfo>& pendingReads,
-                                  std::vector<ReadInfoWithUid>& pendingReadsWithUid) {
-        CHECK(mDataLoader);
-        if (mDataLoaderFeatures & DATA_LOADER_FEATURE_UID) {
-            return this->onPendingReadsLooperEvent(pendingReadsWithUid);
-        } else {
-            return this->onPendingReadsLooperEvent(pendingReads);
-        }
-    }
-
-    int onLogLooperEvent(std::vector<ReadInfo>& pageReads,
-                         std::vector<ReadInfoWithUid>& pageReadsWithUid) {
-        CHECK(mDataLoader);
-        if (mDataLoaderFeatures & DATA_LOADER_FEATURE_UID) {
-            return this->onLogLooperEvent(pageReadsWithUid);
-        } else {
-            return this->onLogLooperEvent(pageReads);
-        }
-    }
-
     void writeData(jstring name, jlong offsetBytes, jlong lengthBytes, jobject incomingFd) const {
         CHECK(mCallbackControl);
         JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
@@ -500,7 +414,7 @@
         return android::incfs::openForSpecialOps(mControl, fid);
     }
 
-    int writeBlocks(android::dataloader::Span<const IncFsDataBlock> blocks) const {
+    int writeBlocks(Span<const IncFsDataBlock> blocks) const {
         return android::incfs::writeBlocks(blocks);
     }
 
@@ -525,28 +439,25 @@
     }
 
     bool reportStatus(DataLoaderStatus status) {
-        JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
-        const auto& jni = jniIds(env);
-
-        jint osStatus;
-        switch (status) {
-            case DATA_LOADER_UNAVAILABLE:
-                osStatus = jni.constants.DATA_LOADER_UNAVAILABLE;
-                break;
-            case DATA_LOADER_UNRECOVERABLE:
-                osStatus = jni.constants.DATA_LOADER_UNRECOVERABLE;
-                break;
-            default: {
-                ALOGE("Unable to report invalid status. status=%d", status);
-                return false;
-            }
+        if (status < DATA_LOADER_FIRST_STATUS || DATA_LOADER_LAST_STATUS < status) {
+            ALOGE("Unable to report invalid status. status=%d", status);
+            return false;
         }
-        return reportStatusViaCallback(env, mListener, mStorageId, osStatus);
+        JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
+        return reportStatusViaCallback(env, mListener, mStorageId, status);
     }
 
     bool checkAndClearJavaException(std::string_view method) const {
         JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
-        return ::checkAndClearJavaException(env, method);
+
+        if (!env->ExceptionCheck()) {
+            return false;
+        }
+
+        LOG(ERROR) << "Java exception during DataLoader::" << method;
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+        return true;
     }
 
     const UniqueControl& control() const { return mControl; }
@@ -563,7 +474,6 @@
     UniqueControl const mControl;
 
     ::DataLoader* mDataLoader = nullptr;
-    DataLoaderFeatures mDataLoaderFeatures = DATA_LOADER_FEATURE_NONE;
 
     std::mutex mPendingReadsLooperBusy;
     std::mutex mLogLooperBusy;
@@ -576,8 +486,7 @@
         return 0;
     }
     auto&& dataLoaderConnector = (DataLoaderConnector*)data;
-    return dataLoaderConnector->onPendingReadsLooperEvent(globals().pendingReads,
-                                                          globals().pendingReadsWithUid);
+    return dataLoaderConnector->onPendingReadsLooperEvent(globals().pendingReads);
 }
 
 static int onLogLooperEvent(int fd, int events, void* data) {
@@ -586,7 +495,7 @@
         return 0;
     }
     auto&& dataLoaderConnector = (DataLoaderConnector*)data;
-    return dataLoaderConnector->onLogLooperEvent(globals().pageReads, globals().pageReadsWithUid);
+    return dataLoaderConnector->onLogLooperEvent(globals().pageReads);
 }
 
 static int createFdFromManaged(JNIEnv* env, jobject pfd) {
@@ -619,10 +528,7 @@
     auto pr = createFdFromManaged(env,
                                   env->GetObjectField(managedIncControl, jni.controlPendingReads));
     auto log = createFdFromManaged(env, env->GetObjectField(managedIncControl, jni.controlLog));
-    auto blocksWritten =
-            createFdFromManaged(env,
-                                env->GetObjectField(managedIncControl, jni.controlBlocksWritten));
-    return android::incfs::createControl(cmd, pr, log, blocksWritten);
+    return android::incfs::createControl(cmd, pr, log);
 }
 
 DataLoaderParamsPair::DataLoaderParamsPair(android::dataloader::DataLoaderParams&& dataLoaderParams)
@@ -638,32 +544,31 @@
 
     const DataLoaderType type = (DataLoaderType)env->GetIntField(managedParams, jni.paramsType);
 
-    ScopedLocalRef<jstring> paramsPackageName(env,
-                                              GetStringField(env, managedParams,
-                                                             jni.paramsPackageName));
-    ScopedLocalRef<jstring> paramsClassName(env,
-                                            GetStringField(env, managedParams,
-                                                           jni.paramsClassName));
-    ScopedLocalRef<jstring> paramsArguments(env,
-                                            GetStringField(env, managedParams,
-                                                           jni.paramsArguments));
-    ScopedUtfChars package(env, paramsPackageName.get());
-    ScopedUtfChars className(env, paramsClassName.get());
-    ScopedUtfChars arguments(env, paramsArguments.get());
-    return DataLoaderParamsPair(android::dataloader::DataLoaderParams(type, package.c_str(),
-                                                                      className.c_str(),
-                                                                      arguments.c_str()));
+    std::string packageName(
+            env->GetStringUTFChars((jstring)env->GetObjectField(managedParams,
+                                                                jni.paramsPackageName),
+                                   nullptr));
+    std::string className(
+            env->GetStringUTFChars((jstring)env->GetObjectField(managedParams, jni.paramsClassName),
+                                   nullptr));
+    std::string arguments(
+            env->GetStringUTFChars((jstring)env->GetObjectField(managedParams, jni.paramsArguments),
+                                   nullptr));
+
+    return DataLoaderParamsPair(android::dataloader::DataLoaderParams(type, std::move(packageName),
+                                                                      std::move(className),
+                                                                      std::move(arguments)));
 }
 
 static void pendingReadsLooperThread() {
-    constexpr auto kTimeoutMsecs = -1;
+    constexpr auto kTimeoutMsecs = 60 * 1000;
     while (!globals().stopped) {
         pendingReadsLooper().pollAll(kTimeoutMsecs);
     }
 }
 
 static void logLooperThread() {
-    constexpr auto kTimeoutMsecs = -1;
+    constexpr auto kTimeoutMsecs = 60 * 1000;
     while (!globals().stopped) {
         logLooper().pollAll(kTimeoutMsecs);
     }
@@ -703,11 +608,6 @@
 
 void DataLoader_Initialize(struct ::DataLoaderFactory* factory) {
     CHECK(factory) << "DataLoader factory is invalid.";
-    globals().legacyDataLoaderFactory = factory;
-}
-
-void DataLoader_Initialize_WithFeatures(struct ::DataLoaderFactory* factory) {
-    CHECK(factory) << "DataLoader factory is invalid.";
     globals().dataLoaderFactory = factory;
 }
 
@@ -760,23 +660,15 @@
         }
     }
     auto nativeControl = createIncFsControlFromManaged(env, control);
-    if (nativeControl) {
-        using namespace android::incfs;
-        ALOGI("DataLoader::create incremental fds: %d/%d/%d/%d", nativeControl.cmd(),
-              nativeControl.pendingReads(), nativeControl.logs(), nativeControl.blocksWritten());
-        auto cmdPath = pathFromFd(nativeControl.cmd());
-        auto dir = path::dirName(cmdPath);
-        ALOGI("DataLoader::create incremental dir: %s, files: %s/%s/%s/%s",
-              details::c_str(dir).get(), details::c_str(path::baseName(cmdPath)).get(),
-              details::c_str(path::baseName(pathFromFd(nativeControl.pendingReads()))).get(),
-              details::c_str(path::baseName(pathFromFd(nativeControl.logs()))).get(),
-              details::c_str(path::baseName(pathFromFd(nativeControl.blocksWritten()))).get());
-    } else {
-        ALOGI("DataLoader::create no incremental control");
-    }
+    ALOGI("DataLoader::create1 cmd: %d|%s", nativeControl.cmd(),
+          pathFromFd(nativeControl.cmd()).c_str());
+    ALOGI("DataLoader::create1 pendingReads: %d|%s", nativeControl.pendingReads(),
+          pathFromFd(nativeControl.pendingReads()).c_str());
+    ALOGI("DataLoader::create1 log: %d|%s", nativeControl.logs(),
+          pathFromFd(nativeControl.logs()).c_str());
 
     auto nativeParams = DataLoaderParamsPair::createFromManaged(env, params);
-    ALOGI("DataLoader::create params: %d|%s|%s|%s", nativeParams.dataLoaderParams().type(),
+    ALOGI("DataLoader::create2: %d|%s|%s|%s", nativeParams.dataLoaderParams().type(),
           nativeParams.dataLoaderParams().packageName().c_str(),
           nativeParams.dataLoaderParams().className().c_str(),
           nativeParams.dataLoaderParams().arguments().c_str());
@@ -795,7 +687,6 @@
     auto dataLoaderConnector =
             std::make_unique<DataLoaderConnector>(env, service, storageId, std::move(nativeControl),
                                                   serviceConnector, callbackControl, listener);
-    bool created = dataLoaderConnector->onCreate(nativeParams, params);
     {
         std::lock_guard lock{globals().dataLoaderConnectorsLock};
         auto [dlIt, dlInserted] =
@@ -805,8 +696,7 @@
             ALOGE("id(%d): already exist, skipping creation.", storageId);
             return false;
         }
-
-        if (!created) {
+        if (!dlIt->second->onCreate(nativeParams, params)) {
             globals().dataLoaderConnectors.erase(dlIt);
             // Enable the reporter.
             reportUnavailableOnExit.reset(listener);
@@ -832,6 +722,8 @@
     std::unique_ptr<_jobject, decltype(destroyAndReportUnavailable)>
             destroyAndReportUnavailableOnExit(nullptr, destroyAndReportUnavailable);
 
+    const UniqueControl* control;
+    jobject listener;
     DataLoaderConnectorPtr dataLoaderConnector;
     {
         std::lock_guard lock{globals().dataLoaderConnectorsLock};
@@ -840,44 +732,41 @@
             ALOGE("Failed to start id(%d): not found", storageId);
             return false;
         }
-        dataLoaderConnector = dlIt->second;
-    }
-    const UniqueControl* control = &(dataLoaderConnector->control());
-    jobject listener = dataLoaderConnector->getListenerLocalRef(env);
 
-    if (!dataLoaderConnector->onStart()) {
-        ALOGE("Failed to start id(%d): onStart returned false", storageId);
-        destroyAndReportUnavailableOnExit.reset(listener);
-        return false;
+        listener = dlIt->second->getListenerLocalRef(env);
+
+        dataLoaderConnector = dlIt->second;
+        if (!dataLoaderConnector->onStart()) {
+            ALOGE("Failed to start id(%d): onStart returned false", storageId);
+            destroyAndReportUnavailableOnExit.reset(listener);
+            return false;
+        }
+
+        control = &(dataLoaderConnector->control());
+
+        // Create loopers while we are under lock.
+        if (control->pendingReads() >= 0 && !globals().pendingReadsLooperThread.joinable()) {
+            pendingReadsLooper();
+            globals().pendingReadsLooperThread = std::thread(&pendingReadsLooperThread);
+        }
+        if (control->logs() >= 0 && !globals().logLooperThread.joinable()) {
+            logLooper();
+            globals().logLooperThread = std::thread(&logLooperThread);
+        }
     }
 
     if (control->pendingReads() >= 0) {
-        auto&& looper = pendingReadsLooper();
-        if (!globals().pendingReadsLooperThread.joinable()) {
-            std::lock_guard lock{globals().dataLoaderConnectorsLock};
-            if (!globals().pendingReadsLooperThread.joinable()) {
-                globals().pendingReadsLooperThread = std::thread(&pendingReadsLooperThread);
-            }
-        }
-
-        looper.addFd(control->pendingReads(), android::Looper::POLL_CALLBACK,
-                     android::Looper::EVENT_INPUT, &onPendingReadsLooperEvent,
-                     dataLoaderConnector.get());
-        looper.wake();
+        pendingReadsLooper().addFd(control->pendingReads(), android::Looper::POLL_CALLBACK,
+                                   android::Looper::EVENT_INPUT, &onPendingReadsLooperEvent,
+                                   dataLoaderConnector.get());
+        pendingReadsLooper().wake();
     }
 
     if (control->logs() >= 0) {
-        auto&& looper = logLooper();
-        if (!globals().logLooperThread.joinable()) {
-            std::lock_guard lock{globals().dataLoaderConnectorsLock};
-            if (!globals().logLooperThread.joinable()) {
-                globals().logLooperThread = std::thread(&logLooperThread);
-            }
-        }
-
-        looper.addFd(control->logs(), android::Looper::POLL_CALLBACK, android::Looper::EVENT_INPUT,
-                     &onLogLooperEvent, dataLoaderConnector.get());
-        looper.wake();
+        logLooper().addFd(control->logs(), android::Looper::POLL_CALLBACK,
+                          android::Looper::EVENT_INPUT, &onLogLooperEvent,
+                          dataLoaderConnector.get());
+        logLooper().wake();
     }
 
     const auto& jni = jniIds(env);
@@ -886,8 +775,17 @@
     return true;
 }
 
-static void DataLoaderService_OnStop_NoStatus(const UniqueControl* control,
-                                              const DataLoaderConnectorPtr& dataLoaderConnector) {
+jobject DataLoaderService_OnStop_NoStatus(JNIEnv* env, jint storageId) {
+    const UniqueControl* control;
+    {
+        std::lock_guard lock{globals().dataLoaderConnectorsLock};
+        auto dlIt = globals().dataLoaderConnectors.find(storageId);
+        if (dlIt == globals().dataLoaderConnectors.end()) {
+            return nullptr;
+        }
+        control = &(dlIt->second->control());
+    }
+
     if (control->pendingReads() >= 0) {
         pendingReadsLooper().removeFd(control->pendingReads());
         pendingReadsLooper().wake();
@@ -896,25 +794,30 @@
         logLooper().removeFd(control->logs());
         logLooper().wake();
     }
-    dataLoaderConnector->onStop();
-}
 
-bool DataLoaderService_OnStop(JNIEnv* env, jint storageId) {
-    DataLoaderConnectorPtr dataLoaderConnector;
+    jobject listener = nullptr;
     {
         std::lock_guard lock{globals().dataLoaderConnectorsLock};
         auto dlIt = globals().dataLoaderConnectors.find(storageId);
         if (dlIt == globals().dataLoaderConnectors.end()) {
             ALOGI("Failed to stop id(%d): not found", storageId);
-            return true;
+            return nullptr;
         }
-        dataLoaderConnector = dlIt->second;
-    }
-    const UniqueControl* control = &(dataLoaderConnector->control());
-    jobject listener = dataLoaderConnector->getListenerLocalRef(env);
 
-    // Just stop.
-    DataLoaderService_OnStop_NoStatus(control, dataLoaderConnector);
+        listener = dlIt->second->getListenerLocalRef(env);
+
+        auto&& dataLoaderConnector = dlIt->second;
+        dataLoaderConnector->onStop();
+    }
+    return listener;
+}
+
+bool DataLoaderService_OnStop(JNIEnv* env, jint storageId) {
+    auto listener = DataLoaderService_OnStop_NoStatus(env, storageId);
+    if (listener == nullptr) {
+        ALOGI("Failed to stop id(%d): not found", storageId);
+        return true;
+    }
 
     const auto& jni = jniIds(env);
     reportStatusViaCallback(env, listener, storageId, jni.constants.DATA_LOADER_STOPPED);
@@ -922,26 +825,36 @@
     return true;
 }
 
-bool DataLoaderService_OnDestroy(JNIEnv* env, jint storageId) {
-    DataLoaderConnectorPtr dataLoaderConnector;
+jobject DataLoaderService_OnDestroy_NoStatus(JNIEnv* env, jint storageId) {
+    jobject listener = DataLoaderService_OnStop_NoStatus(env, storageId);
+    if (!listener) {
+        return nullptr;
+    }
+
     {
         std::lock_guard lock{globals().dataLoaderConnectorsLock};
         auto dlIt = globals().dataLoaderConnectors.find(storageId);
         if (dlIt == globals().dataLoaderConnectors.end()) {
-            ALOGI("Failed to destroy id(%d): not found", storageId);
-            return true;
+            return nullptr;
         }
-        dataLoaderConnector = std::move(dlIt->second);
+
+        auto&& dataLoaderConnector = dlIt->second;
+        dataLoaderConnector->onDestroy();
         globals().dataLoaderConnectors.erase(dlIt);
     }
-    const UniqueControl* control = &(dataLoaderConnector->control());
 
-    // Stop/destroy.
-    DataLoaderService_OnStop_NoStatus(control, dataLoaderConnector);
-    // This will destroy the last instance of the DataLoaderConnectorPtr and should trigger the
-    // destruction of the DataLoader. However if there are any hanging instances, the destruction
-    // will be postponed. E.g. OnPrepareImage in progress at the same time we call OnDestroy.
-    dataLoaderConnector = {};
+    return listener;
+}
+
+bool DataLoaderService_OnDestroy(JNIEnv* env, jint storageId) {
+    jobject listener = DataLoaderService_OnDestroy_NoStatus(env, storageId);
+    if (!listener) {
+        ALOGI("Failed to remove id(%d): not found", storageId);
+        return true;
+    }
+
+    const auto& jni = jniIds(env);
+    reportStatusViaCallback(env, listener, storageId, jni.constants.DATA_LOADER_DESTROYED);
 
     return true;
 }
@@ -972,22 +885,23 @@
     files.reserve(size);
 
     for (int i = 0; i < size; ++i) {
-        ScopedLocalRef<jobject> jfile(env, env->GetObjectArrayElement(jfiles, i));
+        jobject jfile = env->GetObjectArrayElement(jfiles, i);
 
         DataLoaderLocation location =
-                (DataLoaderLocation)env->GetIntField(jfile.get(), jni.installationFileLocation);
-        ScopedUtfChars name(env, GetStringField(env, jfile.get(), jni.installationFileName));
-        IncFsSize size = env->GetLongField(jfile.get(), jni.installationFileLengthBytes);
+                (DataLoaderLocation)env->GetIntField(jfile, jni.installationFileLocation);
+        std::string name =
+                env->GetStringUTFChars((jstring)env->GetObjectField(jfile,
+                                                                    jni.installationFileName),
+                                       nullptr);
+        IncFsSize size = env->GetLongField(jfile, jni.installationFileLengthBytes);
 
-        ScopedLocalRef<jbyteArray> jmetadataBytes(env,
-                                                  GetByteArrayField(env, jfile.get(),
-                                                                    jni.installationFileMetadata));
-        auto metadataElements = env->GetByteArrayElements(jmetadataBytes.get(), nullptr);
-        auto metadataLength = env->GetArrayLength(jmetadataBytes.get());
+        auto jmetadataBytes = (jbyteArray)env->GetObjectField(jfile, jni.installationFileMetadata);
+        auto metadataElements = env->GetByteArrayElements(jmetadataBytes, nullptr);
+        auto metadataLength = env->GetArrayLength(jmetadataBytes);
         RawMetadata metadata(metadataElements, metadataElements + metadataLength);
-        env->ReleaseByteArrayElements(jmetadataBytes.get(), metadataElements, 0);
+        env->ReleaseByteArrayElements(jmetadataBytes, metadataElements, 0);
 
-        files.emplace_back(location, name.c_str(), size, std::move(metadata));
+        files.emplace_back(location, std::move(name), size, std::move(metadata));
     }
 
     return DataLoaderInstallationFilesPair(std::move(files));
@@ -1011,6 +925,7 @@
 
 bool DataLoaderService_OnPrepareImage(JNIEnv* env, jint storageId, jobjectArray addedFiles,
                                       jobjectArray removedFiles) {
+    jobject listener;
     DataLoaderConnectorPtr dataLoaderConnector;
     {
         std::lock_guard lock{globals().dataLoaderConnectorsLock};
@@ -1019,20 +934,14 @@
             ALOGE("Failed to handle onPrepareImage for id(%d): not found", storageId);
             return false;
         }
+        listener = dlIt->second->getListenerLocalRef(env);
         dataLoaderConnector = dlIt->second;
     }
-    jobject listener = dataLoaderConnector->getListenerLocalRef(env);
 
     auto addedFilesPair = DataLoaderInstallationFilesPair::createFromManaged(env, addedFiles);
     bool result = dataLoaderConnector->onPrepareImage(addedFilesPair.ndkFiles());
 
     const auto& jni = jniIds(env);
-
-    if (checkAndClearJavaException(env, "onPrepareImage")) {
-        reportStatusViaCallback(env, listener, storageId, jni.constants.DATA_LOADER_UNAVAILABLE);
-        return false;
-    }
-
     reportStatusViaCallback(env, listener, storageId,
                             result ? jni.constants.DATA_LOADER_IMAGE_READY
                                    : jni.constants.DATA_LOADER_IMAGE_NOT_READY);
diff --git a/libdataloader/JNIHelpers.h b/libdataloader/JNIHelpers.h
index c35a669..f884eca 100644
--- a/libdataloader/JNIHelpers.h
+++ b/libdataloader/JNIHelpers.h
@@ -59,14 +59,6 @@
     return env->GetStaticIntField(clazz, res);
 }
 
-static inline jstring GetStringField(JNIEnv* env, jobject obj, jfieldID field) {
-    return reinterpret_cast<jstring>(env->GetObjectField(obj, field));
-}
-
-static inline jbyteArray GetByteArrayField(JNIEnv* env, jobject obj, jfieldID field) {
-    return reinterpret_cast<jbyteArray>(env->GetObjectField(obj, field));
-}
-
 static inline JNIEnv* GetJNIEnvironment(JavaVM* vm) {
     JNIEnv* env;
     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
diff --git a/libdataloader/ManagedDataLoader.cpp b/libdataloader/ManagedDataLoader.cpp
index c277d45..8f3e888 100644
--- a/libdataloader/ManagedDataLoader.cpp
+++ b/libdataloader/ManagedDataLoader.cpp
@@ -91,32 +91,18 @@
 
 } // namespace
 
-ManagedDataLoader::ManagedDataLoader(JavaVM* jvm, jobject dataLoader)
-      : mJvm(jvm), mDataLoader(dataLoader) {
+ManagedDataLoader::ManagedDataLoader(JavaVM* jvm) : mJvm(jvm) {
     CHECK(mJvm);
-
-    LegacyDataLoader::onStart = [](auto) -> bool { return true; };
-    LegacyDataLoader::onStop = [](auto) {};
-    LegacyDataLoader::onDestroy = [](LegacyDataLoader* self) {
-        auto me = static_cast<ManagedDataLoader*>(self);
-        me->onDestroy();
-        delete me;
-    };
-    LegacyDataLoader::onPrepareImage = [](auto* self, const auto addedFiles[],
-                                          int addedFilesCount) -> bool {
-        return static_cast<ManagedDataLoader*>(self)->onPrepareImage(
-                DataLoaderInstallationFiles(addedFiles, addedFilesCount));
-    };
-    LegacyDataLoader::onPendingReads = [](auto, auto, auto) {};
-    LegacyDataLoader::onPageReads = [](auto, auto, auto) {};
 }
 
-LegacyDataLoader* ManagedDataLoader::create(JavaVM* jvm,
-                                            android::dataloader::FilesystemConnectorPtr ifs,
-                                            android::dataloader::StatusListenerPtr listener,
-                                            android::dataloader::ServiceConnectorPtr service,
-                                            android::dataloader::ServiceParamsPtr params) {
-    JNIEnv* env = GetJNIEnvironment(jvm);
+bool ManagedDataLoader::onCreate(const android::dataloader::DataLoaderParams&,
+                                 android::dataloader::FilesystemConnectorPtr ifs,
+                                 android::dataloader::StatusListenerPtr listener,
+                                 android::dataloader::ServiceConnectorPtr service,
+                                 android::dataloader::ServiceParamsPtr params) {
+    CHECK(!mDataLoader);
+
+    JNIEnv* env = GetJNIEnvironment(mJvm);
     const auto& jni = jniIds(env);
 
     jobject dlp = env->NewObject(jni.dataLoaderParams, jni.dataLoaderParamsConstruct, params);
@@ -126,16 +112,14 @@
     auto dataLoader = env->CallObjectMethod(service, jni.dataLoaderServiceOnCreateDataLoader, dlp);
     if (!dataLoader) {
         LOG(ERROR) << "Failed to create Java DataLoader.";
-        return nullptr;
+        return false;
     }
     if (env->ExceptionCheck()) {
-        return nullptr;
-    }
-    if (!env->CallBooleanMethod(dataLoader, jni.dataLoaderOnCreate, dlp, ifsc)) {
-        return nullptr;
+        return false;
     }
 
-    return new ManagedDataLoader(jvm, env->NewGlobalRef(dataLoader));
+    mDataLoader = env->NewGlobalRef(dataLoader);
+    return env->CallBooleanMethod(mDataLoader, jni.dataLoaderOnCreate, dlp, ifsc);
 }
 
 void ManagedDataLoader::onDestroy() {
@@ -179,18 +163,4 @@
     return env->CallBooleanMethod(mDataLoader, jni.dataLoaderOnPrepareImage, jaddedFiles, nullptr);
 }
 
-ManagedDataLoaderFactory::ManagedDataLoaderFactory() {
-    ::DataLoaderFactory::onCreate =
-            [](::DataLoaderFactory* self, const ::DataLoaderParams* ndkParams,
-               ::DataLoaderFilesystemConnectorPtr fsConnector,
-               ::DataLoaderStatusListenerPtr statusListener, ::DataLoaderServiceVmPtr vm,
-               ::DataLoaderServiceConnectorPtr serviceConnector,
-               ::DataLoaderServiceParamsPtr serviceParams) -> ::DataLoader* {
-        return reinterpret_cast<::DataLoader*>(
-                ManagedDataLoader::create(vm, static_cast<FilesystemConnector*>(fsConnector),
-                                          static_cast<StatusListener*>(statusListener),
-                                          serviceConnector, serviceParams));
-    };
-}
-
 } // namespace android::dataloader
diff --git a/libdataloader/ManagedDataLoader.h b/libdataloader/ManagedDataLoader.h
index b9f714f..33d00c6 100644
--- a/libdataloader/ManagedDataLoader.h
+++ b/libdataloader/ManagedDataLoader.h
@@ -17,50 +17,30 @@
 
 #include <dataloader.h>
 
-__BEGIN_DECLS
-
-// This simulates legacy dataloader (compiled with previous version of libincfs_dataloader).
-// We still need to be able to support them.
-struct LegacyDataLoader {
-    bool (*onStart)(struct LegacyDataLoader* self);
-    void (*onStop)(struct LegacyDataLoader* self);
-    void (*onDestroy)(struct LegacyDataLoader* self);
-
-    bool (*onPrepareImage)(struct LegacyDataLoader* self,
-                           const DataLoaderInstallationFile addedFiles[], int addedFilesCount);
-
-    void (*onPendingReads)(struct LegacyDataLoader* self, const IncFsReadInfo pendingReads[],
-                           int pendingReadsCount);
-    void (*onPageReads)(struct LegacyDataLoader* self, const IncFsReadInfo pageReads[],
-                        int pageReadsCount);
-};
-
-__END_DECLS
-
 namespace android::dataloader {
 
 // Default DataLoader redirects everything back to Java.
-struct ManagedDataLoader : private LegacyDataLoader {
-    static LegacyDataLoader* create(JavaVM* jvm, android::dataloader::FilesystemConnectorPtr ifs,
-                                    android::dataloader::StatusListenerPtr listener,
-                                    android::dataloader::ServiceConnectorPtr service,
-                                    android::dataloader::ServiceParamsPtr params);
+struct ManagedDataLoader : public DataLoader {
+    ManagedDataLoader(JavaVM* jvm);
 
 private:
-    ManagedDataLoader(JavaVM* jvm, jobject dataLoader);
-
     // Lifecycle.
-    void onDestroy();
+    bool onCreate(const android::dataloader::DataLoaderParams&,
+                  android::dataloader::FilesystemConnectorPtr ifs,
+                  android::dataloader::StatusListenerPtr listener,
+                  android::dataloader::ServiceConnectorPtr service,
+                  android::dataloader::ServiceParamsPtr params) final;
+    bool onStart() final { return true; }
+    void onStop() final {}
+    void onDestroy() final;
 
-    // Installation.
-    bool onPrepareImage(DataLoaderInstallationFiles addedFiles);
+    bool onPrepareImage(DataLoaderInstallationFiles addedFiles) final;
+
+    void onPendingReads(PendingReads pendingReads) final {}
+    void onPageReads(PageReads pageReads) final {}
 
     JavaVM* const mJvm;
     jobject mDataLoader = nullptr;
 };
 
-struct ManagedDataLoaderFactory : public ::DataLoaderFactory {
-    ManagedDataLoaderFactory();
-};
-
 } // namespace android::dataloader
diff --git a/libdataloader/include/dataloader.h b/libdataloader/include/dataloader.h
index 2cfd9ff..a46167d 100644
--- a/libdataloader/include/dataloader.h
+++ b/libdataloader/include/dataloader.h
@@ -36,9 +36,7 @@
 struct StatusListener;
 
 using FileId = IncFsFileId;
-using Uid = IncFsUid;
 using ReadInfo = IncFsReadInfo;
-using ReadInfoWithUid = IncFsReadInfoWithUid;
 using DataBlock = IncFsDataBlock;
 
 using FilesystemConnectorPtr = FilesystemConnector*;
@@ -49,9 +47,7 @@
 using DataLoaderPtr = std::unique_ptr<DataLoader>;
 using DataLoaderInstallationFiles = Span<const ::DataLoaderInstallationFile>;
 using PendingReads = Span<const ReadInfo>;
-using PendingReadsWithUid = Span<const ReadInfoWithUid>;
 using PageReads = Span<const ReadInfo>;
-using PageReadsWithUid = Span<const ReadInfoWithUid>;
 using RawMetadata = std::vector<char>;
 using DataBlocks = Span<const DataBlock>;
 
@@ -63,9 +59,6 @@
 
     virtual ~DataLoader() {}
 
-    // Bitmask of supported features.
-    virtual DataLoaderFeatures getFeatures() const = 0;
-
     // Lifecycle.
     virtual bool onCreate(const DataLoaderParams&, FilesystemConnectorPtr, StatusListenerPtr,
                           ServiceConnectorPtr, ServiceParamsPtr) = 0;
@@ -79,9 +72,6 @@
     // IFS callbacks.
     virtual void onPendingReads(PendingReads pendingReads) = 0;
     virtual void onPageReads(PageReads pageReads) = 0;
-
-    virtual void onPendingReadsWithUid(PageReadsWithUid pendingReads) = 0;
-    virtual void onPageReadsWithUid(PendingReadsWithUid pageReads) = 0;
 };
 
 struct DataLoaderParams {
diff --git a/libdataloader/include/dataloader_inline.h b/libdataloader/include/dataloader_inline.h
index 10a5c46..26da530 100644
--- a/libdataloader/include/dataloader_inline.h
+++ b/libdataloader/include/dataloader_inline.h
@@ -22,9 +22,6 @@
 
 struct DataLoaderImpl : public ::DataLoader {
     DataLoaderImpl(DataLoaderPtr&& dataLoader) : mDataLoader(std::move(dataLoader)) {
-        getFeatures = [](DataLoader* self) -> DataLoaderFeatures {
-            return static_cast<DataLoaderImpl*>(self)->mDataLoader->getFeatures();
-        };
         onStart = [](DataLoader* self) -> bool {
             return static_cast<DataLoaderImpl*>(self)->mDataLoader->onStart();
         };
@@ -50,16 +47,6 @@
             return static_cast<DataLoaderImpl*>(self)->mDataLoader->onPageReads(
                     PageReads(pageReads, pageReadsCount));
         };
-        onPendingReadsWithUid = [](DataLoader* self, const IncFsReadInfoWithUid pendingReads[],
-                                   int pendingReadsCount) {
-            return static_cast<DataLoaderImpl*>(self)->mDataLoader->onPendingReadsWithUid(
-                    PendingReadsWithUid(pendingReads, pendingReadsCount));
-        };
-        onPageReadsWithUid = [](DataLoader* self, const IncFsReadInfoWithUid pageReads[],
-                                int pageReadsCount) {
-            return static_cast<DataLoaderImpl*>(self)->mDataLoader->onPageReadsWithUid(
-                    PageReadsWithUid(pageReads, pageReadsCount));
-        };
     }
 
 private:
@@ -112,7 +99,7 @@
 } // namespace details
 
 inline void DataLoader::initialize(DataLoader::Factory&& factory) {
-    DataLoader_Initialize_WithFeatures(new details::DataLoaderFactoryImpl(std::move(factory)));
+    DataLoader_Initialize(new details::DataLoaderFactoryImpl(std::move(factory)));
 }
 
 inline DataLoaderParams::DataLoaderParams(DataLoaderType type, std::string&& packageName,
diff --git a/libdataloader/include/dataloader_ndk.h b/libdataloader/include/dataloader_ndk.h
index 14dc3df..67013ec 100644
--- a/libdataloader/include/dataloader_ndk.h
+++ b/libdataloader/include/dataloader_ndk.h
@@ -24,9 +24,12 @@
 
 #define DATALOADER_LIBRARY_NAME "libdataloader.so"
 
+// Keep in sync with IDataLoaderStatusListener.aidl
 typedef enum {
-    DATA_LOADER_UNAVAILABLE = 7,
     DATA_LOADER_UNRECOVERABLE = 8,
+
+    DATA_LOADER_FIRST_STATUS = DATA_LOADER_UNRECOVERABLE,
+    DATA_LOADER_LAST_STATUS = DATA_LOADER_UNRECOVERABLE,
 } DataLoaderStatus;
 
 typedef enum {
@@ -41,11 +44,6 @@
     DATA_LOADER_LOCATION_MEDIA_DATA = 2,
 } DataLoaderLocation;
 
-typedef enum {
-    DATA_LOADER_FEATURE_NONE = 0,
-    DATA_LOADER_FEATURE_UID = 1 << 0,
-} DataLoaderFeatures;
-
 struct DataLoaderParams {
     int type;
     const char* packageName;
@@ -83,7 +81,6 @@
 typedef jobject DataLoaderServiceParamsPtr;
 
 struct DataLoader {
-    // DataLoader v1.
     bool (*onStart)(struct DataLoader* self);
     void (*onStop)(struct DataLoader* self);
     void (*onDestroy)(struct DataLoader* self);
@@ -95,15 +92,6 @@
                            int pendingReadsCount);
     void (*onPageReads)(struct DataLoader* self, const IncFsReadInfo pageReads[],
                         int pageReadsCount);
-
-    // DataLoader v2, with features.
-    // Use DataLoader_Initialize_WithFeatures to set a factory for v2 DataLoader.
-    DataLoaderFeatures (*getFeatures)(struct DataLoader* self);
-
-    void (*onPendingReadsWithUid)(struct DataLoader* self,
-                                  const IncFsReadInfoWithUid pendingReads[], int pendingReadsCount);
-    void (*onPageReadsWithUid)(struct DataLoader* self, const IncFsReadInfoWithUid pageReads[],
-                               int pageReadsCount);
 };
 
 struct DataLoaderFactory {
@@ -113,7 +101,6 @@
                                    DataLoaderServiceParamsPtr);
 };
 void DataLoader_Initialize(struct DataLoaderFactory*);
-void DataLoader_Initialize_WithFeatures(struct DataLoaderFactory*);
 
 void DataLoader_FilesystemConnector_writeData(DataLoaderFilesystemConnectorPtr, jstring name,
                                               jlong offsetBytes, jlong lengthBytes,
diff --git a/sysprop/Android.bp b/sysprop/Android.bp
index 59ba604..5d7c86b 100644
--- a/sysprop/Android.bp
+++ b/sysprop/Android.bp
@@ -1,7 +1,3 @@
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
 sysprop_library {
     name: "com.android.sysprop.incremental",
     srcs: ["IncrementalProperties.sysprop"],
diff --git a/sysprop/api/com.android.sysprop.incremental-current.txt b/sysprop/api/com.android.sysprop.incremental-current.txt
index e69de29..998da9e 100644
--- a/sysprop/api/com.android.sysprop.incremental-current.txt
+++ b/sysprop/api/com.android.sysprop.incremental-current.txt
@@ -0,0 +1,9 @@
+props {
+  module: "android.sysprop.IncrementalProperties"
+  prop {
+    api_name: "enable"
+    type: String
+    scope: Internal
+    prop_name: "ro.incremental.enable"
+  }
+}