Snap for 8564071 from e5995fe2b5b7deadcd060be4947b09d4470ae328 to mainline-os-statsd-release

Change-Id: I09413e996752f730f5398473291c3406d1fd4113
diff --git a/Android.bp b/Android.bp
deleted file mode 100644
index 736bc40..0000000
--- a/Android.bp
+++ /dev/null
@@ -1,741 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-filegroup {
-    name: "iorap-aidl",
-    srcs: [
-        // note: using **/* doesn't work, so list each file one by one:
-        // see also b/70046217
-
-        // note: list only 'interface' aidl files, otherwise
-        // aidl generates an error "Refusing to generate code with unstructured parcelables."
-        "binder/com/google/android/startop/iorap/IIorap.aidl",
-        "binder/com/google/android/startop/iorap/ITaskListener.aidl",
-    ],
-    path: "binder",
-}
-
-cc_defaults {
-    name: "iorap-default-flags",
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wextra",
-        "-Wno-missing-field-initializers",
-        "-Wno-unused-parameter",
-        "-Wno-unused-variable",
-    ],
-
-    local_include_dirs: [
-        "include",
-        "src",
-    ],
-    // TODO: shouldn't need this but there's a soong/cmake generator bug.
-    export_include_dirs: [
-        "include",
-        "src",
-    ],
-
-    /*
-    TODO: Header refactoring cleanup:
-
-    Option 1): Move src/$component/file_name.h to src/$component/include/$component/file_name.h
-    Option 2): Symlink src/$component/include/$component to src/$component
-
-    Set export_include_dirs to '$component/include' for that component.
-
-    Also delete the 'include' directory unless we have code other non-iorap
-    targets are allowed to reference.
-    */
-
-    clang: true,
-    static_libs: ["libc++fs"],
-    shared_libs: ["libbase"],
-
-    // build all ioraps for host.
-    host_supported: true,
-    target: {
-        darwin: {
-            enabled: false,
-        }
-    },
-}
-
-cc_defaults {
-    name: "iorap-default-dependencies",
-
-    static_libs: [
-        "libiorap-binder",
-        "libplatformprotos",  // android framework C++ protos.
-    ],
-    shared_libs: [
-        "libbinder",
-        "libutils",
-        "libcutils", // tracing.
-
-        "libfruit",  // dependency injection.
-        // TODO: remove these annoying dependencies by hiding them in the main library code.
-
-        // dependency for libplatformprotos
-        // "libprotobuf-cpp-lite",
-
-        // libplatformprotos has an indirect dependency on full, causing compilation/linking
-        // errors if we use lite
-        "libprotobuf-cpp-full",
-
-        // phenotype flags support
-        "server_configurable_flags",
-    ],
-
-    // srcs: [":libprotobuf-internal-protos"],
-    // commented out because it causes compilation errors
-    // TODO: can we use the lite library somehow?
-
-    header_libs: ["librxcpp"],
-}
-
-cc_library_static {
-    name: "libiorap-binder",
-    defaults: ["iorap-default-flags"],
-
-    srcs: [
-        ":iorap-aidl",
-        "src/binder/iiorap_impl.cc",
-        "src/binder/package_change_observer.cc",
-        "src/binder/package_manager_remote.cc",
-        "src/binder/package_version_map.cc",
-    ],
-    shared_libs: [
-        "libbinder",
-        "libutils",
-        "libcutils", // tracing.
-    ],
-    aidl: {
-        local_include_dirs: ["binder"],
-        include_dirs: ["frameworks/native/aidl/binder"],
-        export_aidl_headers: true,
-    },
-
-    static_libs: [
-       "libplatformprotos",  // android framework C++ protos.
-    ],
-}
-
-cc_defaults {
-    name: "libiorap-manager-default-dependencies",
-    static_libs: [
-        "libiorap-binder",
-        "libiorap-perfetto",
-        "libiorap-prefetcher",
-        "libiorap-db",
-        "libiorap-maintenance",
-    ],
-    defaults: [
-        "libiorap-perfetto-default-dependencies",
-        "libiorap-prefetcher-default-dependencies",
-        "libiorap-db-default-dependencies",
-    ],
-    // Users of 'libiorap-manager' also need to include these defaults to avoid
-    // linking errors.
-}
-
-cc_library_static {
-    name: "libiorap-manager",
-    defaults: [
-        "iorap-default-flags",
-        "iorap-default-dependencies",
-        "libiorap-manager-default-dependencies",
-    ],
-
-    srcs: [
-        "src/manager/**/*.cc",
-    ],
-}
-
-cc_binary {
-    name: "iorapd",
-    defaults: [
-        "iorap-default-flags",
-        "iorap-default-dependencies",
-        "libiorap-manager-default-dependencies",
-    ],
-    srcs: [
-        "src/iorapd/main.cc",
-    ],
-    static_libs: [
-        "libiorap-manager",
-    ],
-    init_rc: [
-        "iorapd.rc",
-    ],
-    // iorapd fork+execs into iorap.prefetcherd and iorap.cmd.compiler
-    // maintenance used by tests
-    required: [
-        "iorap.cmd.compiler",
-        "iorap.prefetcherd",
-        "iorap.cmd.maintenance",
-    ],
-}
-
-cc_library_static {
-    name: "libiorap-inode2filename",
-    defaults: [
-        "iorap-default-flags",
-        "iorap-default-dependencies",
-    ],
-
-    srcs: [
-        "src/inode2filename/**/*.cc",
-    ],
-}
-
-cc_binary {
-  name: "iorap.inode2filename",
-  defaults: [
-      "iorap-default-flags",
-      "iorap-default-dependencies",
-  ],
-  srcs: [
-      "src/inode2filename/**/*.cc",
-  ],
-  // Easier debugging. TODO: make a separate debug config.
-  // XX: Using -O0 seems to completely hide some errors.
-  cflags: ["-O2", "-UNDEBUG", "-DIORAP_INODE2FILENAME_MAIN=1"],
-  sanitize: {
-    undefined: true,
-    all_undefined: true,
-    // Pretty print when ubsan detects a problem.
-    // Otherwise it just calls abort().
-
-/*
-    diag: {
-      undefined: true,
-    },
-    */ // don't use the diag when you want it to crash.
-  },
-}
-
-cc_test {
-    name: "iorapd-tests",
-    test_suites: ["device-tests"],
-    gtest: false,  // we use gtest *and* gmock.
-    defaults: [
-        "iorap-default-flags",
-        "iorap-default-dependencies",
-        "libiorap-compiler-default-dependencies",
-    ],
-    srcs: [
-        "tests/src/binder/*.cc",
-        "tests/src/inode2filename/*.cc",
-        "tests/src/log/*.cc",
-        "tests/src/tmp/*.cc",
-    ],
-    data: [
-        "tests/src/compiler/testdata/*",
-    ],
-    cflags: ["-O2", "-UNDEBUG"],
-
-    // TODO:  we should probably have per-component tests.
-    static_libs: ["libgmock_main", "libgmock", "libgtest", "libiorap-inode2filename"],
-
-}
-
-
-cc_test_host {
-    name: "iorapd-host-tests",
-    gtest: false,  // we use gtest *and* gmock.
-    target: {
-        darwin: {
-            enabled: false,
-        }
-    },
-    defaults: [
-        "iorap-default-flags",
-        "iorap-default-dependencies",
-        "libiorap-compiler-default-dependencies",
-        "libiorap-maintenance-default-dependencies",
-    ],
-    srcs: [
-        "tests/src/compiler/*.cc",
-        "tests/src/db/*.cc",
-        "tests/src/maintenance/*.cc",
-    ],
-    data: [
-        "tests/src/compiler/testdata/*",
-        "tests/src/maintenance/testdata/*",
-    ],
-    cflags: ["-O2", "-UNDEBUG"],
-
-    // TODO:  we should probably have per-component tests.
-    static_libs: [
-    "libgmock_main",
-    "libgmock",
-    "libgtest",
-    "libiorap-compiler",
-    "libiorap-maintenance",
-    ],
-}
-
-filegroup {
-  name: "libiorap-perfetto-protos",
-  srcs: [
-  ],
-}
-
-// Static libraries cannot export their dependencies,
-// the current convention is to use an extra 'defaults' rule for statics
-// to bring in all the dependencies.
-cc_defaults {
-    name: "libiorap-perfetto-default-dependencies",
-
-    // Some of the libperfetto header typedefs leak out into iorap.
-    // Avoids compilation #include errors.
-    // TODO: clean this up, the headers should not leak out (maybe all we need is a PerfettoConsumer
-    // forward declaration?).
-    include_dirs: ["external/perfetto/include"],
-    // Various perfetto protos are used directly by iorap.
-    //
-    // Furthermore, we need this regardless to avoid linking errors when linking
-    // libiorap-perfetto.a into the main cc_binary rule.
-    static_libs: [
-        "perfetto_trace_protos",
-    ],
-
-    shared_libs: [
-        // Not part of true dependencies: Users of 'libiorap-perfetto' do not link against
-        // libperfetto.
-        // We only put this to avoid linking errors when building iorapd.
-        // TODO: can we split iorapd into libiorapd-main that doesn't link against libperfetto?
-        // only the last cc_binary should need the full transitive closure of the dependency graph.
-        "libperfetto",
-    ]
-}
-
-cc_library_static {
-    name: "libiorap-perfetto",
-    defaults: [
-        "iorap-default-flags",
-        "iorap-default-dependencies",
-        "libiorap-perfetto-default-dependencies",
-    ],
-
-    srcs: [
-        "src/perfetto/**/*.cc",
-    ],
-}
-
-cc_binary {
-  name: "iorap.cmd.perfetto",
-  defaults: [
-      "iorap-default-flags",
-      "iorap-default-dependencies",
-  ],
-  shared_libs: ["libperfetto"],
-  include_dirs: ["external/perfetto/include"],
-  srcs: [
-      "src/perfetto/**/*.cc",
-  ],
-  // Easier debugging. TODO: make a separate debug config.
-  // XX: Using -O0 seems to completely hide some errors.
-  cflags: ["-O2", "-UNDEBUG", "-DIORAP_PERFETTO_MAIN=1"],
-  sanitize: {
-    undefined: true,
-    all_undefined: true,
-    // Pretty print when ubsan detects a problem.
-    // Otherwise it just calls abort().
-
-/*
-    diag: {
-      undefined: true,
-    },
-    */ // don't use the diag when you want it to crash.
-  },
-
-  static_libs: [
-    "perfetto_trace_protos",
-  ],
-}
-
-// Static libraries cannot export their dependencies,
-// the current convention is to use an extra 'defaults' rule for statics
-// to bring in all the dependencies.
-cc_defaults {
-    name: "libiorap-compiler-default-dependencies",
-
-    defaults: [
-        // use the perfetto namespace
-        "libiorap-perfetto-default-dependencies",
-        // use the inode2filename namespace
-        "libiorap-serialize-default-dependencies",  // uses but does not re-export serialize.
-    ],
-
-    // Some of the libperfetto header typedefs leak out into iorap.
-    // Avoids compilation #include errors.
-    // TODO: clean this up, the headers should not leak out (maybe all we need is a PerfettoConsumer
-    // forward declaration?).
-    include_dirs: [],
-    // Various perfetto protos are used directly by iorap.
-    //
-    // Furthermore, we need this regardless to avoid linking errors when linking
-    // libiorap-compiler.a into the main cc_binary rule.
-    static_libs: [
-        "libiorap-perfetto",
-        // "perfetto_trace_protos",
-        "libiorap-inode2filename",
-        "libiorap-serialize",
-    ],
-
-    shared_libs: [
-        // Not part of true dependencies: Users of 'libiorap-compiler' do not link against
-        // libperfetto.
-        // We only put this to avoid linking errors when building iorapd.
-        // TODO: can we split iorapd into libiorapd-main that doesn't link against libperfetto?
-        // only the last cc_binary should need the full transitive closure of the dependency graph.
-    ]
-}
-
-cc_library_static {
-    name: "libiorap-compiler",
-    defaults: [
-        "iorap-default-flags",
-        "iorap-default-dependencies",
-        "libiorap-compiler-default-dependencies",
-    ],
-
-    srcs: [
-        "src/compiler/**/*.cc",
-    ],
-}
-
-cc_binary {
-  name: "iorap.cmd.compiler",
-  defaults: [
-      "iorap-default-flags",
-      "iorap-default-dependencies",
-      "libiorap-compiler-default-dependencies",
-  ],
-  shared_libs: [],
-  include_dirs: [],
-  srcs: [
-      "src/compiler/**/*.cc",
-  ],
-  // Easier debugging. TODO: make a separate debug config.
-  // XX: Using -O0 seems to completely hide some errors.
-  cflags: ["-O2", "-UNDEBUG", "-DIORAP_COMPILER_MAIN=1"],
-  sanitize: {
-    undefined: true,
-    all_undefined: true,
-    // Pretty print when ubsan detects a problem.
-    // Otherwise it just calls abort().
-
-/*
-    diag: {
-      undefined: true,
-    },
-    */ // don't use the diag when you want it to crash.
-  },
-
-  static_libs: [
-  ],
-  required: [
-      "iorap.inode2filename",
-  ],
-}
-
-// Static libraries cannot export their dependencies,
-// the current convention is to use an extra 'defaults' rule for statics
-// to bring in all the dependencies.
-cc_defaults {
-    name: "libiorap-serialize-default-dependencies",
-
-    defaults: [
-    ],
-
-    include_dirs: [],
-    static_libs: [
-    ],
-    shared_libs: [
-    ],
-    // Above intentionally left empty.
-    srcs: [
-        "src/serialize/**/*.proto",
-    ],
-}
-
-cc_library_static {
-    name: "libiorap-serialize",
-    defaults: [
-        "iorap-default-flags",
-        "iorap-default-dependencies",
-        "libiorap-serialize-default-dependencies",
-    ],
-
-    srcs: [
-        "src/serialize/**/*.cc",
-    ],
-}
-
-
-// Static libraries cannot export their dependencies,
-// the current convention is to use an extra 'defaults' rule for statics
-// to bring in all the dependencies.
-cc_defaults {
-    name: "libiorap-prefetcher-default-dependencies",
-
-    defaults: [
-    ],
-
-    include_dirs: [],
-    static_libs: [
-        "libiorap-serialize",
-    ],
-    shared_libs: [
-        "libminijail",
-    ],
-
-    // disable mac builds because libminijail doesn't work there
-    target: {
-        darwin: {
-            enabled: false,
-        },
-    },
-}
-
-cc_library_static {
-    name: "libiorap-prefetcher",
-    defaults: [
-        "iorap-default-flags",
-        "iorap-default-dependencies",
-        "libiorap-prefetcher-default-dependencies",
-        "libiorap-serialize-default-dependencies",
-    ],
-
-    srcs: [
-        "src/prefetcher/**/*.cc",
-    ],
-}
-
-cc_binary {
-  name: "iorap.prefetcherd",
-  defaults: [
-      "iorap-default-flags",
-      "iorap-default-dependencies",
-      "libiorap-prefetcher-default-dependencies",
-      "libiorap-serialize-default-dependencies",
-  ],
-  shared_libs: [],
-  include_dirs: [],
-  srcs: [
-      "src/prefetcher/**/*.cc",
-  ],
-  // Easier debugging. TODO: make a separate debug config.
-  // XX: Using -O0 seems to completely hide some errors.
-  cflags: ["-O2", "-UNDEBUG", "-DIORAP_PREFETCHER_MAIN=1"],
-  sanitize: {
-    undefined: true,
-    all_undefined: true,
-    // Pretty print when ubsan detects a problem.
-    // Otherwise it just calls abort().
-
-/*
-    diag: {
-      undefined: true,
-    },
-    */ // don't use the diag when you want it to crash.
-  },
-
-  static_libs: [
-  ],
-}
-
-cc_binary {
-  name: "iorap.cmd.prefetcher.client",
-  defaults: [
-      "iorap-default-flags",
-      "iorap-default-dependencies",
-      "libiorap-prefetcher-default-dependencies",
-      "libiorap-serialize-default-dependencies",
-  ],
-  shared_libs: [],
-  include_dirs: [],
-  srcs: [
-      "src/prefetcher/**/*.cc",
-  ],
-  // Easier debugging. TODO: make a separate debug config.
-  // XX: Using -O0 seems to completely hide some errors.
-  cflags: ["-O2", "-UNDEBUG", "-DIORAP_PREFETCHER_MAIN_CLIENT=1"],
-  sanitize: {
-    undefined: true,
-    all_undefined: true,
-    // Pretty print when ubsan detects a problem.
-    // Otherwise it just calls abort().
-
-/*
-    diag: {
-      undefined: true,
-    },
-    */ // don't use the diag when you want it to crash.
-  },
-
-  static_libs: [
-  ],
-}
-
-prebuilt_etc {
-  name: "iorap.prefetcherd.policy",
-  sub_dir: "seccomp_policy",
-  arch: {
-    arm: {
-      src: "seccomp_policy/prefetcherd.arm.policy"
-    },
-    arm64: {
-      src: "seccomp_policy/prefetcherd.arm64.policy"
-    },
-    x86: {
-      src: "seccomp_policy/prefetcherd.x86.policy"
-    },
-    x86_64: {
-      src: "seccomp_policy/prefetcherd.x86_64.policy"
-    },
-  },
-  required: [
-      "crash_dump.policy",
-  ],
-}
-
-// Static libraries cannot export their dependencies,
-// the current convention is to use an extra 'defaults' rule for statics
-// to bring in all the dependencies.
-cc_defaults {
-    name: "libiorap-db-default-dependencies",
-
-    defaults: [
-    ],
-
-    include_dirs: [],
-    static_libs: [
-    ],
-    shared_libs: [
-        "libsqlite",
-    ],
-}
-
-cc_library_static {
-    name: "libiorap-db",
-    defaults: [
-        "iorap-default-flags",
-        "iorap-default-dependencies",
-        "libiorap-db-default-dependencies",
-    ],
-
-    srcs: [
-        "src/db/**/*.cc",
-    ],
-}
-
-cc_binary {
-  name: "iorap.cmd.db",
-  defaults: [
-      "iorap-default-flags",
-      "iorap-default-dependencies",
-      "libiorap-db-default-dependencies",
-  ],
-  shared_libs: [],
-  include_dirs: [],
-  srcs: [
-      "src/db/**/*.cc",
-  ],
-  // Easier debugging. TODO: make a separate debug config.
-  // XX: Using -O0 seems to completely hide some errors.
-  cflags: ["-O2", "-UNDEBUG", "-DIORAP_DB_MAIN=1"],
-  sanitize: {
-    undefined: true,
-    all_undefined: true,
-    // Pretty print when ubsan detects a problem.
-    // Otherwise it just calls abort().
-
-/*
-    diag: {
-      undefined: true,
-    },
-    */ // don't use the diag when you want it to crash.
-  },
-
-  static_libs: [
-  ],
-}
-
-cc_defaults {
-    name: "libiorap-maintenance-default-dependencies",
-
-    defaults: [
-        "libiorap-compiler-default-dependencies",
-        "libiorap-db-default-dependencies",
-        "libiorap-prefetcher-default-dependencies",
-    ],
-
-    include_dirs: [],
-
-    static_libs: [
-        "libiorap-binder",
-        "libiorap-compiler",
-        "libiorap-db",
-        "libiorap-prefetcher",
-    ],
-
-    shared_libs: []
-}
-
-cc_library_static {
-    name: "libiorap-maintenance",
-    defaults: [
-        "iorap-default-flags",
-        "iorap-default-dependencies",
-        "libiorap-maintenance-default-dependencies",
-    ],
-
-    srcs: [
-        "src/maintenance/*.cc",
-    ],
-}
-
-cc_binary {
-  name: "iorap.cmd.maintenance",
-  defaults: [
-      "iorap-default-flags",
-      "iorap-default-dependencies",
-      "libiorap-maintenance-default-dependencies",
-  ],
-  shared_libs: [],
-  include_dirs: [],
-  srcs: [
-      "src/maintenance/*.cc",
-  ],
-  cflags: ["-O2", "-UNDEBUG", "-DIORAP_MAINTENANCE_MAIN=1"],
-  sanitize: {
-    undefined: true,
-    all_undefined: true,
-
-    diag: {
-      undefined: true,
-    },
-  },
-
-  static_libs: [],
-}
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index 4e9f5fd..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-# Build every binary target in system/iorap
-.PHONY: iorap-nall
-iorap-nall: \
-  iorapd iorap.inode2filename iorapd-tests iorap.cmd.perfetto \
-  iorap.cmd.compiler
-
-# Build every binary target required for
-# frameworks/base/startop/scripts/app_startup_runner
-# to work with iorap.
-.PHONY: iorap-app-startup-runner
-iorap-app-startup-runner: \
-  iorapd iorap.inode2filename \
-  iorap.cmd.compiler
-
-
diff --git a/binder/com/google/android/startop/iorap/AppIntentEvent.aidl b/binder/com/google/android/startop/iorap/AppIntentEvent.aidl
deleted file mode 100644
index dbf1d02..0000000
--- a/binder/com/google/android/startop/iorap/AppIntentEvent.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.startop.iorap;
-
-/** @hide */
-parcelable AppIntentEvent cpp_header "binder/app_intent_event.h";
diff --git a/binder/com/google/android/startop/iorap/AppLaunchEvent.aidl b/binder/com/google/android/startop/iorap/AppLaunchEvent.aidl
deleted file mode 100644
index ea3f9f1..0000000
--- a/binder/com/google/android/startop/iorap/AppLaunchEvent.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.startop.iorap;
-
-/** @hide */
-parcelable AppLaunchEvent cpp_header "binder/app_launch_event.h";
diff --git a/binder/com/google/android/startop/iorap/DexOptEvent.aidl b/binder/com/google/android/startop/iorap/DexOptEvent.aidl
deleted file mode 100644
index a4e175b..0000000
--- a/binder/com/google/android/startop/iorap/DexOptEvent.aidl
+++ /dev/null
@@ -1,20 +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.
- */
-
-package com.google.android.startop.iorap;
-
-/** @hide */
-parcelable DexOptEvent cpp_header "binder/dexopt_event.h";
diff --git a/binder/com/google/android/startop/iorap/IIorap.aidl b/binder/com/google/android/startop/iorap/IIorap.aidl
deleted file mode 100644
index 05faefe..0000000
--- a/binder/com/google/android/startop/iorap/IIorap.aidl
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.startop.iorap;
-
-import com.google.android.startop.iorap.ITaskListener;
-
-import com.google.android.startop.iorap.AppIntentEvent;
-import com.google.android.startop.iorap.AppLaunchEvent;
-import com.google.android.startop.iorap.DexOptEvent;
-import com.google.android.startop.iorap.JobScheduledEvent;
-import com.google.android.startop.iorap.PackageEvent;
-import com.google.android.startop.iorap.RequestId;
-import com.google.android.startop.iorap.SystemServiceEvent;
-import com.google.android.startop.iorap.SystemServiceUserEvent;
-
-/**
-* IIOrap is a client interface to the input/output readahead and pin daemon (iorapd).
-*
-* The aim is to speed-up the cold start-up time of certain use-cases like application startup
-* by utilizing trace-based pinning or readahead.
-*
-* Programatically, the behavior of iorapd should be treated like a black box. There is no
-* "correctness", but only performance. By sending the right events at the appropriate time,
-* we can squeeze more performance out of the system.
-*
-* If some events are not appropriately wired up, system performance may (temporarily) degrade.
-*
-* {@hide} */
-oneway interface IIorap {
-   /**
-    * Set an ITaskListener which will be used to deliver notifications of in-progress/completition
-    * for the onXEvent method calls below this.<br /><br />
-    *
-    * iorapd does all the work asynchronously and may deliver one or more onProgress events after
-    * the event begins to be processed. It will always send back one onComplete that is considered
-    * terminal.<br /><br />
-    *
-    * onProgress/onComplete are matched to the original event by the requestId. Once an onComplete
-    * occurs for any given requestId, no further callbacks with the same requestId will occur.
-    * It is illegal for the caller to reuse the same requestId on different invocations of IIorap.
-    * <br /><br />
-    *
-    * onXEvent(id1) must be well-ordered w.r.t. onXEvent(id2), the assumption is that later
-    * calls happen-after earlier calls and that id2 > id1. Decreasing request IDs will
-    * immediately get rejected.
-    * <br /><br />
-    *
-    * Sequence diagram of stereotypical successful event delivery and response notification:
-    *
-    * <pre>
-    *
-    *           ┌─────────────┐                ┌──────┐
-    *           │system_server│                │iorapd│
-    *           └──────┬──────┘                └──┬───┘
-    *                  Request [01]: onSomeEvent ┌┴┐
-    *                  │────────────────────────>│ │
-    *                  │                         │ │
-    *                  │                         │ │  ╔════════════════════════╗
-    *                  │                         │ │  ║start processing event ░║
-    *                  │                         │ │  ╚════════════════════════╝
-    *                  │                         │ │
-    * ╔═══════╤════════╪═════════════════════════╪═╪══════════════════════════════╗
-    * ║ LOOP  │  1 or more times                 │ │                              ║
-    * ╟───────┘        │                         │ │                              ║
-    * ║                │Request [01]: onProgress │ │                              ║
-    * ║                │<────────────────────────│ │                              ║
-    * ║                │                         │ │                              ║
-    * ║                │                         │ │────┐                         ║
-    * ║                │                         │ │    │ workload in progress    ║
-    * ║                │                         │ │<───┘                         ║
-    * ╚════════════════╪═════════════════════════╪═╪══════════════════════════════╝
-    *                  │                         └┬┘
-    *                  .                          .
-    *                  .                          .
-    *                  .                          .
-    *                  .                          .
-    *                  .                          .
-    *                  │                         ┌┴┐  ╔═════════════════════════╗
-    *                  │                         │ │  ║finish processing event ░║
-    *                  │                         │ │  ╚═════════════════════════╝
-    *                  │Request [01]: onComplete │ │
-    *                  │<────────────────────────│ │
-    *           ┌──────┴──────┐                ┌─└┬┘──┐
-    *           │system_server│                │iorapd│
-    *           └─────────────┘                └──────┘
-    *
-    * </pre> <!-- system/iorap/docs/binder/IIorap_setTaskListener.plantuml -->
-    */
-    void setTaskListener(ITaskListener listener);
-
-    // All callbacks will be done via the ITaskListener.
-    // The RequestId passed in is the same RequestId sent back via the ITaskListener.
-    // See above for more details.
-
-    // Note: For each ${Type}Event, see the ${Type}Event.java for more documentation
-    // in frameworks/base/startop/src/com/google/android/startop/iorap/${Type}Event.java
-
-    // void onActivityHintEvent(in RequestId request, in ActivityHintEvent event);
-    void onAppLaunchEvent(in RequestId request, in AppLaunchEvent event);
-    void onDexOptEvent(in RequestId request, in DexOptEvent event);
-    void onJobScheduledEvent(in RequestId request, in JobScheduledEvent event);
-    void onPackageEvent(in RequestId request, in PackageEvent event);
-    void onAppIntentEvent(in RequestId request, in AppIntentEvent event);
-    void onSystemServiceEvent(in RequestId request, in SystemServiceEvent event);
-    void onSystemServiceUserEvent(in RequestId request, in SystemServiceUserEvent event);
-}
diff --git a/binder/com/google/android/startop/iorap/ITaskListener.aidl b/binder/com/google/android/startop/iorap/ITaskListener.aidl
deleted file mode 100644
index 0b5f4a6..0000000
--- a/binder/com/google/android/startop/iorap/ITaskListener.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.startop.iorap;
-
-import com.google.android.startop.iorap.TaskResult;
-import com.google.android.startop.iorap.RequestId;
-
-/**
-* Provide callbacks to the {@code IIorap} client in response to method invocations.<br /><br />
-*
-* @see com.google.android.startop.iorap.IIorap
-*
-* {@hide} */
-oneway interface ITaskListener {
-    void onProgress(in RequestId requestId, in TaskResult result);
-    void onComplete(in RequestId requestId, in TaskResult result);
-}
-
-// TODO: we can probably delete the multiple methods. one is likely sufficient?
diff --git a/binder/com/google/android/startop/iorap/JobScheduledEvent.aidl b/binder/com/google/android/startop/iorap/JobScheduledEvent.aidl
deleted file mode 100644
index d4b5454..0000000
--- a/binder/com/google/android/startop/iorap/JobScheduledEvent.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.startop.iorap;
-
-/** @hide */
-parcelable JobScheduledEvent cpp_header "binder/job_scheduled_event.h";
diff --git a/binder/com/google/android/startop/iorap/PackageEvent.aidl b/binder/com/google/android/startop/iorap/PackageEvent.aidl
deleted file mode 100644
index 8f9d18e..0000000
--- a/binder/com/google/android/startop/iorap/PackageEvent.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.startop.iorap;
-
-/** @hide */
-parcelable PackageEvent cpp_header "binder/package_event.h";
diff --git a/binder/com/google/android/startop/iorap/RequestId.aidl b/binder/com/google/android/startop/iorap/RequestId.aidl
deleted file mode 100644
index 895af87..0000000
--- a/binder/com/google/android/startop/iorap/RequestId.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.startop.iorap;
-
-/** @hide */
-parcelable RequestId cpp_header "binder/request_id.h";
diff --git a/binder/com/google/android/startop/iorap/SystemServiceEvent.aidl b/binder/com/google/android/startop/iorap/SystemServiceEvent.aidl
deleted file mode 100644
index 005676f..0000000
--- a/binder/com/google/android/startop/iorap/SystemServiceEvent.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.startop.iorap;
-
-/** @hide */
-parcelable SystemServiceEvent cpp_header "binder/system_service_event.h";
diff --git a/binder/com/google/android/startop/iorap/SystemServiceUserEvent.aidl b/binder/com/google/android/startop/iorap/SystemServiceUserEvent.aidl
deleted file mode 100644
index c165dc4..0000000
--- a/binder/com/google/android/startop/iorap/SystemServiceUserEvent.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.startop.iorap;
-
-/** @hide */
-parcelable SystemServiceUserEvent cpp_header "binder/system_service_user_event.h";
diff --git a/binder/com/google/android/startop/iorap/TaskResult.aidl b/binder/com/google/android/startop/iorap/TaskResult.aidl
deleted file mode 100644
index 76cce8f..0000000
--- a/binder/com/google/android/startop/iorap/TaskResult.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.startop.iorap;
-
-/** @hide */
-parcelable TaskResult cpp_header "binder/task_result.h";
diff --git a/docs/binder/ActivityHint.dot b/docs/binder/ActivityHint.dot
deleted file mode 100644
index 94b5a84..0000000
--- a/docs/binder/ActivityHint.dot
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Convert with `graph-easy --as=boxart` to get textual rendering.
- */
-digraph finite_state_machine {
-rankdir=LR;
-size="8,5"
-node [shape = circle ]; STARTED;
-node [shape = doublecircle];
-
-"" -> STARTED;
-STARTED -> CANCELLED;
-STARTED -> COMPLETED;
-COMPLETED -> POST_COMPLETED;
-COMPLETED -> CANCELLED;
-}
diff --git a/docs/binder/IIorap_setTaskListener.plantuml b/docs/binder/IIorap_setTaskListener.plantuml
deleted file mode 100644
index 5cdfac7..0000000
--- a/docs/binder/IIorap_setTaskListener.plantuml
+++ /dev/null
@@ -1,53 +0,0 @@
-@startuml
-' Copyright (C) 2018 The Android Open Source Project
-'
-' Licensed under the Apache License, Version 2.0 (the "License");
-' you may not use this file except in compliance with the License.
-' You may obtain a copy of the License at
-'
-'      http://www.apache.org/licenses/LICENSE-2.0
-'
-' Unless required by applicable law or agreed to in writing, software
-' distributed under the License is distributed on an "AS IS" BASIS,
-' WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-' See the License for the specific language governing permissions and
-' limitations under the License.
-
-' Compile with PlantUML:
-' http://www.plantuml.com/plantuml/uml/
-
-
-'hide footbox
-
-participant "system_server" as ss
-participant iorapd
-
-autonumber 1 0 "Request [00]:"
-
-ss -\ iorapd : onSomeEvent
-activate iorapd
-note right of iorapd
-  start processing event
-end note
-
-loop 1 or more times
-iorapd -\ ss : onProgress
-
-autonumber stop
-iorapd -> iorapd : workload in progress
-autonumber resume
-
-end
-
-' some time later...
-... ...
-
-note right of iorapd
-  finish processing event
-end note
-
-
-iorapd -\ ss : onComplete
-
-deactivate iorapd
-@enduml
diff --git a/docs/binder/TaskResult.dot b/docs/binder/TaskResult.dot
deleted file mode 100644
index 28d7819..0000000
--- a/docs/binder/TaskResult.dot
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Convert with `graph-easy --as=boxart` to get textual rendering.
- */
-digraph finite_state_machine {
-rankdir=LR;
-size="8,5"
-node [shape = circle ]; BEGAN ONGOING;
-node [shape = doublecircle];
-
-// graph-easy does not support multiple state syntax {}, write one-by-one
-
-"" -> BEGAN;
-"" -> ERROR;
-BEGAN -> ERROR;
-ONGOING -> ERROR;
-
-BEGAN -> ONGOING;
-BEGAN -> COMPLETED;
-ONGOING -> COMPLETED;
-
-}
diff --git a/include/binder/activity_info.h b/include/binder/activity_info.h
deleted file mode 100644
index 0712f18..0000000
--- a/include/binder/activity_info.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_BINDER_ACTIVITY_INFO_H_
-#define IORAP_BINDER_ACTIVITY_INFO_H_
-
-#include "binder/common.h"
-#include "binder/auto_parcelable.h"
-#include "common/introspection.h"
-
-#include <string>
-
-namespace iorap {
-namespace binder {
-
-struct ActivityInfo : public AutoParcelable<ActivityInfo> {
-  std::string package_name;
-  std::string activity_name;
-};
-
-IORAP_INTROSPECT_ADAPT_STRUCT(ActivityInfo, package_name, activity_name);
-
-}
-}
-IORAP_JAVA_NAMESPACE_BINDER_TYPEDEF(ActivityInfo)
-
-#endif  // IORAP_BINDER_ACTIVITY_INFO_H_
diff --git a/include/binder/app_intent_event.h b/include/binder/app_intent_event.h
deleted file mode 100644
index bbd19ee..0000000
--- a/include/binder/app_intent_event.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_BINDER_APP_INTENT_EVENT_H_
-#define IORAP_BINDER_APP_INTENT_EVENT_H_
-
-#include "binder/common.h"
-#include "binder/auto_parcelable.h"
-#include "common/introspection.h"
-
-#include "binder/activity_info.h"
-
-namespace iorap {
-namespace binder {
-
-struct AppIntentEvent : public AutoParcelable<AppIntentEvent> {
-  enum class Type : int32_t {
-    kDefaultIntentChanged = 0,
-  };
-
-  Type type;
-  ActivityInfo old_activity_info;
-  ActivityInfo new_activity_info;
-};
-
-IORAP_INTROSPECT_ADAPT_STRUCT(AppIntentEvent, type, old_activity_info, new_activity_info);
-
-}
-}
-IORAP_JAVA_NAMESPACE_BINDER_TYPEDEF(AppIntentEvent)
-
-#endif  // IORAP_BINDER_APP_INTENT_EVENT_H_
diff --git a/include/binder/app_launch_event.h b/include/binder/app_launch_event.h
deleted file mode 100644
index 0127e09..0000000
--- a/include/binder/app_launch_event.h
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_BINDER_APP_LAUNCH_EVENT_H_
-#define IORAP_BINDER_APP_LAUNCH_EVENT_H_
-
-#include "binder/common.h"
-#include "common/introspection.h"
-#include "common/expected.h"
-
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
-#include <frameworks/base/core/proto/android/content/intent.pb.h>  // IntentProto
-#include <frameworks/base/core/proto/android/server/activitymanagerservice.pb.h>  // ActivityRecord
-
-namespace iorap {
-namespace binder {
-
-// These protos are part of the iorapd binder ABI, alias them for easier usage.
-using IntentProto = ::android::content::IntentProto;
-using ActivityRecordProto = ::com::android::server::wm::ActivityRecordProto;
-
-struct AppLaunchEvent : public ::android::Parcelable {
-  // Index position matters: Keep up-to-date with AppLaunchEvent.java sTypes field.
-  enum class Type : int32_t {
-    kUninitialized = -1,
-    kIntentStarted = 0,
-    kIntentFailed = 1,
-    kActivityLaunched = 2,
-    kActivityLaunchFinished = 3,
-    kActivityLaunchCancelled = 4,
-    kReportFullyDrawn = 5,
-  };
-
-  enum class Temperature : int32_t {
-    kUninitialized = -1,
-    kCold = 1,
-    kWarm = 2,
-    kHot = 3,
-  };
-
-  Type type{Type::kUninitialized};
-  int64_t sequence_id{-1};
-  // kIntentStarted only.
-  std::unique_ptr<IntentProto> intent_proto;
-  // kActivityLaunched only.
-  Temperature temperature{Temperature::kUninitialized};
-  // kActivityLaunch*. Can be null in kActivityLaunchCancelled.
-  std::unique_ptr<ActivityRecordProto> activity_record_proto;
-  // kIntentStarted, kActivityLaunchFinished and kReportFullyDrawn only.
-  int64_t timestamp_nanos{-1};
-
-  AppLaunchEvent() = default;
-  AppLaunchEvent(Type type,
-                 int64_t sequence_id,
-                 std::unique_ptr<IntentProto> intent_proto = nullptr,
-                 Temperature temperature = Temperature::kUninitialized,
-                 std::unique_ptr<ActivityRecordProto> activity_record_proto = nullptr,
-                 int64_t timestamp_nanos = -1)
-    : type(type),
-      sequence_id(sequence_id),
-      intent_proto(std::move(intent_proto)),
-      temperature(temperature),
-      activity_record_proto(std::move(activity_record_proto)),
-      timestamp_nanos(timestamp_nanos) {
-  }
-
-  AppLaunchEvent(const AppLaunchEvent& other) {
-    *this = other;
-  }
-
-  AppLaunchEvent& operator=(const AppLaunchEvent& other) {
-    if (&other == this) {
-      return *this;
-    }
-
-    type = other.type;
-    sequence_id = other.sequence_id;
-    if (other.intent_proto != nullptr) {
-      intent_proto.reset(new IntentProto(*other.intent_proto));
-    }
-    temperature = other.temperature;
-    if (other.activity_record_proto != nullptr) {
-      activity_record_proto.reset(new ActivityRecordProto(*other.activity_record_proto));
-    }
-    timestamp_nanos = other.timestamp_nanos;
-
-    return *this;
-  }
-
-  ::android::status_t readFromParcel(const android::Parcel* parcel) override {
-
-#   define PARCEL_READ_OR_RETURN(function, ...) \
-    if (::android::status_t res = function(__VA_ARGS__); res != ::android::NO_ERROR) { \
-      LOG(ERROR) << "AppLaunchEvent::readFromParcel failed"; \
-      return res; \
-    }
-
-    int32_t type_int;
-    PARCEL_READ_OR_RETURN(parcel->readInt32, &type_int);
-    type = static_cast<Type>(type_int);
-
-    LOG(VERBOSE) << "AppLaunchEvent::readFromParcel (type=" << type_int << ")";
-
-    PARCEL_READ_OR_RETURN(parcel->readInt64, &sequence_id);
-
-    switch (type) {
-      case Type::kIntentStarted:
-        PARCEL_READ_OR_RETURN(readIntent, parcel);
-        PARCEL_READ_OR_RETURN(parcel->readInt64, &timestamp_nanos);
-        break;
-      case Type::kIntentFailed:
-        // No extra arguments.
-        break;
-      case Type::kActivityLaunched: {
-        PARCEL_READ_OR_RETURN(readActivityRecordProto, parcel);
-        int32_t temperature_int;
-        PARCEL_READ_OR_RETURN(parcel->readInt32, &temperature_int);
-        temperature = static_cast<Temperature>(temperature_int);
-        break;
-      }
-      case Type::kActivityLaunchFinished:
-        PARCEL_READ_OR_RETURN(readActivityRecordProto, parcel);
-        PARCEL_READ_OR_RETURN(parcel->readInt64, &timestamp_nanos);
-        break;
-      case Type::kActivityLaunchCancelled:
-        PARCEL_READ_OR_RETURN(readActivityRecordProtoNullable, parcel);
-        break;
-      case Type::kReportFullyDrawn:
-        PARCEL_READ_OR_RETURN(readActivityRecordProto, parcel);
-        PARCEL_READ_OR_RETURN(parcel->readInt64, &timestamp_nanos);
-        break;
-      default:
-        return android::BAD_VALUE;
-    }
-#   undef PARCEL_READ_OR_RETURN
-
-    return ::android::NO_ERROR;
-
-    // TODO: std::variant + protobuf implementation in AutoParcelable.
-  }
-
-#define PARCEL_WRITE_OR_RETURN(function, ...) \
-  if (::android::status_t res = function(__VA_ARGS__); res != ::android::NO_ERROR) { \
-    return res; \
-  }
-
-  ::android::status_t writeToParcel(android::Parcel* parcel) const override {
-    PARCEL_WRITE_OR_RETURN(parcel->writeInt32, static_cast<int32_t>(type));
-    PARCEL_WRITE_OR_RETURN(parcel->writeInt64, sequence_id);
-
-    switch (type) {
-      case Type::kIntentStarted:
-        PARCEL_WRITE_OR_RETURN(writeIntent, parcel);
-        PARCEL_WRITE_OR_RETURN(parcel->writeInt64, timestamp_nanos);
-        break;
-      case Type::kIntentFailed:
-        // No extra arguments.
-        break;
-      case Type::kActivityLaunched:
-        PARCEL_WRITE_OR_RETURN(writeActivityRecordProto, parcel);
-        PARCEL_WRITE_OR_RETURN(parcel->writeInt32, static_cast<int32_t>(temperature));
-        break;
-      case Type::kActivityLaunchFinished:
-        PARCEL_WRITE_OR_RETURN(writeActivityRecordProto, parcel);
-        PARCEL_WRITE_OR_RETURN(parcel->writeInt64, timestamp_nanos);
-        break;
-      case Type::kActivityLaunchCancelled:
-        PARCEL_WRITE_OR_RETURN(writeActivityRecordProtoNullable, parcel);
-        break;
-      case Type::kReportFullyDrawn:
-        PARCEL_WRITE_OR_RETURN(writeActivityRecordProtoNullable, parcel);
-        PARCEL_WRITE_OR_RETURN(parcel->writeInt64, timestamp_nanos);
-        break;
-      default:
-        DCHECK(false) << "attempted to write an uninitialized AppLaunchEvent to Parcel";
-        return android::BAD_VALUE;
-    }
-
-#undef PARCEL_WRITE_OR_RETURN
-
-    return android::NO_ERROR;
-  }
-
- private:
-  // Using 'unique_ptr' here because protobufs don't have a move constructor. Is there
-  // a better way that is cheap to pass them around?
-  template <typename T>
-  static expected<std::unique_ptr<T>, ::android::status_t>
-  ReadProto(const android::Parcel* parcel) {
-    DCHECK(parcel != nullptr);
-
-    ::android::status_t res;
-
-    std::vector<uint8_t> byte_vector;
-    if ((res = parcel->readByteVector(/*out*/&byte_vector)) != ::android::NO_ERROR) {
-      return unexpected(res);
-    }
-    // TODO: we may want to do this without an extra copy, by parsing
-    // the protobuf directly out of the parcel.
-
-    const uint8_t* data = byte_vector.data();
-    const size_t size = byte_vector.size();
-
-    std::unique_ptr<T> proto_ptr{new T{}};
-
-    if (!proto_ptr) {
-      return unexpected(::android::NO_MEMORY);
-    }
-
-    if (!proto_ptr->ParseFromArray(data, size)) {
-      return unexpected(::android::BAD_VALUE);
-    }
-
-    return proto_ptr;
-  }
-
-  template <typename T>
-  static expected<std::unique_ptr<T>, ::android::status_t>
-  ReadNullableProto(const android::Parcel* parcel) {
-    DCHECK(parcel != nullptr);
-
-    bool value;
-
-    ::android::status_t res;
-    res = parcel->readBool(/*out*/&value);
-
-    if (res != ::android::NO_ERROR) {
-      return unexpected(res);
-    }
-
-    if (!value) {
-      return std::unique_ptr<T>{nullptr};
-    }
-
-    return ReadProto<T>(parcel);
-  }
-
-  template <typename T>
-  static ::android::status_t
-  WriteProto(android::Parcel* parcel, const std::unique_ptr<T>& proto) {
-    DCHECK(parcel != nullptr);
-    DCHECK(proto != nullptr);
-
-    std::vector<uint8_t> byte_vector;
-    {
-      const int serialized_size = proto->ByteSize();
-      byte_vector.resize(serialized_size);
-      if (!proto->SerializeToArray(byte_vector.data(), serialized_size)) {
-        return ::android::BAD_VALUE;
-      }
-    }
-
-    ::android::status_t res;
-    if ((res = parcel->writeByteVector(/*in*/byte_vector)) != ::android::NO_ERROR) {
-      return res;
-    }
-
-    return ::android::NO_ERROR;
-  }
-
-  template <typename T>
-  static ::android::status_t
-  WriteNullableProto(android::Parcel* parcel, const std::unique_ptr<T>& maybe_proto) {
-    bool value = (maybe_proto != nullptr);
-
-    ::android::status_t res;
-    res = parcel->writeBool(value);
-
-    if (res != ::android::NO_ERROR) {
-      return res;
-    }
-
-    if (!value) {
-      return ::android::NO_ERROR;
-    }
-
-    return WriteProto<T>(parcel, maybe_proto);
-  }
-
-  android::status_t readIntent(const android::Parcel* parcel) {
-    expected<std::unique_ptr<IntentProto>, ::android::status_t> maybe_intent =
-        ReadProto<IntentProto>(parcel);
-
-    if (maybe_intent) {
-      intent_proto = std::move(maybe_intent.value());
-      return ::android::NO_ERROR;
-    } else {
-      return maybe_intent.error();
-    }
-  }
-
-  android::status_t readActivityRecordProto(const android::Parcel* parcel) {
-    expected<std::unique_ptr<ActivityRecordProto>, ::android::status_t> maybe_record =
-        ReadProto<ActivityRecordProto>(parcel);
-
-    if (maybe_record) {
-      activity_record_proto = std::move(maybe_record.value());
-      return ::android::NO_ERROR;
-    } else {
-      return maybe_record.error();
-    }
-  }
-
-  android::status_t readActivityRecordProtoNullable(const android::Parcel* parcel) {
-    expected<std::unique_ptr<ActivityRecordProto>, ::android::status_t> maybe_record =
-        ReadNullableProto<ActivityRecordProto>(parcel);
-
-    if (maybe_record) {
-      activity_record_proto = std::move(maybe_record.value());
-      return ::android::NO_ERROR;
-    } else {
-      return maybe_record.error();
-    }
-  }
-
-  android::status_t writeIntent(android::Parcel* parcel) const {
-    return WriteProto<IntentProto>(parcel, intent_proto);
-  }
-
-  android::status_t writeActivityRecordProto(android::Parcel* parcel) const {
-    return WriteProto<ActivityRecordProto>(parcel, activity_record_proto);
-  }
-
-  android::status_t writeActivityRecordProtoNullable(android::Parcel* parcel) const {
-    return WriteNullableProto<ActivityRecordProto>(parcel, activity_record_proto);
-  }
-};
-
-inline std::ostream& operator<<(std::ostream& os, const AppLaunchEvent::Type& type) {
-  switch (type) {
-    case AppLaunchEvent::Type::kUninitialized:
-      os << "kUninitialized";
-      break;
-    case AppLaunchEvent::Type::kIntentStarted:
-      os << "kIntentStarted";
-      break;
-    case AppLaunchEvent::Type::kIntentFailed:
-      os << "kIntentFailed";
-      break;
-    case AppLaunchEvent::Type::kActivityLaunched:
-      os << "kActivityLaunched";
-      break;
-    case AppLaunchEvent::Type::kActivityLaunchCancelled:
-      os << "kActivityLaunchCancelled";
-      break;
-    case AppLaunchEvent::Type::kActivityLaunchFinished:
-      os << "kActivityLaunchFinished";
-      break;
-    case AppLaunchEvent::Type::kReportFullyDrawn:
-      os << "kReportFullyDrawn";
-      break;
-    default:
-      os << "(unknown)";
-  }
-  return os;
-}
-
-inline std::ostream& operator<<(std::ostream& os, const AppLaunchEvent::Temperature& type) {
-  switch (type) {
-    case AppLaunchEvent::Temperature::kUninitialized:
-      os << "kUninitialized";
-      break;
-    case AppLaunchEvent::Temperature::kCold:
-      os << "kCold";
-      break;
-    case AppLaunchEvent::Temperature::kWarm:
-      os << "kWarm";
-      break;
-    case AppLaunchEvent::Temperature::kHot:
-      os << "kHot";
-      break;
-    default:
-      os << "(unknown)";
-  }
-  return os;
-}
-
-inline std::ostream& operator<<(std::ostream& os, const AppLaunchEvent& e) {
-  os << "AppLaunchEvent{";
-  os << "type=" << e.type << ",";
-  os << "sequence_id=" << e.sequence_id << ",";
-
-  os << "intent_proto=";
-  if (e.intent_proto == nullptr) {
-    os << "(nullptr)";
-  } else {
-    os << "(action=" << e.intent_proto->action() << ",";
-    os << "component=";
-    if (e.intent_proto->has_component()) {
-      // $package/$class_name
-      os << e.intent_proto->component().package_name() << "/"
-         << e.intent_proto->component().class_name();
-    } else {
-      os << "(no component)";
-    }
-    os << ")";
-  }
-  os << ",";
-
-  os << "temperature=" << e.temperature << ",";
-  os << ",";
-
-  os << "activity_record_proto=";
-  if (e.activity_record_proto == nullptr) {
-    os << "(nullptr)";
-  } else {
-    // title or component name.
-    os << "'" << e.activity_record_proto->identifier().title() << "'";
-  }
-  os << ",";
-
-  os << "timestamp_nanos=" << e.timestamp_nanos << ",";
-  os << ",";
-
-  os << "}";
-
-  return os;
-}
-
-/*
-IORAP_INTROSPECT_ADAPT_STRUCT(AppLaunchEvent,
-                              type,
-                              sequence_id,
-                              intent_proto,
-                              temperature,
-                              activity_record_proto);
-*/
-
-}  // namespace binder
-}  // namespace iorap
-
-IORAP_JAVA_NAMESPACE_BINDER_TYPEDEF(AppLaunchEvent)
-
-#endif  // IORAP_BINDER_APP_LAUNCH_EVENT_H_
diff --git a/include/binder/auto_parcelable.h b/include/binder/auto_parcelable.h
deleted file mode 100644
index 357615c..0000000
--- a/include/binder/auto_parcelable.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_BINDER_AUTO_PARCELABLE_H_
-#define IORAP_BINDER_AUTO_PARCELABLE_H_
-
-#include "binder/Parcelable.h"
-#include "binder/Parcel.h"
-#include "binder/Status.h"
-
-#include "common/introspection.h"
-
-namespace iorap {
-namespace binder {
-
-//
-// Implements the android::Parcelable interface (readFromParcel, writeToParcel)
-// automatically by using compile-time introspection on T.
-//
-// Requires that 'T' implements introspection by using the IORAP_INTROSPECT_ADAPT_STRUCT macro.
-//
-template <typename T>
-struct AutoParcelable : public ::android::Parcelable {
- private:
-  using Status = android::binder::Status;
-  using Parcel = android::Parcel;
-  using Parcelable = android::Parcelable;
-  using status_t = android::status_t;
-
- public:
-  // Write every (introspected) field to the parcel by automatically inferring the correct
-  // write method to invoke on the parcel from the member type.
-  status_t writeToParcel(Parcel* parcel) const override {
-    if (parcel == nullptr) {
-      return ::android::UNEXPECTED_NULL;
-    }
-
-    status_t result = android::NO_ERROR;
-    ::iorap::introspect::for_each_member_field_value(*Self(), [&](auto&& value) {
-      if (result == android::NO_ERROR) {
-        result = writeAnyToParcel(/*inout*/parcel, value);
-      }
-    });
-
-    return result;
-  }
-
-  // Read every (introspected) field to the parcel by automatically inferring the correct
-  // read method to invoke on the parcel from the member type.
-  //
-  // Resilient to partial read failures: A return code other than NO_ERROR means that
-  // the current value is left unmodified.
-  status_t readFromParcel(const Parcel* parcel) override {
-    if (parcel == nullptr) {
-      return ::android::UNEXPECTED_NULL;
-    }
-
-    T tmp{*Self()};
-
-    // Unpack all the parcelable data into a temporary copy.
-    // Parceling could fail halfway through, in which case
-    // the original object is unaffected.
-
-    status_t result = android::NO_ERROR;
-    ::iorap::introspect::for_each_member_field_set_value(tmp, [&](auto field_type) {
-      // type<?> field_type
-
-      using ValueT = typename decltype(field_type)::type;
-
-      if (result == android::NO_ERROR) {
-        auto&& [res, read_value] = readAnyFromParcel<ValueT>(/*inout*/parcel);
-        result = res;
-        return ::iorap::introspect::aliasing_forward<ValueT>(read_value);
-      } else {
-        // TODO: nice-to-have fold over members to early-out on failure.
-        return ValueT{};
-      }
-    });
-
-    if (result != android::NO_ERROR) {
-      return result;
-    }
-
-    // Success! Now we can copy all the data in a single step.
-    *Self() = std::move(tmp);
-
-    // TODO: nice-to-have some kind of invariants-checking after reading the parcel data.
-
-    return ::android::NO_ERROR;
-  }
-
- private:
-#define AUTO_PARCELABLE_BINDER_MAPPING(FN) \
-FN(Byte,int8_t)\
-FN(Int32,int32_t)\
-FN(Uint32,uint32_t)\
-FN(Int64,int64_t)\
-FN(Uint64,uint64_t)\
-FN(Float,float)\
-FN(Double,double)\
-FN(Bool,bool)\
-FN(CString,const char*)\
-FN(String16,const String16&)\
-FN(String16,const std::unique_ptr<String16>&)\
-FN(StrongBinder,const sp<IBinder>&)\
-
-  template <typename F>
-  static status_t writeAnyToParcel(Parcel* parcel, const F& value) {
-    using namespace android;  // NOLINT
-
-    // 'F' is the original type of the field here, so it's safe to use it undecayed.
-    // However, to make matching easier we almost always want to match against the decayed type.
-    using D = std::decay_t<F>;  // [const] [volatile] X[&][&] -> X
-
-    if constexpr (std::is_base_of_v<Parcelable, D>) {
-      return value.writeToParcel(parcel);
-    } else if constexpr (std::is_enum_v<D>) {
-      return writeAnyToParcel(parcel, static_cast<std::underlying_type_t<F>>(value));
-#define AUTO_PARCELABLE_WRITE_TO_PARCEL(fn_name, type_name) \
-    } else if constexpr (std::is_same_v<D, std::decay_t<type_name>>) { \
-      return parcel->write ## fn_name (value);
-AUTO_PARCELABLE_BINDER_MAPPING(AUTO_PARCELABLE_WRITE_TO_PARCEL)
-    } else if constexpr (std::is_same_v<D, std::string>) {
-      return parcel->writeUtf8AsUtf16(value);
-    } else {
-      STATIC_FAIL(D, "Unsupported type: Add more manual type conversions above^^^");
-    }
-
-#undef AUTO_PARCELABLE_WRITE_TO_PARCEL
-  }
-
-  template <typename F>
-  static auto readAnyFromParcel(const Parcel* parcel) {
-    // returns pair(status_t, ~F~)
-    using namespace android;
-
-    // Since 'F' is almost always an lvalue reference (due to F=decltype(auto&&),
-    // we should lose the references, and also any consts.
-    using D = std::decay_t<F>;
-
-    D value;
-    status_t result;
-
-    if constexpr (std::is_base_of_v<Parcelable, D>) {
-      status_t result = value.readFromParcel(/*in*/parcel);
-    } else if constexpr (std::is_enum_v<D>) {
-      auto&& [res, val] = readAnyFromParcel<std::underlying_type_t<D>>(parcel);
-      result = res;
-      value = static_cast<D>(val);
-#define AUTO_PARCELABLE_READ_FROM_PARCEL(fn_name, type_name) \
-    } else if constexpr (std::is_same_v<D, std::decay_t<type_name>>) { \
-      result = parcel->read ## fn_name (/*out*/&value);
-AUTO_PARCELABLE_BINDER_MAPPING(AUTO_PARCELABLE_READ_FROM_PARCEL)
-    } else if constexpr (std::is_same_v<D, std::string>) {
-      result = parcel->readUtf8FromUtf16(/*out*/&value);
-    } else {
-      STATIC_FAIL(D, "Unsupported type: Add more manual type conversions above^^^");
-    }
-#undef AUTO_PARCELABLE_READ_FROM_PARCEL
-
-    return std::make_pair(result, std::move(value));
-  }
-
-  T* Self() {
-    return static_cast<T*>(this);
-  }
-  const T* Self() const {
-    return static_cast<const T*>(this);
-  }
-};
-
-}  // namespace binder
-}  // namespace iorap
-
-#endif  // IORAP_BINDER_AUTO_PARCELABLE_H_
diff --git a/include/binder/common.h b/include/binder/common.h
deleted file mode 100644
index f31e1e9..0000000
--- a/include/binder/common.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_BINDER_COMMON_H_
-#define IORAP_BINDER_COMMON_H_
-
-// AIDL has no way to specify a custom C++ namespace for parcelables.
-//
-// We want our parcelables to live in the ::iorap::binder namespace,
-//   not in com.google.android.startop.iorap
-// So this macro is just a short-hand for doing an alias across namespaces.
-#define IORAP_JAVA_NAMESPACE_BINDER_TYPEDEF(what) \
-namespace com { namespace google { namespace android { namespace startop { namespace iorap { using what = ::iorap::binder::what; } } } } }
-
-#endif  // IORAP_BINDER_COMMON_H_
diff --git a/include/binder/dexopt_event.h b/include/binder/dexopt_event.h
deleted file mode 100644
index cb506f4..0000000
--- a/include/binder/dexopt_event.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_BINDER_DEXOPT_EVENT_H_
-#define IORAP_BINDER_DEXOPT_EVENT_H_
-
-#include "binder/common.h"
-#include "binder/auto_parcelable.h"
-#include "common/introspection.h"
-
-namespace iorap {
-namespace binder {
-
-struct DexOptEvent : public AutoParcelable<DexOptEvent> {
-  enum class Type : int32_t {
-    kPackageUpdate = 0,
-  };
-
-  Type type;
-  std::string package_name;
-};
-
-IORAP_INTROSPECT_ADAPT_STRUCT(DexOptEvent, type, package_name);
-
-}
-}
-IORAP_JAVA_NAMESPACE_BINDER_TYPEDEF(DexOptEvent)
-
-#endif  // IORAP_BINDER_DEXOPT_EVENT_H_
diff --git a/include/binder/job_scheduled_event.h b/include/binder/job_scheduled_event.h
deleted file mode 100644
index 6b067d7..0000000
--- a/include/binder/job_scheduled_event.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_BINDER_JOB_SCHEDULED_EVENT_H_
-#define IORAP_BINDER_JOB_SCHEDULED_EVENT_H_
-
-#include "binder/common.h"
-#include "binder/auto_parcelable.h"
-#include "common/introspection.h"
-
-namespace iorap {
-namespace binder {
-
-struct JobScheduledEvent : public AutoParcelable<JobScheduledEvent> {
-  enum class Type : int32_t {
-    kStartJob = 0,
-    kStopJob = 1,
-  };
-
-  Type type;
-  int32_t job_id;
-  std::string package_name;
-  bool should_update_versions;
-
-  enum class Sort : int32_t {
-    kIdleMaintenance = 0,
-  };
-
-  Sort sort;
-
-  constexpr bool operator==(const JobScheduledEvent& other) const {
-    return type == other.type
-        && job_id == other.job_id
-        && sort == other.sort
-        && package_name == other.package_name
-        && should_update_versions == other.should_update_versions;
-  }
-
-  constexpr bool operator!=(const JobScheduledEvent& other) const {
-    return !(*this == other);
-  }
-};
-
-IORAP_INTROSPECT_ADAPT_STRUCT(
-    JobScheduledEvent, type, job_id, sort, package_name, should_update_versions);
-
-}
-}
-IORAP_JAVA_NAMESPACE_BINDER_TYPEDEF(JobScheduledEvent)
-
-#endif  // IORAP_BINDER_JOB_SCHEDULED_EVENT_H_
diff --git a/include/binder/package_event.h b/include/binder/package_event.h
deleted file mode 100644
index d8d7933..0000000
--- a/include/binder/package_event.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_BINDER_PACKAGE_EVENT_H_
-#define IORAP_BINDER_PACKAGE_EVENT_H_
-
-#include "binder/common.h"
-#include "binder/auto_parcelable.h"
-#include "common/introspection.h"
-
-namespace iorap {
-namespace binder {
-
-struct PackageEvent : public AutoParcelable<PackageEvent> {
-  enum class Type : int32_t {
-    kReplaced = 0,
-  };
-
-  Type type;
-  std::string package_uri;
-  std::string package_name;
-};
-
-IORAP_INTROSPECT_ADAPT_STRUCT(PackageEvent, type, package_uri, package_name);
-
-}
-}
-IORAP_JAVA_NAMESPACE_BINDER_TYPEDEF(PackageEvent)
-
-#endif  // IORAP_BINDER_PACKAGE_EVENT_H_
diff --git a/include/binder/request_id.h b/include/binder/request_id.h
deleted file mode 100644
index 71a2edd..0000000
--- a/include/binder/request_id.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_BINDER_REQUEST_ID_H_
-#define IORAP_BINDER_REQUEST_ID_H_
-
-#include "binder/common.h"
-#include "binder/auto_parcelable.h"
-
-namespace iorap {
-namespace binder {
-
-struct RequestId : public AutoParcelable<RequestId> {
-  int64_t request_id;
-
-  constexpr bool operator==(const RequestId& other) const {
-    return request_id == other.request_id;
-  }
-
-  constexpr bool operator!=(const RequestId& other) const {
-    return !(*this == other);
-  }
-};
-
-IORAP_INTROSPECT_ADAPT_STRUCT(RequestId, request_id);
-
-}
-}
-IORAP_JAVA_NAMESPACE_BINDER_TYPEDEF(RequestId)
-
-#endif  // IORAP_BINDER_REQUEST_ID_H_
diff --git a/include/binder/system_service_event.h b/include/binder/system_service_event.h
deleted file mode 100644
index a82c200..0000000
--- a/include/binder/system_service_event.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_BINDER_SYSTEM_SERVICE_EVENT_H_
-#define IORAP_BINDER_SYSTEM_SERVICE_EVENT_H_
-
-#include "binder/common.h"
-#include "binder/auto_parcelable.h"
-#include "common/introspection.h"
-
-namespace iorap {
-namespace binder {
-
-struct SystemServiceEvent : public AutoParcelable<SystemServiceEvent> {
-  enum class Type : int32_t {
-    kBootPhase = 0,
-    kStart = 1,
-  };
-
-  Type type;
-};
-
-IORAP_INTROSPECT_ADAPT_STRUCT(SystemServiceEvent, type);
-
-}
-}
-IORAP_JAVA_NAMESPACE_BINDER_TYPEDEF(SystemServiceEvent)
-
-#endif  // IORAP_BINDER_SYSTEM_SERVICE_EVENT_H_
diff --git a/include/binder/system_service_user_event.h b/include/binder/system_service_user_event.h
deleted file mode 100644
index 43f92ea..0000000
--- a/include/binder/system_service_user_event.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_BINDER_SYSTEM_SERVICE_USER_EVENT_H_
-#define IORAP_BINDER_SYSTEM_SERVICE_USER_EVENT_H_
-
-#include "binder/common.h"
-#include "binder/auto_parcelable.h"
-#include "common/introspection.h"
-
-namespace iorap {
-namespace binder {
-
-struct SystemServiceUserEvent : public AutoParcelable<SystemServiceUserEvent> {
-  enum class Type : int32_t {
-    kStartUser = 0,
-    kUnlockUser,
-    kSwitchUser,
-    kStopUser,
-    kCleanupUser,
-  };
-
-  Type type;
-  int32_t user_handle;
-};
-
-IORAP_INTROSPECT_ADAPT_STRUCT(SystemServiceUserEvent, type, user_handle);
-
-}
-}
-IORAP_JAVA_NAMESPACE_BINDER_TYPEDEF(SystemServiceUserEvent)
-
-#endif  // IORAP_BINDER_SYSTEM_SERVICE_USER_EVENT_H_
diff --git a/include/binder/task_result.h b/include/binder/task_result.h
deleted file mode 100644
index b060f3f..0000000
--- a/include/binder/task_result.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_BINDER_TASK_RESULT_H_
-#define IORAP_BINDER_TASK_RESULT_H_
-
-#include "binder/common.h"
-#include "binder/auto_parcelable.h"
-#include "common/introspection.h"
-
-namespace iorap {
-namespace binder {
-
-struct TaskResult : public AutoParcelable<TaskResult> {
-  enum class State : int32_t {
-    kBegan = 0,
-    kOngoing = 1,
-    kCompleted = 2,
-    kError = 3,
-    kMax = kError,
-  };
-
-  State state;
-
-  TaskResult() = default;
-  explicit TaskResult(State state) : state(state) {}
-
-  constexpr bool operator==(const TaskResult& other) const {
-    return state == other.state;
-  }
-
-  constexpr bool operator!=(const TaskResult& other) const {
-    return !(*this == other);
-  }
-};
-
-IORAP_INTROSPECT_ADAPT_STRUCT(TaskResult, state);
-
-}
-}
-IORAP_JAVA_NAMESPACE_BINDER_TYPEDEF(TaskResult)
-
-#endif  // IORAP_BINDER_TASK_RESULT_H_
diff --git a/iorapd.rc b/iorapd.rc
deleted file mode 100644
index cb887ac..0000000
--- a/iorapd.rc
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-service iorapd /system/bin/iorapd
-    class main
-    disabled
-    user iorapd
-    group iorapd
-    capabilities DAC_READ_SEARCH
-    writepid /dev/cpuset/system-background/tasks
-# TODO: should this be something else like performance/tasks?
-# the main 'activity hint' thread needs to be fairly high priority to kick off
-# tracing or prefetching asap.
-
-on property:ro.iorapd.enable=false
-    stop iorapd
-
-on post-fs-data
-    # Create directory for iorapd (see iorapd_data_file in selinux file_contexts).
-    mkdir /data/misc/iorapd/ 0750 iorapd system
-
-# Start iorapd when either prefetching or tracing is enabled.
-on property:persist.device_config.runtime_native_boot.iorap_perfetto_enable=true && property:ro.iorapd.enable=true
-    start iorapd
-
-on property:persist.device_config.runtime_native_boot.iorap_readahead_enable=true && property:ro.iorapd.enable=true
-    start iorapd
diff --git a/seccomp_policy/prefetcherd.arm.policy b/seccomp_policy/prefetcherd.arm.policy
deleted file mode 120000
index a4642af..0000000
--- a/seccomp_policy/prefetcherd.arm.policy
+++ /dev/null
@@ -1 +0,0 @@
-prefetcherd.arm64.policy
\ No newline at end of file
diff --git a/seccomp_policy/prefetcherd.arm64.policy b/seccomp_policy/prefetcherd.arm64.policy
deleted file mode 100644
index a796ad1..0000000
--- a/seccomp_policy/prefetcherd.arm64.policy
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# main usage: fadvise to prefetch data
-fadvise64: 1
-
-# bionic's fdsan requires this
-getrlimit: 1
-
-@include /system/etc/seccomp_policy/crash_dump.arm64.policy
diff --git a/seccomp_policy/prefetcherd.x86.policy b/seccomp_policy/prefetcherd.x86.policy
deleted file mode 120000
index a4642af..0000000
--- a/seccomp_policy/prefetcherd.x86.policy
+++ /dev/null
@@ -1 +0,0 @@
-prefetcherd.arm64.policy
\ No newline at end of file
diff --git a/seccomp_policy/prefetcherd.x86_64.policy b/seccomp_policy/prefetcherd.x86_64.policy
deleted file mode 120000
index a4642af..0000000
--- a/seccomp_policy/prefetcherd.x86_64.policy
+++ /dev/null
@@ -1 +0,0 @@
-prefetcherd.arm64.policy
\ No newline at end of file
diff --git a/src/binder/iiorap_def.h b/src/binder/iiorap_def.h
deleted file mode 100644
index 5763380..0000000
--- a/src/binder/iiorap_def.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IIORAP_IFACE_DEF_H
-#define IIORAP_IFACE_DEF_H
-
-// Provide an x-macro that defines the 'IIorap.aidl' interface through repeated
-// macro invocation on the member functions and their respective parameters.
-//
-// Future changes in the AIDL file to add new methods or change parameters should avoid
-// a boilerplate-ripple effect in the rest of the codebase.
-
-#define IIORAP_IFACE_DEF(FN_BEGIN, FN, FN_END)                                                     \
-FN_BEGIN(::com::google::android::startup::iorap::,IIorap)                                          \
-/* name              <see IORAP_BINDER_PARAM_JOIN> */                                              \
-FN(setTaskListener, (const ::android::sp<::com::google::android::startop::iorap::,ITaskListener,>&,listener)) /*NOLINT*/ \
-FN(onAppLaunchEvent,(const ::com::google::android::startop::iorap::,RequestId,&,request),          \
-                    (const ::com::google::android::startop::iorap::,AppLaunchEvent,&,event))       \
-FN(onJobScheduledEvent,                                                                            \
-                    (const ::com::google::android::startop::iorap::,RequestId,&,request),          \
-                    (const ::com::google::android::startop::iorap::,JobScheduledEvent,&,event))    \
-FN(onPackageEvent,  (const ::com::google::android::startop::iorap::,RequestId,&,request),          \
-                    (const ::com::google::android::startop::iorap::,PackageEvent,&,event))         \
-FN(onAppIntentEvent,(const ::com::google::android::startop::iorap::,RequestId,&,request),          \
-                    (const ::com::google::android::startop::iorap::,AppIntentEvent,&,event))       \
-FN(onSystemServiceEvent,                                                                           \
-                    (const ::com::google::android::startop::iorap::,RequestId,&,request),          \
-                    (const ::com::google::android::startop::iorap::,SystemServiceEvent,&,event))   \
-FN(onSystemServiceUserEvent,                                                                       \
-                    (const ::com::google::android::startop::iorap::,RequestId,&,request),          \
-                    (const ::com::google::android::startop::iorap::,SystemServiceUserEvent,&,event))\
-FN(onDexOptEvent,   (const ::com::google::android::startop::iorap::,RequestId,&,request),          \
-                    (const ::com::google::android::startop::iorap::,DexOptEvent,&,event))          \
-FN_END()                                                                                           \
-
-// Convenience macros to unpack the 2nd parameter from IIORAP_IFACE_DEF#FN calls.
-
-#define IORAP_BINDER_PARAM_JOIN_ALL(arg) IORAP_BINDER_PARAM_JOIN_ALL_IMPL arg
-#define IORAP_BINDER_PARAM_JOIN_ALL_IMPL(type_l, type, type_r, name) type_l type type_r name
-
-#define IORAP_BINDER_PARAM_JOIN_NAMES(arg) IORAP_BINDER_PARAM_JOIN_NAMES_IMPL arg
-#define IORAP_BINDER_PARAM_JOIN_NAMES_IMPL(type_l, type, type_r, name) name
-
-#endif //IIORAP_IFACE_DEF_H
diff --git a/src/binder/iiorap_impl.cc b/src/binder/iiorap_impl.cc
deleted file mode 100644
index 13adcc0..0000000
--- a/src/binder/iiorap_impl.cc
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "binder/iiorap_impl.h"
-#include "binder/iiorap_def.h"
-#include "common/macros.h"
-#include "manager/event_manager.h"
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <binder/BinderService.h>
-#include <binder/IPCThreadState.h>
-#include <include/binder/request_id.h>
-#include <utils/Printer.h>
-
-#include <codecvt>
-#include <locale>
-#include <utility>
-
-/*
- * Definitions for the IIorap binder native service implementation.
- * See also IIorap.aidl.
- */
-
-using Status = ::android::binder::Status;
-using ITaskListener = ::com::google::android::startop::iorap::ITaskListener;
-
-namespace iorap {
-namespace binder {
-
-namespace {
-// Forward declarations.
-template<typename ... Args>
-Status Send(const char* function_name, Args&& ... args);
-}
-
-// Join all parameter declarations by splitting each parameter with a comma.
-// Types are used fully.
-#define IIORAP_IMPL_ARG_DECLARATIONS(...) \
-  IORAP_PP_MAP_SEP(IORAP_BINDER_PARAM_JOIN_ALL, IORAP_PP_COMMA, __VA_ARGS__)
-#define IIORAP_IMPL_ARG_NAMES(...) \
-  IORAP_PP_MAP_SEP(IORAP_BINDER_PARAM_JOIN_NAMES, IORAP_PP_COMMA, __VA_ARGS__)
-#define IIORAP_IMPL_BODY(name, ...)                                                                \
-  ::android::binder::Status IIorapImpl::name(IIORAP_IMPL_ARG_DECLARATIONS(__VA_ARGS__)) {          \
-    return Send(#name, impl_.get(), IIORAP_IMPL_ARG_NAMES(__VA_ARGS__));                           \
-  }
-
-IIORAP_IFACE_DEF(/*begin*/IORAP_PP_NOP, IIORAP_IMPL_BODY, /*end*/IORAP_PP_NOP);
-
-#undef IIORAP_IMPL_BODY
-#undef IIORAP_IMPL_ARG_NAMES
-#undef IIORAP_IMPL_ARGS
-
-namespace {
-
-struct ServiceParams {
-  bool fake_{false};
-  std::shared_ptr<manager::EventManager> event_manager_;
-};
-
-static std::atomic<bool> s_service_started_{false};
-static std::atomic<bool> s_service_params_ready_{false};
-
-// TODO: BinderService constructs IIorapImpl,
-// but how do I get a pointer to it afterwards?
-//
-// This is a workaround for that, by using a global.
-static ServiceParams s_service_params_;
-static std::atomic<ServiceParams*> s_service_params_atomic_;
-
-// Convert an android::String16 (UTF-16) to a UTF-8 std::string.
-static std::string String16ToStdString(const ::android::String16& s16) {
-  std::u16string u16{s16.string()};
-  std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
-
-  std::string res = convert.to_bytes(u16);
-  return res;
-}
-
-}  // namespace anonymous
-
-class IIorapImpl::Impl {
-  // ITaskListener implementation for iorap::manager::EventManager.
-  struct EventManagerTaskCallbacks : public iorap::manager::TaskResultCallbacks {
-    explicit EventManagerTaskCallbacks(iorap::borrowed<IIorapImpl::Impl*> impl) {
-      CHECK(impl != nullptr);
-      impl_ = impl;
-    }
-
-    virtual void OnProgress(iorap::binder::RequestId request_id, iorap::binder::TaskResult task_result) override {
-      impl_->ReplyWithResult(request_id, /*completed*/false, std::move(task_result));
-    }
-    virtual void OnComplete(iorap::binder::RequestId request_id, iorap::binder::TaskResult task_result) override {
-      impl_->ReplyWithResult(request_id, /*completed*/true, std::move(task_result));
-    }
-
-    virtual ~EventManagerTaskCallbacks() {}
-
-    iorap::borrowed<IIorapImpl::Impl*> impl_;
-  };
-
- public:
-  ~Impl() {
-    package_manager_->UnregisterPackageChangeObserver(package_change_observer_);
-  }
-
-  void SetTaskListener(const ::android::sp<ITaskListener>& listener) {
-    ::android::sp<ITaskListener> old_listener = listener_;
-    if (old_listener != nullptr && listener != nullptr) {
-      LOG(WARNING) << "IIorap::setTaskListener: already had a task listener set";
-    }
-    listener_ = listener;
-  }
-
-  void ReplyWithResult(const RequestId& request_id, TaskResult::State result_state) {
-    ::android::sp<ITaskListener> listener = listener_;
-    if (listener == nullptr) {
-      // No listener. Cannot send anything back to the client.
-      // This could be normal, e.g. client had set listener to null before disconnecting.
-      LOG(DEBUG) << "Drop result, no listener registered.";
-      // TODO: print the result with ostream operator<<
-      return;
-    }
-
-    TaskResult result;
-    result.state = result_state;
-
-    // TODO: verbose, not info.
-    if (result_state == TaskResult::State::kCompleted) {
-      LOG(VERBOSE) << "ITaskListener::onComplete (request_id=" << request_id.request_id << ")";
-      listener->onComplete(request_id, result);
-    } else {
-      LOG(VERBOSE) << "ITaskListener::onProgress (request_id=" << request_id.request_id << ")";
-      listener->onProgress(request_id, result);
-    }
-  }
-
-  void ReplyWithResult(const RequestId& request_id, bool completed, TaskResult result) {
-    ::android::sp<ITaskListener> listener = listener_;
-    if (listener == nullptr) {
-      // No listener. Cannot send anything back to the client.
-      // This could be normal, e.g. client had set listener to null before disconnecting.
-      LOG(DEBUG) << "Drop result, no listener registered.";
-      // TODO: print the result with ostream operator<<
-      return;
-    }
-
-    // TODO: verbose, not info.
-    if (completed) {
-      LOG(VERBOSE) << "ITaskListener::onComplete (request_id=" << request_id.request_id << ")";
-      listener->onComplete(request_id, result);
-    } else {
-      LOG(VERBOSE) << "ITaskListener::onProgress (request_id=" << request_id.request_id << ")";
-      listener->onProgress(request_id, result);
-    }
-  }
-
-  bool OnAppLaunchEvent(const RequestId& request_id,
-                        const AppLaunchEvent& event) {
-    if (MaybeHandleFakeBehavior(request_id)) {
-      return true;
-    }
-
-    return service_params_.event_manager_->OnAppLaunchEvent(request_id, event);
-  }
-
-  bool OnDexOptEvent(const RequestId& request_id, const DexOptEvent& event) {
-    if (MaybeHandleFakeBehavior(request_id)) {
-      return true;
-    }
-
-    return service_params_.event_manager_->OnDexOptEvent(request_id, event);
-  }
-
-  bool  OnJobScheduledEvent(const RequestId& request_id,
-                            const JobScheduledEvent& event) {
-    if (MaybeHandleFakeBehavior(request_id)) {
-      return true;
-    }
-
-    return service_params_.event_manager_->OnJobScheduledEvent(request_id, event);
-  }
-
-  void Dump(/*borrow*/::android::Printer& printer,
-            const ::android::Vector<::android::String16>& args) {
-
-    if (args.size() == 0) {
-      service_params_.event_manager_->Dump(/*borrow*/printer);
-      return;
-    }
-
-    ::android::String16 arg_prev;
-    for (const ::android::String16& arg : args) {
-      bool unknown = false;
-      if (arg == ::android::String16("--all") || arg == ::android::String16("-a")) {
-        // using 'dumpsys' or 'bugreport' passes a single '-a' flag to this function.
-        service_params_.event_manager_->Dump(/*borrow*/printer);
-      } else if (arg == ::android::String16("--refresh-properties")) {
-        service_params_.event_manager_->RefreshSystemProperties(/*borrow*/printer);
-        printer.printLine("System properties refreshed.");
-      } else if (arg == ::android::String16("--compile-package")) {
-        // Intentionally left blank.
-      } else if (arg_prev == ::android::String16("--compile-package")) {
-        std::string package_name = String16ToStdString(arg);
-
-        if (!service_params_.event_manager_->CompilePackage(/*borrow*/printer, package_name)) {
-          printer.printFormatLine("Failed to compile package %s.", package_name.c_str());
-        } else {
-          printer.printFormatLine("Package %s compiled.", package_name.c_str());
-        }
-      } else if (arg == ::android::String16("--purge-package")) {
-        // Intentionally left blank.
-      } else if (arg_prev == ::android::String16("--purge-package")) {
-        std::string package_name = String16ToStdString(arg);
-
-        if (!service_params_.event_manager_->PurgePackage(/*borrow*/printer, package_name)) {
-          printer.printFormatLine("Failed to purge package %s.", package_name.c_str());
-        } else {
-          printer.printFormatLine("Package %s purged.", package_name.c_str());
-        }
-      } else {
-        unknown = true;
-      }
-
-      if (unknown && arg != ::android::String16("--help")) {
-        printer.printLine("Invalid arguments.");
-        printer.printLine("");
-
-        printer.printLine("Arguments were:");
-        for (const ::android::String16& arg16 : args) {
-          printer.printFormatLine("  '%s'", String16ToStdString(arg16).c_str());
-        }
-        printer.printLine("");
-      }
-
-      if (unknown || arg == ::android::String16("--help")) {
-        printer.printLine("Iorapd dumpsys commands:");
-        printer.printLine("  (none),--all,-a: Print state information for debugging iorapd.");
-        printer.printLine("  --help: Display this help menu");
-        printer.printLine("  --compile-package <name>: Compile single package on device");
-        printer.printLine("  --purge-package <name>: Delete database entries/files for package");
-        printer.printLine("  --refresh-properties: Refresh system properties");
-        return;
-      }
-
-      arg_prev = arg;
-    }
-  }
-
-  void HandleFakeBehavior(const RequestId& request_id) {
-    DCHECK(service_params_.fake_);
-
-    // Send these dummy callbacks for testing only.
-    ReplyWithResult(request_id, TaskResult::State::kBegan);
-    ReplyWithResult(request_id, TaskResult::State::kOngoing);
-    ReplyWithResult(request_id, TaskResult::State::kCompleted);
-  }
-
-  // TODO: Subclass IIorap with a separate fake implementation.
-  bool MaybeHandleFakeBehavior(const RequestId& request_id) {
-    if (service_params_.fake_) {
-      HandleFakeBehavior(request_id);
-      return true;
-    }
-
-    return false;
-  }
-
-  ::android::sp<ITaskListener> listener_;
-
-  Impl(ServiceParams p) : service_params_{std::move(p)}, event_manager_callbacks_{new EventManagerTaskCallbacks{this}} {
-    CHECK(service_params_.event_manager_ != nullptr);
-
-    service_params_.event_manager_->SetTaskResultCallbacks(
-      std::static_pointer_cast<manager::TaskResultCallbacks>(event_manager_callbacks_));
-
-    // Init the package change observer.
-    package_manager_ = PackageManagerRemote::Create();
-
-    if (package_manager_ == nullptr) {
-      LOG(ERROR) << "Failed to get package manager service in IIorapImpl::Impl."
-                 << " Is system_server down?";
-      exit(1);
-    }
-
-    package_change_observer_ =
-        new PackageChangeObserver(service_params_.event_manager_);
-    package_manager_death_recipient_ =
-        new PackageManagerDeathRecipient(package_manager_, package_change_observer_);
-
-    package_manager_->RegisterPackageChangeObserver(package_change_observer_);
-    package_manager_->
-        RegisterPackageManagerDeathRecipient(package_manager_death_recipient_);
-
-  }
-
-  ServiceParams service_params_;
-  std::shared_ptr<EventManagerTaskCallbacks> event_manager_callbacks_;
-  android::sp<PackageChangeObserver> package_change_observer_;
-  android::sp<PackageManagerDeathRecipient> package_manager_death_recipient_;
-  std::shared_ptr<PackageManagerRemote> package_manager_;
-};
-
-using Impl = IIorapImpl::Impl;
-
-IIorapImpl::IIorapImpl() {
-  // Acquire edge of synchronizes-with IIorapImpl::Start().
-  CHECK(s_service_params_ready_.load());
-  // Do not turn this into a DCHECK, the above atomic load
-  // must happen-before the read of s_service_params_ready_.
-  impl_.reset(new Impl(std::move(s_service_params_)));
-}
-
-namespace {
-  static bool started_ = false;
-}
-bool IIorapImpl::Start(std::shared_ptr<manager::EventManager> event_manager) {
-  if (s_service_started_.load()) {  // Acquire-edge (see bottom of function).
-    // Note: Not meant to be idempotent. Two threads could race, and the second
-    // one would likely fail the publish.
-
-    LOG(ERROR) << "service was already started";
-    return false;  // Already started
-  }
-
-  CHECK(event_manager != nullptr);
-
-  {
-    // This block of code needs to happen-before IIorapImpl::IIorapImpl.
-
-    // TODO: There should be a simpler way of passing down
-    // this data which doesn't involve globals and memory synchronization.
-    ServiceParams* p = &s_service_params_;
-    // TODO: move all property reads to a dedicated Config class.
-    p->fake_ = ::android::base::GetBoolProperty("iorapd.binder.fake", /*default*/false);
-    p->event_manager_ = std::move(event_manager);
-
-    // Release edge of synchronizes-with IIorapImpl::IIorapImpl.
-    s_service_params_ready_.store(true);
-  }
-
-  ::android::IPCThreadState::self()->disableBackgroundScheduling(/*disable*/true);
-  ::android::status_t ret = android::BinderService<IIorapImpl>::publish();
-  if (ret != android::OK) {
-    LOG(ERROR) << "BinderService::publish failed with error code: " << ret;
-    return false;
-  }
-
-  android::sp<android::ProcessState> ps = android::ProcessState::self();
-  // Reduce thread consumption by only using 1 thread.
-  // We should also be able to leverage this by avoiding locks, etc.
-  ps->setThreadPoolMaxThreadCount(/*maxThreads*/1);
-  ps->startThreadPool();
-  ps->giveThreadPoolName();
-
-  // Release edge synchronizes-with the top of this function.
-  s_service_started_.store(true);
-
-  // TODO: IIRC thread-start(t1) synchronizes-with t1.main, so we should be able
-  // to delete the majority of atomics for any pre-thread-start initialization...
-
-  return true;
-}
-
-::android::status_t IIorapImpl::dump(int fd, const ::android::Vector<::android::String16>& args) {
-
-  ::android::FdPrinter printer{fd};
-
-  impl_->Dump(printer, args);
-
-  return ::android::NO_ERROR;
-}
-
-namespace {
-
-#define MAYBE_HAVE_FAKE_BEHAVIOR(self, request_id) \
-  if (self->MaybeHandleFakeBehavior(request_id)) { return ::android::binder::Status::ok(); }
-
-template <typename ... Args>
-Status SendArgs(const char* function_name,
-                Impl* self,
-                const RequestId& request_id,
-                Args&&... /*rest*/) {
-  LOG(VERBOSE) << "IIorap::" << function_name << " (request_id = " << request_id.request_id << ")";
-
-  MAYBE_HAVE_FAKE_BEHAVIOR(self, request_id);
-
-  // TODO: implementation.
-  LOG(ERROR) << "IIorap::" << function_name << " -- not implemented for real code";
-  return Status::fromStatusT(::android::INVALID_OPERATION);
-}
-
-template <typename ... Args>
-Status SendArgs(const char* function_name, Impl* self, Args&&... rest) {
-  DCHECK_EQ(std::string(function_name), "setTaskListener");
-  LOG(VERBOSE) << "IIorap::setTaskListener";
-  self->SetTaskListener(std::forward<Args&&>(rest)...);
-
-  return Status::ok();
-}
-
-template <typename ... Args>
-Status SendArgs(const char* function_name,
-                Impl* self,
-                const RequestId& request_id,
-                const AppLaunchEvent& app_launch_event) {
-  DCHECK_EQ(std::string(function_name), "onAppLaunchEvent");
-  LOG(VERBOSE) << "IIorap::onAppLaunchEvent";
-
-  MAYBE_HAVE_FAKE_BEHAVIOR(self, request_id);
-
-  if (self->OnAppLaunchEvent(request_id, app_launch_event)) {
-    return Status::ok();
-  } else {
-    // TODO: I suppose this should write out an exception back,
-    // like a service-specific error or something.
-    //
-    // It depends on whether or not we even have any synchronous
-    // errors.
-    //
-    // Most of the work here is done async, so it should handle
-    // async callbacks.
-    return Status::fromStatusT(::android::BAD_VALUE);
-  }
-}
-
-template <typename ... Args>
-Status SendArgs(const char* function_name,
-                Impl* self,
-                const RequestId& request_id,
-                const DexOptEvent& event) {
-  DCHECK_EQ(std::string(function_name), "onDexOptEvent");
-  LOG(VERBOSE) << "IIorap::onDexOptEvent";
-
-  MAYBE_HAVE_FAKE_BEHAVIOR(self, request_id);
-
-  if (self->OnDexOptEvent(request_id, event)) {
-    return Status::ok();
-  } else {
-    return Status::fromStatusT(::android::BAD_VALUE);
-  }
-}
-
-template <typename ... Args>
-Status SendArgs(const char* function_name,
-                Impl* self,
-                const RequestId& request_id,
-                const JobScheduledEvent& event) {
-  DCHECK_EQ(std::string(function_name), "onJobScheduledEvent");
-  LOG(VERBOSE) << "IIorap::onJobScheduledEvent";
-
-  MAYBE_HAVE_FAKE_BEHAVIOR(self, request_id);
-
-  if (self->OnJobScheduledEvent(request_id, event)) {
-    return Status::ok();
-  } else {
-    // TODO: I suppose this should write out an exception back,
-    // like a service-specific error or something.
-    //
-    // It depends on whether or not we even have any synchronous
-    // errors.
-    //
-    // Most of the work here is done async, so it should handle
-    // async callbacks.
-    return Status::fromStatusT(::android::BAD_VALUE);
-  }
-}
-
-template <typename ... Args>
-Status Send(const char* function_name, Args&&... args) {
-  LOG(VERBOSE) << "IIorap::Send(" << function_name << ")";
-
-  return SendArgs(function_name, std::forward<Args>(args)...);
-}
-}  // namespace <anonymous>
-
-}  // namespace binder
-}  // namespace iorap
diff --git a/src/binder/iiorap_impl.h b/src/binder/iiorap_impl.h
deleted file mode 100644
index ae1422f..0000000
--- a/src/binder/iiorap_impl.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_BINDER_IIORAP_IMPL_H
-#define IORAP_BINDER_IIORAP_IMPL_H
-
-#include "binder/iiorap_def.h"
-#include "binder/package_change_observer.h"
-#include "binder/package_manager_remote.h"
-#include "common/macros.h"
-
-#include "com/google/android/startop/iorap/BnIorap.h"
-
-#include <memory>
-
-namespace android {
-template <typename Service>
-class BinderService;
-}
-
-namespace iorap::manager {
-  class EventManager;
-};
-
-namespace iorap {
-namespace binder {
-
-// Implementation of the IIorap service. This enables remote clients
-// to connect to this process via the binder service manager.
-//
-// See also IIorap.aidl.
-class IIorapImpl : public ::com::google::android::startop::iorap::BnIorap {
-public:
-  static bool Start(std::shared_ptr<iorap::manager::EventManager> event_manager);
-  static constexpr const char* getServiceName() { return "iorapd"; };
-
-  virtual ::android::status_t dump(int fd,
-                                   const ::android::Vector<::android::String16>& args) override;
-
-// Join all parameter declarations by splitting each parameter with a comma.
-// Types are used fully.
-#define IIORAP_IMPL_ARGS(...) \
-  IORAP_PP_MAP_SEP(IORAP_BINDER_PARAM_JOIN_ALL, IORAP_PP_COMMA, __VA_ARGS__)
-#define IIORAP_IMPL_BODY(name, ...) \
-  ::android::binder::Status name(IIORAP_IMPL_ARGS(__VA_ARGS__)) override;
-
-IIORAP_IFACE_DEF(/*begin*/IORAP_PP_NOP, IIORAP_IMPL_BODY, /*end*/IORAP_PP_NOP);
-
-#undef IIORAP_IMPL_BODY
-#undef IIORAP_IMPL_ARGS
-
-  class Impl;
-private:
-  IIorapImpl();  // open for BinderService::publish.
-
-  friend class ::android::BinderService<IIorapImpl>;
-
-  std::unique_ptr<Impl> impl_;
-};
-}
-}
-
-
-#endif //IORAP_BINDER_IIORAP_IMPL_H
diff --git a/src/binder/package_change_observer.cc b/src/binder/package_change_observer.cc
deleted file mode 100644
index 1907af8..0000000
--- a/src/binder/package_change_observer.cc
+++ /dev/null
@@ -1,37 +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 "package_change_observer.h"
-#include "package_manager_remote.h"
-#include "manager/event_manager.h"
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-
-namespace iorap::binder {
-
-PackageChangeObserver::PackageChangeObserver(
-    std::shared_ptr<iorap::manager::EventManager> event_manager) :
-  event_manager_(event_manager){}
-
-android::binder::Status PackageChangeObserver::onPackageChanged(
-  const android::content::pm::PackageChangeEvent& event) {
-  LOG(DEBUG) << "Received PackageChangeObserver::onPackageChanged";
-  if (event_manager_->OnPackageChanged(event)) {
-    return android::binder::Status::ok();
-  } else {
-    return android::binder::Status::fromStatusT(android::BAD_VALUE);
-  }
-}
-}  // namespace iorap::binder
diff --git a/src/binder/package_change_observer.h b/src/binder/package_change_observer.h
deleted file mode 100644
index ac488ac..0000000
--- a/src/binder/package_change_observer.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_PACKAGE_CHANGE_OBSERVER_H_
-#define IORAP_SRC_PACKAGE_CHANGE_OBSERVER_H_
-
-#include "binder/iiorap_def.h"
-
-#include <android/content/pm/BnPackageChangeObserver.h>
-#include <android/content/pm/PackageChangeEvent.h>
-#include <android/content/pm/IPackageManagerNative.h>
-
-namespace iorap::manager {
-  class EventManager;
-};
-
-namespace iorap::binder {
-
-class PackageChangeObserver : public android::content::pm::BnPackageChangeObserver  {
- public:
-  PackageChangeObserver(std::shared_ptr<iorap::manager::EventManager> event_manager);
-
-  // Callback when the package is changed.
-  android::binder::Status onPackageChanged(
-      const ::android::content::pm::PackageChangeEvent& event) override;
- private:
-  std::shared_ptr<iorap::manager::EventManager> event_manager_;
-};
-}  // namespace iorap::binder
-
-#endif  // IORAP_SRC_PACKAGE_CHANGE_OBSERVER_H_
diff --git a/src/binder/package_manager_remote.cc b/src/binder/package_manager_remote.cc
deleted file mode 100644
index 46671eb..0000000
--- a/src/binder/package_manager_remote.cc
+++ /dev/null
@@ -1,196 +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 "package_manager_remote.h"
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-
-#include <chrono>
-#include <thread>
-
-namespace iorap::binder {
-
-const constexpr int64_t kTimeoutMs = 60 * 1000; // 1 min
-const constexpr int64_t kIntervalMs = 1000; // 1 sec
-
-std::shared_ptr<PackageManagerRemote> PackageManagerRemote::Create() {
-  std::shared_ptr<PackageManagerRemote> package_manager =
-      std::make_shared<PackageManagerRemote>();
-  if (package_manager->ReconnectWithTimeout(kTimeoutMs)) {
-    return package_manager;
-  }
-  return nullptr;
-}
-
-android::sp<IPackageManager> PackageManagerRemote::GetPackageService() {
-  android::sp<android::IBinder> binder = android::defaultServiceManager()->getService(
-      android::String16{"package_native"});
-  if (binder == nullptr) {
-    LOG(ERROR) << "Cannot get package manager service!";
-    return nullptr;
-  }
-
-  return android::interface_cast<IPackageManager>(binder);
-}
-
-std::optional<int64_t> PackageManagerRemote::GetPackageVersion(
-    const std::string& package_name) {
-  int64_t version_code;
-  android::binder::Status status = InvokeRemote(
-      [this, &version_code, &package_name]() {
-        return package_service_->getVersionCodeForPackage(
-            android::String16(package_name.c_str()), /*out*/&version_code);
-      });
-  if (status.isOk()) {
-    return version_code;
-  } else {
-    LOG(WARNING) << "Failed to get version: "
-                 << status.toString8().c_str()
-                 << " for " << package_name
-                 << ". Retry to connect package manager service.";
-    return std::nullopt;
-  }
-}
-
-std::optional<VersionMap> PackageManagerRemote::GetPackageVersionMap() {
-  VersionMap package_version_map;
-  std::optional<std::vector<std::string>> packages = GetAllPackages();
-  if (!packages) {
-    LOG(DEBUG) << "Failed to get all packages. The package manager may be down.";
-    return std::nullopt;
-  }
-  LOG(DEBUG) << "PackageManagerRemote::GetPackageVersionMap: "
-             << packages->size()
-             << " packages are found.";
-
-  for (const std::string& package : *packages) {
-    std::optional<int64_t> version = GetPackageVersion(package);
-    if (!version) {
-      LOG(DEBUG) << "Cannot get version for " << package
-                 << "Package manager may be down";
-      return std::nullopt;
-    }
-    package_version_map[package] = *version;
-  }
-
-  return package_version_map;
-}
-
-std::optional<std::vector<std::string>> PackageManagerRemote::GetAllPackages() {
-  std::vector<std::string> packages;
-  android::binder::Status status = InvokeRemote(
-      [this, &packages]() {
-        return package_service_->getAllPackages(/*out*/&packages);
-      });
-
-  if (status.isOk()) {
-    return packages;
-  }
-
-  LOG(ERROR) << "Failed to get all packages: " << status.toString8().c_str();
-  return std::nullopt;
-
-}
-
-bool PackageManagerRemote::ReconnectWithTimeout(int64_t timeout_ms) {
-  int64_t count = 0;
-  package_service_ = nullptr;
-  std::chrono::duration interval = std::chrono::milliseconds(1000);
-  std::chrono::duration timeout = std::chrono::milliseconds(timeout_ms);
-
-  while (package_service_ == nullptr) {
-    LOG(WARNING) << "Reconnect to package manager service: " << ++count << " times";
-    package_service_ = GetPackageService();
-    std::this_thread::sleep_for(interval);
-    if (count * interval >= timeout) {
-      LOG(ERROR) << "Fail to create version map in "
-                 << timeout.count()
-                 << " milliseconds."
-                 << " Reason: Failed to connect to package manager service."
-                 << " Is system_server down?";
-      return false;
-    }
-  }
-
-  return true;
-}
-
-template <typename T>
-android::binder::Status PackageManagerRemote::InvokeRemote(T&& lambda) {
-  android::binder::Status status =
-      static_cast<android::binder::Status>(lambda());
-  if (status.isOk()) {
-    return status;
-  }
-
-  if (!ReconnectWithTimeout(kTimeoutMs)) {
-    return status;
-  }
-
-  return lambda();
-}
-
-void PackageManagerRemote::RegisterPackageChangeObserver(
-    android::sp<PackageChangeObserver> observer) {
-  LOG(DEBUG) << "Register package change observer.";
-  android::binder::Status status = InvokeRemote(
-      [this, &observer]() {
-        return package_service_->registerPackageChangeObserver(observer);
-      });
-
-  if (!status.isOk()) {
-    LOG(ERROR) << "Cannot register package change observer. Is system_server down?";
-    exit(1);
-  }
-}
-
-void PackageManagerRemote::UnregisterPackageChangeObserver(
-    android::sp<PackageChangeObserver> observer) {
-  LOG(DEBUG) << "Unregister package change observer.";
-  android::binder::Status status = InvokeRemote(
-      [this, &observer]() {
-        return package_service_->unregisterPackageChangeObserver(observer);
-      });
-
-  if (!status.isOk()) {
-    LOG(WARNING) << "Cannot unregister package change observer.";
-  }
-}
-
-void PackageManagerRemote::RegisterPackageManagerDeathRecipient(
-    android::sp<PackageManagerDeathRecipient> death_recipient) {
-  LOG(DEBUG) << "Register package manager death recipient.";
-  android::status_t status =
-      android::IInterface::asBinder(package_service_.get())->linkToDeath(death_recipient);
-
-  if (status == android::OK) {
-    return;
-  }
-
-  if (!ReconnectWithTimeout(kTimeoutMs) ||
-      android::OK != android::IInterface::asBinder(
-          package_service_.get())->linkToDeath(death_recipient)) {
-    LOG(ERROR) << "Failed to register package manager death recipient. Is system_server down?";
-    exit(1);
-  }
-}
-
-void PackageManagerDeathRecipient::binderDied(const android::wp<android::IBinder>& /* who */) {
-  LOG(DEBUG) << "PackageManagerDeathRecipient::binderDied try to re-register";
-  package_manager_->RegisterPackageChangeObserver(observer_);
-  package_manager_->
-      RegisterPackageManagerDeathRecipient(this);
-}
-}  // namespace iorap::package_manager
diff --git a/src/binder/package_manager_remote.h b/src/binder/package_manager_remote.h
deleted file mode 100644
index 9b0dcd9..0000000
--- a/src/binder/package_manager_remote.h
+++ /dev/null
@@ -1,83 +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.
-
-#ifndef IORAP_SRC_PACKAGE_MANAGER_REMOTE_H_
-#define IORAP_SRC_PACKAGE_MANAGER_REMOTE_H_
-
-#include "binder/package_change_observer.h"
-
-#include <android/content/pm/IPackageManagerNative.h>
-#include <binder/IServiceManager.h>
-
-#include <optional>
-#include <unordered_map>
-
-namespace iorap::binder {
-
-using IPackageManager = android::content::pm::IPackageManagerNative;
-// A map between package name and its version.
-using VersionMap = std::unordered_map<std::string, int64_t>;
-
-class PackageManagerRemote;
-
-class PackageManagerDeathRecipient : public android::IBinder::DeathRecipient {
-public:
-  PackageManagerDeathRecipient(std::shared_ptr<PackageManagerRemote> package_manager,
-                               android::sp<PackageChangeObserver> observer) :
-    package_manager_(package_manager), observer_(observer) {}
-  // android::IBinder::DeathRecipient override:
-  void binderDied(const android::wp<android::IBinder>& /* who */) override;
-
-private:
-  std::shared_ptr<PackageManagerRemote> package_manager_;
-
-  android::sp<PackageChangeObserver> observer_;
-};
-
-class PackageManagerRemote {
- public:
-  static std::shared_ptr<PackageManagerRemote> Create();
-
-  // Gets the package version based on the package name.
-  std::optional<int64_t> GetPackageVersion(const std::string& package_name);
-
-  // Gets a map of package name and its version.
-  std::optional<VersionMap> GetPackageVersionMap();
-
-  void RegisterPackageChangeObserver(android::sp<PackageChangeObserver> observer);
-
-  void UnregisterPackageChangeObserver(android::sp<PackageChangeObserver> observer);
-
-  void RegisterPackageManagerDeathRecipient(
-      android::sp<PackageManagerDeathRecipient> death_recipient);
-
- private:
-  template <typename T>
-  android::binder::Status InvokeRemote(T&& lambda);
-
-  // Reconnects to the package manager service.
-  // Retry until timeout.
-  bool ReconnectWithTimeout(int64_t timeout_ms);
-
-  // Gets the package manager service.
-  static android::sp<IPackageManager> GetPackageService();
-
-  // Gets all package names.
-  std::optional<std::vector<std::string>> GetAllPackages();
-
-  android::sp<IPackageManager> package_service_;
-};
-}  // namespace iorap::package_manager
-
-#endif  // IORAP_SRC_PACKAGE_MANAGER_REMOTE_H_
diff --git a/src/binder/package_version_map.cc b/src/binder/package_version_map.cc
deleted file mode 100644
index 784bb1b..0000000
--- a/src/binder/package_version_map.cc
+++ /dev/null
@@ -1,117 +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 "package_version_map.h"
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-
-namespace iorap::binder {
-
-std::shared_ptr<PackageVersionMap> PackageVersionMap::Create() {
-  std::shared_ptr<PackageManagerRemote> package_manager =
-      PackageManagerRemote::Create();
-  if (!package_manager) {
-    return std::make_shared<PackageVersionMap>();
-  }
-
-  std::optional<VersionMap> map = package_manager->GetPackageVersionMap();
-  return std::make_shared<PackageVersionMap>(package_manager, map);
-}
-
-void PackageVersionMap::UpdateAll() {std::lock_guard<std::mutex> lock(mutex_);
-  size_t old_size = version_map_->size();
-  std::optional<VersionMap> new_version_map =
-      package_manager_->GetPackageVersionMap();
-  if (!new_version_map) {
-    LOG(DEBUG) << "Failed to get the latest version map";
-    return;
-  }
-  version_map_ = std::move(new_version_map);
-  LOG(DEBUG) << "Update for version is done. The size is from " << old_size
-             << " to " << version_map_->size();
-}
-
-bool PackageVersionMap::Update(std::string package_name, int64_t version) {
-  std::lock_guard<std::mutex> lock(mutex_);
-  if (!version_map_) {
-    LOG(DEBUG) << "The version map doesn't exist. "
-               << "The package manager may be down.";
-    return false;
-  }
-
-  VersionMap::iterator it = version_map_->find(package_name);
-  if (it == version_map_->end()) {
-    LOG(DEBUG) << "New installed package "
-               << package_name
-               << " with version "
-               << version;
-    (*version_map_)[package_name] = version;
-    return true;
-  }
-
-  if (it->second != version) {
-    LOG(DEBUG) << "New version package "
-               << package_name
-               << " with version "
-               << version;
-    (*version_map_)[package_name] = version;
-    return true;
-  }
-
-  LOG(DEBUG) << "Same version package "
-             << package_name
-             << " with version "
-             << version;
-  return false;
-}
-
-size_t PackageVersionMap::Size() {
-  if (!version_map_) {
-    LOG(DEBUG) << "The version map doesn't exist. "
-               << "The package manager may be down.";
-    return -1;
-  }
-  return version_map_->size();
-}
-
-std::optional<int64_t> PackageVersionMap::GetOrQueryPackageVersion(
-    const std::string& package_name) {
-  std::lock_guard<std::mutex> lock(mutex_);
-  if (!version_map_) {
-    LOG(DEBUG) << "The version map doesn't exist. "
-               << "The package manager may be down.";
-    return std::nullopt;
-  }
-
-  VersionMap::iterator it = version_map_->find(package_name);
-  if (it == version_map_->end()) {
-    LOG(DEBUG) << "Cannot find version for: " << package_name
-                 << " in the hash table";
-    std::optional<int64_t> version =
-        package_manager_->GetPackageVersion(package_name);
-    if (version) {
-      LOG(VERBOSE) << "Find version for: " << package_name << " on the fly.";
-      (*version_map_)[package_name] = *version;
-      return *version;
-    } else {
-      LOG(ERROR) << "Cannot find version for: " << package_name
-                 << " on the fly.";
-      return -1;
-    }
-  }
-
-  return it->second;
-}
-}  // namespace iorap::binder
diff --git a/src/binder/package_version_map.h b/src/binder/package_version_map.h
deleted file mode 100644
index f2048fe..0000000
--- a/src/binder/package_version_map.h
+++ /dev/null
@@ -1,83 +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.
-
-#ifndef IORAP_SRC_PACKAGE_VERSION_MAP_H_
-#define IORAP_SRC_PACKAGE_VERSION_MAP_H_
-
-#include <android/content/pm/IPackageManagerNative.h>
-#include <binder/IServiceManager.h>
-
-#include <optional>
-#include <unordered_map>
-
-#include "package_manager_remote.h"
-
-namespace iorap::binder {
-
-class PackageVersionMap {
- public:
-  static std::shared_ptr<PackageVersionMap> Create();
-
-  PackageVersionMap(std::shared_ptr<PackageManagerRemote> package_manager,
-                    std::optional<VersionMap> version_map)
-      : package_manager_(package_manager),
-        version_map_(version_map) {}
-
-  PackageVersionMap()
-      : package_manager_(nullptr), version_map_(std::nullopt) {}
-
-  // Updates the version specified by 'package_name' to 'version'.
-  //
-  // Post-condition: Find(package_name) == version.
-  // * if the package is newly installed, insert and return true.
-  // * if the package version is changed, update the version to the
-  //   given one and return true.
-  // * otherwise, return false.
-  bool Update(std::string package_name, int64_t version);
-
-  void UpdateAll();
-
-  // Finds the version of the package in the hash table.
-  // -1 means the app is installed by unversioned.
-  // Empty means the app is not inside the RAM version map, maybe due to
-  // the app is newly installed.
-  std::optional<int64_t> Find(const std::string& package_name) {
-    VersionMap::iterator it = version_map_->find(package_name);
-    if (it == version_map_->end()) {
-      return std::nullopt;
-    }
-    return it->second;
-  }
-
-  size_t Size();
-
-  // Gets or queries the version for the package.
-  //
-  // The method firstly access the hash map in the RAM, which is built when
-  // iorapd starts. If the version is not in the map, it tries the query
-  // the package manager via IPC, with a cost of ~0.6ms.
-  //
-  // If no version can be found for some reason, return -1,
-  // because when an app has no version the package manager returns -1.
-  std::optional<int64_t> GetOrQueryPackageVersion(
-      const std::string& package_name);
-
- private:
-  std::shared_ptr<PackageManagerRemote> package_manager_;
-  std::optional<VersionMap> version_map_;
-  std::mutex mutex_;
-};
-}  // namespace iorap::binder
-
-#endif  // IORAP_SRC_PACKAGE_MANAGER_REMOTE_H_
diff --git a/src/common/async_pool.h b/src/common/async_pool.h
deleted file mode 100644
index 51cd38c..0000000
--- a/src/common/async_pool.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_COMMON_ASYNC_POOL_H_
-#define IORAP_SRC_COMMON_ASYNC_POOL_H_
-
-#include <atomic>
-#include <vector>
-#include <deque>
-#include <future>
-
-#include <condition_variable>
-#include <future>
-
-namespace iorap::common {
-
-class AsyncPool {
-  std::atomic<bool> shutting_down_{false};
-  std::deque<std::future<void>> futures_;
-
-  std::mutex mutex_;
-  std::condition_variable cond_var_;
-
- public:
-
-  // Any threads calling 'Join' should eventually unblock
-  // once all functors have run to completition.
-  void Shutdown() {
-    shutting_down_ = true;
-
-    cond_var_.notify_all();
-  }
-
-  // Block forever until Shutdown is called *and* all
-  // functors passed to 'LaunchAsync' have run to completition.
-  void Join() {
-    std::unique_lock<std::mutex> lock(mutex_);
-    while (true) {
-      // Pop all items eagerly
-      while (true) {
-        auto it = futures_.begin();
-        if (it == futures_.end()) {
-          break;
-        }
-
-        std::future<void> future = std::move(*it);
-        futures_.pop_front();
-
-        lock.unlock();  // do not stall callers of LaunchAsync
-        future.get();
-        lock.lock();
-      }
-
-      if (shutting_down_) {
-        break;
-      }
-
-      // Wait until we either get more items or ask to be shutdown.
-      cond_var_.wait(lock);
-    }
-  }
-
-  // Execute the functor 'u' in a new thread asynchronously.
-  // Using this spawns a new thread each time to immediately begin
-  // async execution.
-  template <typename T>
-  void LaunchAsync(T&& u) {
-    auto future = std::async(std::launch::async, std::forward<T>(u));
-
-    {
-      std::unique_lock<std::mutex> lock(mutex_);
-      futures_.push_back(std::move(future));
-    }
-    cond_var_.notify_one();
-  }
-};
-
-}  // namespace iorap::common
-
-#endif  // IORAP_SRC_COMMON_ASYNC_POOL_H_
diff --git a/src/common/cmd_utils.h b/src/common/cmd_utils.h
deleted file mode 100644
index 4494119..0000000
--- a/src/common/cmd_utils.h
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_COMMON_CMD_UTILS_H_
-#define IORAP_SRC_COMMON_CMD_UTILS_H_
-
-#include <android-base/parsebool.h>
-#include <android-base/properties.h>
-
-#include <iostream>
-#include <sstream>
-#include <optional>
-#include <vector>
-
-namespace iorap::common {
-// Create execve-compatible argv.
-// The lifetime is tied to that of vector.
-inline std::unique_ptr<const char*[]> VecToArgv(const char* program_name,
-                                              const std::vector<std::string>& vector) {
-  // include program name in argv[0]
-  // include a NULL sentinel in the end.
-  std::unique_ptr<const char*[]> ptr{new const char*[vector.size() + 2]};
-
-  // program name
-  ptr[0] = program_name;
-
-  // all the argv
-  for (size_t i = 0; i < vector.size(); ++i) {
-    ptr[i+1] = vector[i].c_str();
-  }
-
-  // null sentinel
-  ptr[vector.size() + 1] = nullptr;
-
-  return ptr;
-}
-
-// Appends an args to the argv.
-template <class T>
-void AppendArgs(std::vector<std::string>& argv,
-                const T& value) {
-  std::stringstream ss;
-  ss << value;
-  argv.push_back(ss.str());
-}
-
-// Appends an args to the argv.
-template <class T, class T2>
-void AppendArgs(std::vector<std::string>& argv,
-                const T& value,
-                const T2& value2) {
-  AppendArgs(argv, value);
-  AppendArgs(argv, value2);
-}
-
-// Appends a named argument to the argv.
-//
-// For example if <name> is "--property" and <value> is int(200):
-// the string "--property=200" is appended to the argv.
-template <class T, class T2>
-void AppendNamedArg(std::vector<std::string>& argv,
-                    const T& name,
-                    const T2& value) {
-  std::stringstream ss;
-  ss << name;
-  ss << "=";
-  ss << value;
-
-  argv.push_back(ss.str());
-}
-
-// Appends args from a vector to the argv repeatedly to argv.
-//
-// For example, if <args> is "--timestamp" and <values> is [100, 200].
-// The "--timestamp 100" and "--timestamp 200" are appended.
-template <class T>
-void AppendArgsRepeatedly(std::vector<std::string>& argv,
-                          std::string args,
-                          const std::vector<T>& values) {
-  for (const T& v : values) {
-     AppendArgs(argv, args, v);
-  }
-}
-
-// Appends args from a vector to the argv repeatedly to argv.
-//
-// For example, if values is [input1.pb, input2.pb],
-// then the "input1.pb" and "input2.pb" are appended.
-template <class T>
-void AppendArgsRepeatedly(std::vector<std::string>& argv,
-                          const std::vector<T>& values) {
-  for (const T& v : values) {
-     AppendArgs(argv, v);
-  }
-}
-
-// Appends a named argument to the argv repeatedly with different values.
-//
-// For example if <name> is "--property" and <value> is [int(200), int(400)]:
-// the strings "--property=200" and "--property=400" are both appended to the argv.
-template <class T, class T2>
-void AppendNamedArgRepeatedly(std::vector<std::string>& argv,
-                              const T& name,
-                              const std::vector<T2>& values) {
-  for (const T2& v :values) {
-    AppendNamedArg(argv, name, v);
-  }
-}
-
-// Get the value of the property.
-// Firstly, try to find the environment variable. If it does not exist,
-// try to get the property. If neither, use the default value..
-//
-// For example, for prop foo.bar.baz, it will first check for
-// FOO_BAR_BAZ environment variable.
-inline std::string GetEnvOrProperty(const std::string& prop, const std::string& default_val) {
-  std::string env_str = prop;
-  // a.b.c -> a_b_c
-  std::replace(env_str.begin(), env_str.end(), '.', '_');
-  // a_b_c -> A_B_C
-  std::transform(env_str.begin(), env_str.end(), env_str.begin(), ::toupper);
-  char *env = getenv(env_str.c_str());
-  if (env) {
-    return std::string(env);
-  }
-  return ::android::base::GetProperty(prop, default_val);
-}
-
-// Get the boolean value of the property.
-// Firstly, try to find the environment variable. If it does not exist,
-// try to get the property. If neither, use the default value..
-//
-// For example, for prop foo.bar.baz, it will first check for
-// FOO_BAR_BAZ environment variable.
-inline bool GetBoolEnvOrProperty(const std::string& prop, bool default_val) {
-  std::string env_str = prop;
-  // a.b.c -> a_b_c
-  std::replace(env_str.begin(), env_str.end(), '.', '_');
-  // a_b_c -> A_B_C
-  std::transform(env_str.begin(), env_str.end(), env_str.begin(), ::toupper);
-  char *env = getenv(env_str.c_str());
-  if (env) {
-    using ::android::base::ParseBoolResult;
-
-    switch (::android::base::ParseBool(env)) {
-      case ParseBoolResult::kError:
-        break;
-      case ParseBoolResult::kFalse:
-        return false;
-      case ParseBoolResult::kTrue:
-        return true;
-    }
-  }
-  return ::android::base::GetBoolProperty(prop, default_val);
-}
-
-}   // namespace iorap::common
-
-#endif  // IORAP_SRC_COMMON_CMD_UTILS_H_
diff --git a/src/common/debug.h b/src/common/debug.h
deleted file mode 100644
index bc21c74..0000000
--- a/src/common/debug.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <ostream>
-
-namespace iorap {
-
-// kIsDebugBuild is special.
-// It gets to be in the 'iorap' namespace
-// so that different modules don't need to qualify it.
-#ifndef NDEBUG
-static constexpr bool kIsDebugBuild = true;
-#else
-static constexpr bool kIsDebugBuild = false;
-#endif
-
-namespace common {
-
-// TODO: move below code to helpers.
-template <typename T, bool>
-struct base_if_condition {};
-
-template <typename T>
-struct base_if_condition<T, true> : public T {};
-
-template <typename T>
-using base_if_debug = base_if_condition<T, kIsDebugBuild>;
-
-namespace detail {
-// "if constexpr" doesn't allow us to exclude fields from a struct/class,
-// and also "if constexpr" doesn't allow us to reference a field that does not
-// exist.
-// so we must move everything into a separate base class.
-template <bool kIsDebug = kIsDebugBuild>
-struct DebugCounterBase {
-  constexpr size_t value() const {
-    return counter;
-  }
-
-  constexpr void set_value(size_t value) {
-    counter = value;
-  }
-
-  size_t counter{1};  // Don't start with 0.
-};
-
-template <>
-struct DebugCounterBase<false /*kIsDebug*/> {
-  constexpr size_t value() const {
-    return 0;
-  }
-
-  constexpr void set_value(size_t value) {
-  }
-};
-}  // namespace detail
-
-// This counter does absolutely nothing, the code compiles to no-ops
-// when debugging is disabled.
-struct DebugCounter : detail::DebugCounterBase<> {
-  constexpr DebugCounter& operator++() {
-    set_value(value() + 1);
-    return *this;
-  }
-
-  constexpr DebugCounter operator++(int) {
-    DebugCounter now = *this;
-    set_value(value() + 1);
-    return now;
-  }
-
-  constexpr operator size_t() const {
-    return value();
-  }
-
-  friend std::ostream& operator<<(std::ostream& os, DebugCounter counter);
-};
-
-inline std::ostream& operator<<(std::ostream& os, DebugCounter counter) {
-  os << counter.value();
-  return os;
-}
-
-// TODO: refactor DebugCounter and base traits into their own files?
-
-}  // namespace common
-}  // namespace iorap
diff --git a/src/common/expected.h b/src/common/expected.h
deleted file mode 100644
index c58e63f..0000000
--- a/src/common/expected.h
+++ /dev/null
@@ -1,410 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_COMMON_EXPECTED_H_
-#define IORAP_SRC_COMMON_EXPECTED_H_
-
-#include <type_traits>
-#include <utility>
-
-#include <android-base/logging.h>  // CHECK/DCHECK.
-
-// Ignore the tautological-undefined-compare warning.
-// We obviously want to do this to protect against undefined behavior
-// that sets a reference to a null value.
-#define DCHECK_UB_NOT_NULL(x) \
-  DCHECK(reinterpret_cast<volatile decltype(x)>(x) != nullptr)
-
-/**
- * Result<Value, Error>-like interface.
- *
- * Subset of the experimental standard C++ proposal (p0323r3)
- *
- * Example:
- *
- *   expected<std::string, status_t> x = function_which_might_fail();
- *   if (x) {
- *     std::string str = x.value();
- *   } else {
- *     status_t err = x.error();
- *   }
- */
-
-namespace iorap {
-namespace detail {
-  // Use perfect forwarding for expected_data constructors with overloading.
-  struct expected_tag{};
-  struct expected_tag_right : public expected_tag {
-    static constexpr bool is_right_v = true;
-  };
-  struct expected_tag_error : public expected_tag {
-    static constexpr bool is_right_v = false;
-  };
-
-  template <typename T, typename E, bool DefineDestructor>
-  struct expected_data;
-
-  // This doesn't always work because this code could be instantiated with a non-trivial T/E,
-  // and then the union becomes invalid.
-  template <typename T, typename E>
-  struct expected_data<T, E, /*DefineDestructor*/true> {
-    // Mark everything 'constexpr' to keep the code the same as the other partial specialization.
-
-    template <typename U>
-    constexpr expected_data(U&& either, expected_tag_right)
-        : right_{std::forward<U>(either)}, is_right_{true} {}
-
-    template <typename U>
-    constexpr expected_data(U&& either, expected_tag_error)
-        : error_{std::forward<U>(either)}, is_right_{false} {}
-
-    constexpr bool has_value() const {
-      return is_right_;
-    }
-
-    constexpr const T& value() const {
-      return right_;
-    }
-
-    constexpr T& value() {
-      return right_;
-    }
-
-    constexpr const E& error() const {
-      return error_;
-    }
-
-    constexpr E& error() {
-      return error_;
-    }
-
-    // Using an "anonymous union" here allows non-trivial types to be stored.
-    union {
-      T right_;
-      E error_;
-    };
-
-    bool is_right_;
-
-    // Below code differs slightly by handling non-trivial constructors/destructors.
-    bool moved_from_{false};
-
-    // Note: Destructors cannot be templated, so it is illegal to use SFINAE to try to
-    // conditionalize this destructor somehow.
-    ~expected_data() {
-      if (moved_from_) { return; }
-      if (is_right_) {
-        right_.~T();
-      } else {
-        error_.~E();
-      }
-    }
-
-    expected_data(expected_data&& other)
-        noexcept(
-            noexcept(T(std::move(other.right_))) &&
-            noexcept(E(std::move(other.error_)))
-        ) {
-      DCHECK_UB_NOT_NULL(&other) << __PRETTY_FUNCTION__;
-      DCHECK_EQ(other.moved_from_, false) << __PRETTY_FUNCTION__;
-      if (other.is_right_) {
-        new (&right_) T(std::move(other.right_));
-      } else {
-        new (&error_) E(std::move(other.error_));
-      }
-      other.moved_from_ = true;
-      is_right_ = other.is_right_;
-    }
-
-    expected_data(const expected_data& other) {
-      DCHECK_UB_NOT_NULL(&other) << __PRETTY_FUNCTION__;
-      DCHECK_EQ(other.moved_from_, false) << __PRETTY_FUNCTION__;
-      if (other.is_right_) {
-        new (&right_) T(other.right_);
-      } else {
-        new (&error_) E(other.error_);
-      }
-      is_right_ = other.is_right_;
-    }
-
-    expected_data& operator=(const expected_data& other) {
-      DCHECK_UB_NOT_NULL(&other) << __PRETTY_FUNCTION__;
-      DCHECK_EQ(other.moved_from_, false) << __PRETTY_FUNCTION__;
-
-      if (this == &other) {
-        return *this;
-      }
-
-      if (other.is_right_) {
-        if (!is_right_) {
-          error_.~E();
-          new (&right_) T(other.right_);
-        } else {
-          right_ = other.right_;
-        }
-      } else {
-        if (is_right_) {
-          right_.~T();
-          new (&error_) E(other.error_);
-        } else {
-          error_ = other.error_;
-        }
-      }
-      is_right_ = other.is_right_;
-
-      return *this;
-    }
-
-    expected_data& operator=(expected_data&& other) {
-      DCHECK_UB_NOT_NULL(&other) << __PRETTY_FUNCTION__;
-      DCHECK_EQ(other.moved_from_, false) << __PRETTY_FUNCTION__;
-
-      if (this == &other) {
-        return *this;
-      }
-
-      if (other.is_right_) {
-        if (!is_right_) {
-          error_.~E();
-          new (&right_) T(std::move(other.right_));
-        } else {
-          right_ = std::move(other.right_);
-        }
-      } else {
-        if (is_right_) {
-          right_.~T();
-          new (&error_) E(std::move(other.error_));
-        } else {
-          error_ = std::move(other.error_);
-        }
-      }
-
-      other.moved_from_ = true;
-      is_right_ = other.is_right_;
-
-      return *this;
-    }
-  };
-
-  // Trivial-destructor copy of the above struct.
-  //
-  // A separate copy is required because otherwise compilation fails with an error about
-  // the union having an implicitly deleted constructor.
-  //
-  // Having this implementation gives us the property that
-  //
-  //     (is_trivially_destructible<T> && is_trivially_destructible<E>
-  //       ==> is_trivially_destructible<expected<T, E>>)
-  template <typename T, typename E>
-  struct expected_data<T, E, /*DefineDestructor*/false> {
-    template <typename U>
-    constexpr expected_data(U&& either, expected_tag_right)
-        : right_{std::forward<U>(either)}, is_right_{true} {}
-
-    template <typename U>
-    constexpr expected_data(U&& either, expected_tag_error)
-        : error_{std::forward<U>(either)}, is_right_{false} {}
-
-    constexpr bool has_value() const {
-      return is_right_;
-    }
-
-    constexpr const T& value() const {
-      return right_;
-    }
-
-    constexpr T& value() {
-      return right_;
-    }
-
-    constexpr const E& error() const {
-      return error_;
-    }
-
-    constexpr E& error() {
-      return error_;
-    }
-
-    // Using an "anonymous union" here allows non-trivial types to be stored.
-    union {
-      T right_;
-      E error_;
-    };
-
-    bool is_right_;
-
-    ~expected_data() = default;
-  };
-
-  // Select between trivial and non-trivial implementations. Trivial implementations
-  // are more optimized and constexpr-compatible.
-  template <typename T, typename E>
-  using expected_pick_data_t =
-      expected_data<T, E,
-        !(std::is_trivially_destructible_v<T> && std::is_trivially_destructible_v<E>) >;
-}  // namespace detail
-
-template <typename E>
-struct unexpected;
-
-// Subset of std::experimental::expected proposal (p0323r3).
-template <typename T, typename E>
-struct expected {
-  // Never-empty: expected<T,E> values have either 'T' or 'E' in them.
-  template <typename U = T, typename _ = std::enable_if_t<std::is_default_constructible_v<U>>>
-  constexpr expected() noexcept(noexcept(T{})) : expected(T{}) {}
-
-  constexpr expected(const T& value) : data_{value, detail::expected_tag_right{}} {}
-  constexpr expected(T&& value) : data_{std::move(value), detail::expected_tag_right{}} {}
-  constexpr expected(const E& error) : data_{error, detail::expected_tag_error{}} {}
-  constexpr expected(E&& error) : data_{std::move(error), detail::expected_tag_error{}} {}
-
-  template <typename G = E>
-  constexpr expected(unexpected<G> const& u) : expected{u.value()} {}
-
-  template <typename G = E>
-  constexpr expected(unexpected<G>&& u) : expected{std::move(u.value())} {}
-
-  explicit constexpr operator bool() const {
-    return has_value();
-  }
-
-  constexpr bool has_value() const {
-    return data_.has_value();
-  }
-
-  constexpr const T& operator*() const {
-    return data_.value();
-  }
-
-  constexpr T& operator*() {
-    return data_.value();
-  }
-
-  constexpr const T* _Nonnull operator->() const {
-    return &data_.value();
-  }
-
-  constexpr T* _Nonnull operator->() {
-    return &data_.value();
-  }
-
-  constexpr T& value() & {
-    CHECK(has_value());
-    return data_.value();
-  }
-
-  constexpr const T& value() const & {
-    CHECK(has_value());
-    return data_.value();
-  }
-
-  constexpr T&& value() && {
-    CHECK(has_value());
-    return std::move(data_.value());
-  }
-
-  constexpr const T& value() const && {
-    CHECK(has_value());
-    return std::move(data_.value());
-  }
-
-  constexpr E& error() {
-    DCHECK(!has_value());
-    return data_.error();
-  }
-
-  constexpr const E& error() const {
-    DCHECK(!has_value());
-    return data_.error();
-  }
-
-  // TODO: other functions such as operator=, unexpected, etc.
- private:
-  detail::expected_pick_data_t<T, E> data_;
-};
-
-// TODO: move to tests file
-namespace {
-  struct TestType {
-    TestType() {}
-    ~TestType() {}
-  };
-  struct TestType2 : TestType {};
-
-  static_assert(std::is_trivially_destructible_v<expected<int, /*error*/double> >);
-  static_assert(!std::is_trivially_destructible_v<expected<TestType, /*error*/double> >);
-  static_assert(!std::is_trivially_destructible_v<expected<int, /*error*/TestType> >);
-  static_assert(!std::is_trivially_destructible_v<expected<TestType, /*error*/TestType2> >);
-
-  // Ensure expected is constexpr-compatible.
-  struct TestCase {
-    static constexpr auto t1 = expected<int, double>{};
-  };
-}  // namespace <anonymous>
-
-template <typename E>
-struct unexpected {
-  unexpected() = delete;
-  constexpr explicit unexpected(const E& error) : error_{error} {}
-  constexpr explicit unexpected(E&& error) : error_{std::move(error)} {}
-  constexpr const E& value() const& { return error_; }
-  constexpr E& value() & { return error_; }
-  constexpr E&& value() && { return std::move(error_); }
-  constexpr E const&& value() const&& { return std::move(error_); }
- private:
-  E error_;
-};
-
-template <class E>
-constexpr bool operator==(const unexpected<E>& x, const unexpected<E>& y) {
-  return x.value() == y.value();
-}
-
-template <class E>
-constexpr bool operator!=(const unexpected<E>& x, const unexpected<E>& y) {
-  return !(x == y);
-}
-
-// TODO: move below codes to separate utils file
-//
-// future C++20 implementation of std::identity
-struct identity {
-  template <typename U>
-  constexpr auto operator()(U&& v) const noexcept {
-    return std::forward<U>(v);
-  }
-};
-
-// Given a lambda [...](auto&& var) {...}
-//   apply std::forward to 'var' to achieve perfect forwarding.
-//
-// Note that this doesn't work when var is a template type, i.e.
-//   template <typename T>
-//   void func(T&& tvar) {...}
-//
-// It would be invalid to use this macro with 'tvar' in that context.
-#define IORAP_FORWARD_LAMBDA(var) std::forward<decltype(var)>(var)
-
-// Borrowed non-null pointer, i.e. we do not own the lifetime.
-//
-// Function calls: This pointer is not used past the call.
-// Struct fields: This pointer is not used past the lifetime of the struct.
-template <class T, class = std::enable_if_t<std::is_pointer<T>::value>>
-using borrowed = T _Nonnull;
-// TODO: need a DCHECK or high warning levels, since null is technically well-defined.
-
-}  // namespace iorap
-
-#endif  // IORAP_SRC_COMMON_EXPECTED_H_
diff --git a/src/common/introspection.h b/src/common/introspection.h
deleted file mode 100644
index af64a20..0000000
--- a/src/common/introspection.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_COMMON_INTROSPECTION_H
-#define IORAP_COMMON_INTROSPECTION_H
-
-/*
- * Provide zero-cost compile-time introspection of struct member fields.
- *
- * Example:
- *
- * // Declaration
- * struct PackageEvent {
- *
- *   int type;
- *   std::string package_uri;
- *   std::string package_name;
- * };
- *
- * IORAP_INTROSPECT_ADAPT_STRUCT(PackageEvent, type, package_uri, package_name);
- *
- * // Usage
- * {
- *   std::stringstream str;
- *   for_each_member_field(PackageEvent{123,"hello","world"}, [&](auto&& val) {
- *     str << val << ",";
- *   }
- *   CHECK_EQ("123,hello,world,"s, str.str());
- * }
- */
-
-#include "common/macros.h"
-#include "common/type.h"
-
-#include <tuple>
-
-namespace iorap {
-namespace introspect {
-
-template <auto value>
-struct member_type;
-
-// Compile-time introspection data for a member-to-pointer.
-//
-// Example:
-//   using package_uri_member_type = member_type<&PackageEvent::&package_uri>
-//   int type = package_uri_member_type::value(PackageEvent{123,"hello","world"});
-//   CHECK_EQ(type, 123);
-template <typename T, typename F, F T::*member>
-struct member_type<member> {
-  // The type of the struct this field is located in, e.g. 'struct XYZ {...}' -> XYZ.
-  static constexpr auto struct_t = type_c<T>;
-  // The type of the field, e.g. 'struct XYZ { int x; }' -> int.
-  static constexpr auto type = type_c<F>;
-
-  // Allow a 'const U', 'volatile U', 'U&' etc here.
-  // Returns the value inside of 'U'.
-  template <typename U>
-  static constexpr decltype(auto) value(U&& v) {
-    static_assert(std::is_same_v<T, std::decay_t<U>>, "U must be cvref of T");
-
-    using U_noref = std::remove_reference_t<U>;
-
-    // This casts from the regular non-const pointer-to-member to a potentially const/volatile
-    // pointer-to-member.
-    F U_noref::*safer_member = member;
-
-    // Now dereference it,
-    return v.*safer_member;
-    // TODO: are we properly returning && for rvalue, & for lvalue refs, etc?
-  }
-
-  static constexpr void set_value(typename decltype(struct_t)::type& s,
-                                  typename decltype(type)::type&& value) {
-    s.*member = std::forward<typename decltype(type)::type>(value);
-  }
-};
-
-// Given a self : T, where T has introspection-enabled support, T has some
-// members m1, m2, m3, ... , mN.
-//
-// Invokes fun(self.*m1); fun(self.*m2); fun(self.*m3); ... ; fun(self.*mN).
-template <typename T, typename F>
-static constexpr void for_each_member_field_value(T&& self, F&& fun) {
-  constexpr auto members = introspect_members(type_c<std::decay_t<T>>);
-  // std::tuple<member_type<A>, member_type<B>, ...>
-
-  // Warning: Don't use 'v=std::forward<V>(v)' as that actually captures-by-value.
-  for_each(members, [&fun, &self](auto&& type) mutable {
-    // Note that 'type' is a member_type
-    fun(type.value(std::forward<T>(self)));
-  });
-}
-
-// Given a self : T, where T has introspection-enabled support, T has some
-// members m1, m2, m3, ... , mN. The basic_type of each member is t1, t2, t3, ..., tN.
-//
-// Invokes
-//   self.*m1 = fun(self, t1);
-//   self.*m2 = fun(self, t2);
-//   self.*m3 = fun(self, t3);
-//   ...;
-//   self.*mN = fun(self, tN).
-template <typename T, typename F>
-static constexpr void for_each_member_field_set_value(T&& self, F&& fun) {
-  constexpr auto members = introspect_members(type_c<std::decay_t<T>>);
-  // std::tuple<member_type<A>, member_type<B>, ...>
-
-  // Warning: Don't use 'v=std::forward<V>(v)' as that actually captures-by-value.
-  for_each(members, [&fun, &self](auto&& type) mutable {
-    // Note that 'type' is a member_type
-    type.set_value(std::forward<T>(self), fun(type.type));
-  });
-}
-
-}
-}
-
-// Add compile-time introspection capabilities to a pre-existing struct or class.
-//
-// Arguments: Name, [Member1, Member2, ... MemberN]
-//
-// Example:
-//
-//   struct Rectangle {
-//     int height;
-//     int width;
-//   };
-//
-//   IORAP_INTROSPECT_ADAPT_STRUCT(Rectangle, height, width);
-//
-// See also for_each_member_field_value.
-#define IORAP_INTROSPECT_ADAPT_STRUCT(/*name, [member1, member2, member3, ...]*/...) \
-  IORAP_INTROSPECT_ADAPT_STRUCT_IMPL(IORAP_PP_NARG(__VA_ARGS__), __VA_ARGS__)
-
-#define IORAP_INTROSPECT_ADAPT_STRUCT_IMPL(N, ...) \
-  IORAP_PP_CONCAT(IORAP_INTROSPECT_ADAPT_STRUCT_IMPL_, N)(__VA_ARGS__)
-
-// This simple implementation relies on the 'introspect_members' function being overloaded
-// for the type<T> values. ADL is then applied to resolve the exact overload for any T,
-// thus allowing this function definition to be in any namespace.
-
-// The auto signature must conform to:
-//   introspect_members(type<T>) -> std::tuple<member_type1, member_type_2, ...>
-
-// TODO: it would be nice to capture the name of the member as a string literal.
-#define IORAP_INTROSPECT_ADAPT_STRUCT_IMPL_1(TYPE) \
-  static constexpr auto introspect_members(::iorap::introspect::type<TYPE>) { \
-    return std::make_tuple();\
-  }
-#define IORAP_INTROSPECT_ADAPT_STRUCT_IMPL_2(TYPE, m1) \
-  static constexpr auto introspect_members(::iorap::introspect::type<TYPE>) { \
-    return std::make_tuple(::iorap::introspect::member_type<&TYPE::m1>{}\
-    );\
-  }
-
-#define IORAP_INTROSPECT_ADAPT_STRUCT_IMPL_3(TYPE, m1, m2) \
-  static constexpr auto introspect_members(::iorap::introspect::type<TYPE>) { \
-    return std::make_tuple(::iorap::introspect::member_type<&TYPE::m1>{},\
-                           ::iorap::introspect::member_type<&TYPE::m2>{}\
-    ); \
-  }
-
-#define IORAP_INTROSPECT_ADAPT_STRUCT_IMPL_4(TYPE, m1, m2, m3) \
-  static constexpr auto introspect_members(::iorap::introspect::type<TYPE>) { \
-    return std::make_tuple(::iorap::introspect::member_type<&TYPE::m1>{},\
-                           ::iorap::introspect::member_type<&TYPE::m2>{},\
-                           ::iorap::introspect::member_type<&TYPE::m3>{}\
-    ); \
-  }
-
-#define IORAP_INTROSPECT_ADAPT_STRUCT_IMPL_5(TYPE, m1, m2, m3, m4) \
-  static constexpr auto introspect_members(::iorap::introspect::type<TYPE>) { \
-    return std::make_tuple(::iorap::introspect::member_type<&TYPE::m1>{},\
-                           ::iorap::introspect::member_type<&TYPE::m2>{},\
-                           ::iorap::introspect::member_type<&TYPE::m3>{},\
-                           ::iorap::introspect::member_type<&TYPE::m4>{}\
-    ); \
-  }
-
-#define IORAP_INTROSPECT_ADAPT_STRUCT_IMPL_6(TYPE, m1, m2, m3, m4, m5) \
-  static constexpr auto introspect_members(::iorap::introspect::type<TYPE>) { \
-    return std::make_tuple(::iorap::introspect::member_type<&TYPE::m1>{},\
-                           ::iorap::introspect::member_type<&TYPE::m2>{},\
-                           ::iorap::introspect::member_type<&TYPE::m3>{},\
-                           ::iorap::introspect::member_type<&TYPE::m4>{},\
-                           ::iorap::introspect::member_type<&TYPE::m5>{}\
-    ); \
-  }
-
-// TODO: Consider using IORAP_PP_MAP
-
-
-#endif  // IORAP_COMMON_INTROSPECTION_H
diff --git a/src/common/loggers.h b/src/common/loggers.h
deleted file mode 100644
index 1dbb2dc..0000000
--- a/src/common/loggers.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_SRC_COMMON_LOGGERS
-#define IORAP_SRC_COMMON_LOGGERS
-
-#include <android-base/logging.h>
-
-namespace iorap {
-namespace common {
-
-// Log to both Stderr and Logd for convenience when running this from the command line.
-class StderrAndLogdLogger {
- public:
-  explicit StderrAndLogdLogger(android::base::LogId default_log_id = android::base::MAIN)
-#ifdef __ANDROID__
-      : logd_(default_log_id)
-#endif
-  {
-  }
-
-  void operator()(::android::base::LogId id,
-                  ::android::base::LogSeverity sev,
-                  const char* tag,
-                  const char* file,
-                  unsigned int line,
-                  const char* message) {
-#ifdef __ANDROID__
-    logd_(id, sev, tag, file, line, message);
-#endif
-    StderrLogger(id, sev, tag, file, line, message);
-  }
-
- private:
-#ifdef __ANDROID__
-  ::android::base::LogdLogger logd_;
-#endif
-};
-
-}  // namespace iorap
-}  // namespace common
-
-#endif
diff --git a/src/common/macros.h b/src/common/macros.h
deleted file mode 100644
index 1b5b38b..0000000
--- a/src/common/macros.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_COMMON_MACROS_H_
-#define IORAP_COMMON_MACROS_H_
-
-// Expands to the # of arguments passed to the macro.
-// For example `IORAP_PP_NARG(a,b,c)` -> 3
-// For example `IORAP_PP_NARG(x)` -> 1
-//
-// The # of arguments must be >0 and <64.
-#define IORAP_PP_NARG(...) \
-  IORAP_PP_NARG_IMPL(__VA_ARGS__, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,)  // NOLINT
-
-// Implementation explanation: Equivalent of:
-//   lst = __VA_ARGS__ + 64..1
-//   return lst[64]
-// The variadic arguments logically shift-off the hardcoded 64..1 list, revealing
-// the # of arguments that were shifted.
-#define IORAP_PP_NARG_IMPL(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31, e32, e33, e34, e35, e36, e37, e38, e39, e40, e41, e42, e43, e44, e45, e46, e47, e48, e49, e50, e51, e52, e53, e54, e55, e56, e57, e58, e59, e60, e61, e62, e63, N, ...) N
-
-#define IORAP_PP_CONCAT(lhs, rhs) \
-  IORAP_PP_CONCAT_IMPL(lhs, rhs)
-
-#define IORAP_PP_CONCAT_IMPL(lhs, rhs) \
-  lhs ## rhs
-
-// Expands to call FN around every argument passed it.
-//   MAP(f, a1, a2, .., an) -> f(a1) f(a2) f(a3) ... f(an)
-#define IORAP_PP_MAP(FN, ...) IORAP_PP_MAP_IMPL(IORAP_PP_NARG(__VA_ARGS__), /*sep=blank*/, FN, __VA_ARGS__)
-// Expands to call FN around every argument passed it.
-// Every non-first/non-last function call also has a separator prefixed before it.
-//   MAP_SEP(f, sep, a1, a2, .., an) -> f(a1) sep() f(a2) sep() f(a3) sep() ... sep() f(an-1) f(an)
-#define IORAP_PP_MAP_SEP(FN, sep, ...) IORAP_PP_MAP_IMPL(IORAP_PP_NARG(__VA_ARGS__), FN, sep, __VA_ARGS__)
-#define IORAP_PP_MAP_IMPL(N, FN, sep, ...) IORAP_PP_CONCAT(IORAP_PP_MAP_IMPL_, N)(FN, sep, __VA_ARGS__)
-#define IORAP_PP_MAP_IMPL_1(FN, sep, a1) FN(a1)
-#define IORAP_PP_MAP_IMPL_2(FN, sep, a1, a2) FN(a1) sep() FN(a2)
-#define IORAP_PP_MAP_IMPL_3(FN, sep, a1, a2, a3) FN(a1) sep() FN(a2) sep() FN(a3)
-#define IORAP_PP_MAP_IMPL_4(FN, sep, a1, a2, a3, a4) FN(a1) sep() FN(a2) sep() FN(a3) sep() FN(a4)
-
-// Deferred comma. Useful with the above MAP function when you need a comma separator.
-#define IORAP_PP_COMMA() ,
-// All arguments are ignored.
-#define IORAP_PP_NOP(...)
-
-#endif  // IORAP_COMMON_MACROS_H_
\ No newline at end of file
diff --git a/src/common/printer.h b/src/common/printer.h
deleted file mode 100644
index 272e459..0000000
--- a/src/common/printer.h
+++ /dev/null
@@ -1,62 +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.
- */
-
-#ifndef IORAP_UTILS_PRINTER_H_
-#define IORAP_UTILS_PRINTER_H_
-
-#include <utils/Printer.h>
-
-#include <string.h>
-
-namespace iorap::common {
-
-class StderrLogPrinter : public ::android::Printer {
-public:
-    // Create a printer using the specified logcat and log priority
-    // - Unless ignoreBlankLines is false, print blank lines to logcat
-    // (Note that the default ALOG behavior is to ignore blank lines)
-    StderrLogPrinter(const char* logtag,
-                     android_LogPriority priority = ANDROID_LOG_DEBUG,
-                     const char* prefix = nullptr,
-                     bool ignore_blank_lines = false)
-      : log_printer_{logtag, priority, prefix, ignore_blank_lines} {
-      logtag_ = logtag;
-      prefix_ = prefix;
-      ignore_blank_lines_ = ignore_blank_lines;
-    }
-
-    // Print the specified line to logcat. No \n at the end is necessary.
-    virtual void printLine(const char* string) override {
-      if (ignore_blank_lines_ && strlen(string) == 0) {
-        return;
-      }
-      std::cerr << logtag_ << ": ";
-      if (prefix_ != nullptr) {
-        std::cerr << prefix_;
-      }
-      std::cerr << string << std::endl;
-      log_printer_.printLine(string);
-    }
- private:
-    ::android::LogPrinter log_printer_;
-    const char* logtag_;
-    const char* prefix_;
-    bool ignore_blank_lines_;
-};
-
-}  // namespace iorap::common
-
-#endif  // IORAP_UTILS_PRINTER_H_
diff --git a/src/common/property.h b/src/common/property.h
deleted file mode 100644
index d910193..0000000
--- a/src/common/property.h
+++ /dev/null
@@ -1,47 +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.
- */
-
-#ifndef IORAP_UTILS_PROPERTY_H_
-#define IORAP_UTILS_PROPERTY_H_
-
-#include <android-base/properties.h>
-#include <server_configurable_flags/get_flags.h>
-
-namespace iorap::common {
-
-constexpr const char* ph_namespace = "runtime_native_boot";
-
-inline bool IsTracingEnabled(const std::string& default_value) {
-  return server_configurable_flags::GetServerConfigurableFlag(
-      ph_namespace,
-      "iorap_perfetto_enable",
-      ::android::base::GetProperty("iorapd.perfetto.enable", default_value)) == "true";
-}
-
-inline bool IsReadAheadEnabled(const std::string& default_value) {
-  return server_configurable_flags::GetServerConfigurableFlag(
-      ph_namespace,
-      "iorap_readahead_enable",
-      ::android::base::GetProperty("iorapd.readahead.enable", default_value)) == "true";
-}
-
-inline bool ExcludeDexFiles(bool default_value) {
-  return ::android::base::GetBoolProperty("iorapd.exclude_dex_files", default_value);
-}
-
-}  // namespace iorap::common
-
-#endif  // IORAP_UTILS_PROPERTY_H_
diff --git a/src/common/rx_async.h b/src/common/rx_async.h
deleted file mode 100644
index d16f5ae..0000000
--- a/src/common/rx_async.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_COMMON_RX_ASYNC_H_
-#define IORAP_SRC_COMMON_RX_ASYNC_H_
-
-#include "common/async_pool.h"
-
-#include <rxcpp/rx.hpp>
-
-namespace iorap::common {
-
-// Helper functions to operate with rx chains asynchronously.
-class RxAsync {
- public:
-  // Subscribe to the observable on a new thread asynchronously.
-  // If no observe_on/subscribe_on is used, the chain will execute
-  // on that new thread.
-  //
-  // Returns the composite_subscription which can be used to
-  // unsubscribe from if we want to abort the chain early.
-  template <typename T, typename U>
-  static rxcpp::composite_subscription SubscribeAsync(
-      AsyncPool& async_pool,
-      T&& observable,
-      U&& subscriber) {
-    rxcpp::composite_subscription subscription;
-
-    async_pool.LaunchAsync([subscription,  // safe copy: ref-counted
-                            observable=std::forward<T>(observable),
-                            subscriber=std::forward<U>(subscriber)]() mutable {
-      observable
-        .as_blocking()
-        .subscribe(subscription,
-                   std::forward<decltype(subscriber)>(subscriber));
-    });
-
-    return subscription;
-  }
-
-  template <typename T, typename U, typename E>
-  static rxcpp::composite_subscription SubscribeAsync(
-      AsyncPool& async_pool,
-      T&& observable,
-      U&& on_next,
-      E&& on_error) {
-    rxcpp::composite_subscription subscription;
-
-    async_pool.LaunchAsync([subscription,  // safe copy: ref-counted
-                            observable=std::forward<T>(observable),
-                            on_next=std::forward<U>(on_next),
-                            on_error=std::forward<E>(on_error)]() mutable {
-      observable
-        .as_blocking()
-        .subscribe(subscription,
-                   std::forward<decltype(on_next)>(on_next),
-                   std::forward<decltype(on_error)>(on_error));
-    });
-
-    return subscription;
-  }
-};
-
-}   // namespace iorap::common
-
-#endif  // IORAP_SRC_COMMON_RX_ASYNC_H_
diff --git a/src/common/trace.h b/src/common/trace.h
deleted file mode 100644
index a07d7bc..0000000
--- a/src/common/trace.h
+++ /dev/null
@@ -1,48 +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.
-
-#ifndef IORAP_COMMON_TRACE_H_
-#define IORAP_COMMON_TRACE_H_
-
-#include <cutils/trace.h>
-
-#include <cstdio>
-#include <sstream>
-
-namespace iorap {
-
-// TODO: refactor into utils/Trace.h
-
-class ScopedFormatTrace {
- public:
-  template <typename ... Args>
-  ScopedFormatTrace(uint64_t tag, const char* fmt, Args&&... args) : tag_{tag} {
-    char buffer[1024];
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat-security"
-    snprintf(buffer, sizeof(buffer), fmt, args...);
-#pragma GCC diagnostic pop
-    atrace_begin(tag, buffer);
-  }
-
-  ~ScopedFormatTrace() {
-    atrace_end(tag_);
-  }
- private:
-  uint64_t tag_;
-};
-
-}  // namespace iorap
-
-#endif  // IORAP_COMMON_TRACE_H_
diff --git a/src/common/type.h b/src/common/type.h
deleted file mode 100644
index e856d73..0000000
--- a/src/common/type.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_COMMON_TYPE_H
-#define IORAP_COMMON_TYPE_H
-
-#include <cstdint>
-#include <tuple>
-
-namespace iorap {
-namespace introspect {
-
-/*
- * Simple types-as-value abstractions.
- *
- * Allow types to be passed as regular function parameters instead of using 'template' type
- * parameters.
- *
- * This enables the following, more concise, pattern:
- * ----------------------------
- *
- * Traditional metaprogramming with template parameters:
- *
- *   template <typename ... Args>
- *   struct get_num_params {
- *     static constexpr size_t value = sizeof...(Args);
- *   };
- *
- *  typename get_num_params<decltype("hello"), decltype("world")>::value == 2
- *  typename get_num_params<decltype(int), decltype(int), decltype(int), decltype(int)>::value == 4
- *
- * Alternative metaprogramming with values:
- *
- *   constexpr auto get_num_params = [](auto&&... val) { return sizeof...(val); };
- *
- *   get_num_params("hello", "world") == 2
- *   get_num_params(0,0,0,0) == 4
- */
-
-/*
- * A fully instantiated type wrapper.
- *
- * basic_type<T> is intended for overloading functions between different basic_types.
- * type_c<T> is intended for instantiating new type wrappers as a short-hand (and not requiring
- * typename).
- *
- * For basic_type<T> in particular it allows one to overload on basic_type<T> to handle specific
- * types, and there's no requirement that T be constexpr, be default constructible, and no
- * template specializations is necessary.
- *
- *   void foo(basic_type<int>) {
- *     printf("int");
- *   }
- *
- *   template <typename T>
- *   void foo(basic_type<T>) {
- *     printf("everything else");
- *   }
- *
- * as opposed to this verbosity
- *
- *   template <typename T>
- *   struct foo {
- *     void operator() {
- *       printf("everything else");
- *     }
- *   };
- *
- *   template <>
- *   struct foo<int> {
- *     void operator() {
- *       printf("int");
- *     }
- *   };
- *
- * OR this super-hack which works in rare situations
- *
- *   void foo(int) {
- *     printf("int");
- *   }
- *
- *   template <typename T>
- *   void foo(T&&) {
- *     printf("everything else")
- *   }
- *
- * Note that invoking the last foo(T&&) is particularly challenging. declval<T> fails at compilation
- * with a static_assert, so a real value has to be constructed that is immediately discarded.
- */
-template <typename T>
-struct basic_type {
-  using type = T;
-};
-
-template <typename T>
-struct type_impl {
-  struct _ : basic_type<T> { };
-};
-
-template <typename T>
-using type = basic_type<T>;  // typename type_impl<T>::_;  // subclass of basic_type<T>
-// TODO: why doesn't using type_impl::_ work with ADL?
-
-template <typename T>
-using type_t = type<T>;
-
-template <typename T>
-constexpr auto type_c = type<T>{};
-
-template <auto X>
-struct value_constant {
-  static constexpr auto value = X;
-};
-
-template <int X>
-constexpr auto int_c = value_constant<X>{};
-
-template <typename T>
-constexpr bool dependent_false_v = false;
-
-// Emit a static_assert(false) if the else branch in an 'if constexpr' is taken.
-// Needs a type as the first parameter.
-#define STATIC_FAIL(T, msg) static_assert(::iorap::introspect::dependent_false_v<T>, msg)
-// Emit a static_assert(false) if an else branch in an 'if constexpr' is taken, used with
-// (e.g. auto) values instead of types.
-#define STATIC_FAIL_DT(var, msg) STATIC_FAIL(decltype(var), msg)
-
-template <size_t i, typename Tuple, typename F>
-static constexpr void for_each_impl(Tuple&& t, F&& f) {
-  if constexpr (i == std::tuple_size<std::decay_t<Tuple>>::value) {
-    return;
-  } else {
-    f(std::get<i>(std::forward<Tuple>(t)));
-    for_each_impl<i+1>(std::forward<Tuple>(t), std::forward<F>(f));
-  }
-}
-
-// for each Tuple<a1,a2,...,aN> invoke { f(a1); f(a2); ... ; f(aN); }
-template <typename Tuple, typename F>
-static constexpr void for_each(Tuple&& t, F&& f) {
-  return for_each_impl<0u>(std::forward<Tuple>(t), std::forward<F>(f));
-}
-
-// Perfect forwarding for structured binding.
-//
-// Example:
-//   auto&& [a,b] = whatever;
-//   return aliasing_forward<T>(a);
-template <typename T, typename U>
-constexpr decltype(auto) aliasing_forward(U&& val) noexcept {
-  if constexpr (std::is_lvalue_reference_v<T>) {
-    return val;
-  } else {
-    return std::move(val);
-  }
-}
-
-
-}  // namespace introspect
-}  // namespace iorap
-
-#endif  // IORAP_COMMON_TYPE_H
diff --git a/src/compiler/compiler.cc b/src/compiler/compiler.cc
deleted file mode 100644
index a546c5c..0000000
--- a/src/compiler/compiler.cc
+++ /dev/null
@@ -1,992 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "compiler/compiler.h"
-
-#include "common/debug.h"
-#include "common/expected.h"
-
-#include "perfetto/rx_producer.h"  // TODO: refactor BinaryWireProtobuf to separate header.
-#include "inode2filename/inode.h"
-#include "inode2filename/search_directories.h"
-#include "serialize/protobuf_io.h"
-
-#include <android-base/unique_fd.h>
-#include <android-base/parseint.h>
-#include <android-base/file.h>
-
-#include <perfetto/trace/trace.pb.h>  // ::perfetto::protos::Trace
-#include <perfetto/trace/trace_packet.pb.h>  // ::perfetto::protos::TracePacket
-
-#include "rxcpp/rx.hpp"
-#include <iostream>
-#include <fstream>
-#include <optional>
-#include <utility>
-#include <regex>
-
-#include <sched.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <syscall.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-namespace iorap::compiler {
-
-using Inode = iorap::inode2filename::Inode;
-using InodeResult = iorap::inode2filename::InodeResult;
-using SearchDirectories = iorap::inode2filename::SearchDirectories;
-
-template <typename T>
-using ProtobufPtr = iorap::perfetto::ProtobufPtr<T>;
-
-struct PerfettoTraceProtoInfo {
-  /* The perfetto trace proto. */
-  ::iorap::perfetto::PerfettoTraceProto proto;
-  /*
-   * The timestamp limit of the trace.
-   * It's used to truncate the trace file.
-   */
-  uint64_t timestamp_limit_ns;
-  /*
-   * The pid of the app.
-   * If positive, it's used to filter out other page cache events.
-   */
-  int32_t pid;
-};
-
-struct PerfettoTracePtrInfo {
-  /* Deserialized protobuf data containing the perfetto trace. */
-  ProtobufPtr<::perfetto::protos::Trace> trace_ptr;
-  /*
-   * The timestamp limit of the trace.
-   * It's used to truncate the trace file.
-   */
-  uint64_t timestamp_limit_ns;
-  /*
-   * The pid of the app.
-   * If positive, it's used to filter out other page cache events.
-   */
-  int32_t pid;
-};
-
-// Attempt to read protobufs from the filenames.
-// Emits one (or none) protobuf for each filename, in the same order as the filenames.
-// On any errors, the items are dropped (errors are written to the error LOG).
-//
-// All work is done on the same Coordinator as the Subscriber.
-template <typename ProtoT /*extends MessageLite*/>
-auto/*observable<PerfettoTracePtrInfo>*/ ReadProtosFromFileNames(
-    rxcpp::observable<CompilationInput> file_infos) {
-  using BinaryWireProtoT = ::iorap::perfetto::PerfettoTraceProto;
-
-  return file_infos
-    .map([](const CompilationInput& file_info) ->
-         std::optional<PerfettoTraceProtoInfo> {
-      LOG(VERBOSE) << "compiler::ReadProtosFromFileNames " << file_info.filename
-                   << " TimeStampLimit "<< file_info.timestamp_limit_ns
-                   << " Pid " << file_info.pid << " [begin]";
-      std::optional<BinaryWireProtoT> maybe_proto =
-          BinaryWireProtoT::ReadFullyFromFile(file_info.filename);
-      if (!maybe_proto) {
-        LOG(ERROR) << "Failed to read file: " << file_info.filename;
-        return std::nullopt;
-      }
-      return {{std::move(maybe_proto.value()), file_info.timestamp_limit_ns, file_info.pid}};
-    })
-    .filter([](const std::optional<PerfettoTraceProtoInfo>& proto_info) {
-      return proto_info.has_value();
-    })
-    .map([](std::optional<PerfettoTraceProtoInfo>& proto_info) ->
-         PerfettoTraceProtoInfo {
-      return proto_info.value();
-    })  // TODO: refactor to something that flattens the optional, and logs in one operator.
-    .map([](PerfettoTraceProtoInfo& proto_info) ->
-         std::optional<PerfettoTracePtrInfo> {
-      std::optional<ProtobufPtr<ProtoT>> t = proto_info.proto.template MaybeUnserialize<ProtoT>();
-      if (!t) {
-        LOG(ERROR) << "Failed to parse protobuf: ";  // TODO: filename.
-        return std::nullopt;
-      }
-      return {{std::move(t.value()), proto_info.timestamp_limit_ns, proto_info.pid}};
-    })
-    .filter([](const std::optional<PerfettoTracePtrInfo>& trace_info) {
-      return trace_info.has_value();
-    })
-    .map([](std::optional<PerfettoTracePtrInfo>& trace_info) ->
-         PerfettoTracePtrInfo {
-      LOG(VERBOSE) << "compiler::ReadProtosFromFileNames [success]";
-      return trace_info.value();
-      // TODO: protobufs have no move constructor. this might be inefficient?
-    });
-
-/*
-  return filenames
-    .map([](const std::string& filename) {
-      LOG(VERBOSE) << "compiler::ReadProtosFromFileNames " << filename << " [begin]";
-      std::optional<BinaryWireProtoT> maybe_proto =
-          BinaryWireProtoT::ReadFullyFromFile(filename);
-      if (!maybe_proto) {
-        LOG(ERROR) << "Failed to read file: " << filename;
-      }
-
-      std::unique_ptr<BinaryWireProtoT> ptr;
-      if (maybe_proto) {
-        ptr.reset(new BinaryWireProtoT{std::move(*maybe_proto)});
-      }
-      return ptr;
-    })
-    .filter([](const std::unique_ptr<BinaryWireProtoT>& proto) {
-      return proto != nullptr;
-    })
-    .map([](std::unique_ptr<BinaryWireProtoT>& proto) {
-      std::optional<ProtoT> t = proto->template MaybeUnserialize<ProtoT>();
-      if (!t) {
-        LOG(ERROR) << "Failed to parse protobuf: ";  // TODO: filename.
-      }
-      return t;
-    })
-    .filter([](const std::optional<ProtoT>& proto) {
-      return proto.has_value();
-    })
-    .map([](std::optional<ProtoT> proto) -> ProtoT {
-      LOG(VERBOSE) << "compiler::ReadProtosFromFileNames [success]";
-      return std::move(proto.value());
-      // TODO: protobufs have no move constructor. this might be inefficient?
-    });
-    */
-}
-
-auto/*observable<PerfettoTracePtrInfo>*/ ReadPerfettoTraceProtos(
-    std::vector<CompilationInput> file_infos) {
-  auto filename_obs = rxcpp::observable<>::iterate(std::move(file_infos));
-  rxcpp::observable<PerfettoTracePtrInfo> obs =
-      ReadProtosFromFileNames<::perfetto::protos::Trace>(std::move(filename_obs));
-  return obs;
-}
-
-// A flattened data representation of an MmFileMap*FtraceEvent.
-// This representation is used for streaming processing.
-//
-// Note: Perfetto applies a 'union' over all possible fields on all possible devices
-// (and uses the max sizeof per-field).
-//
-// Since all protobuf fields are optional, fields not present on a particular device are always
-// null
-struct PageCacheFtraceEvent {
-  /*
-   * Ftrace buffer-specific
-   */
-  uint32_t cpu;  // e.g. 0-7 for the cpu core number.
-
-  /*
-   * Ftrace-event general data
-   */
-
-  // Nanoseconds since an epoch.
-  // Epoch is configurable by writing into trace_clock.
-  // By default this timestamp is CPU local.
-  uint64_t timestamp;
-  // Kernel pid (do not confuse with userspace pid aka tgid)
-  uint32_t pid;
-
-  // Tagged by our code while parsing the ftraces:
-  uint64_t timestamp_relative;  // timestamp relative to first ftrace within a Trace protobuf.
-  bool add_to_page_cache;  // AddToPageCache=true, DeleteFromPageCache=false.
-
-  /*
-   * mm_filemap-specific data
-   *
-   * Fields are common:
-   * - MmFilemapAddToPageCacheFtraceEvent
-   * - MmFilemapDeleteFromPageCacheFtraceEvent
-   */
-  uint64_t pfn;    // page frame number (physical) - null on some devices, e.g. marlin
-  uint64_t i_ino;  // inode number (use in conjunction with s_dev)
-  uint64_t index;  // offset into file: this is a multiple of the page size (usually 4096).
-  uint64_t s_dev;  // (dev_t) device number
-  uint64_t page;   // struct page*. - null on some devices, e.g. blueline.
-
-  Inode inode() const {
-    return Inode::FromDeviceAndInode(static_cast<dev_t>(s_dev),
-                                     static_cast<ino_t>(i_ino));
-  }
-};
-
-std::ostream& operator<<(std::ostream& os, const PageCacheFtraceEvent& e) {
-  os << "{";
-  os << "cpu:" << e.cpu << ",";
-  os << "timestamp:" << e.timestamp << ",";
-  os << "pid:" << e.pid << ",";
-  os << "timestamp_relative:" << e.timestamp_relative << ",";
-  os << "add_to_page_cache:" << e.add_to_page_cache << ",";
-  os << "pfn:" << e.pfn << ",";
-  os << "i_ino:" << e.i_ino << ",";
-  os << "index:" << e.index << ",";
-  os << "s_dev:" << e.s_dev << ",";
-  os << "page:" << e.page;
-  os << "}";
-
-  return os;
-}
-
-/*
- * Gets the start timestamp.
- *
- * It is the minimium timestamp.
- */
-std::optional<uint64_t> GetStartTimestamp(const ::perfetto::protos::Trace& trace) {
-  std::optional<uint64_t> timestamp_relative_start;
-  // Traverse each timestamp to get the minimium one.
-  for (const ::perfetto::protos::TracePacket& packet : trace.packet()) {
-    if (packet.has_timestamp()) {
-      timestamp_relative_start = timestamp_relative_start?
-          std::min(*timestamp_relative_start, packet.timestamp()) : packet.timestamp();
-    }
-    if (!packet.has_ftrace_events()) {
-      continue;
-    }
-    const ::perfetto::protos::FtraceEventBundle& ftrace_event_bundle =
-        packet.ftrace_events();
-    for (const ::perfetto::protos::FtraceEvent& event : ftrace_event_bundle.event()) {
-      if (event.has_timestamp()) {
-        timestamp_relative_start = timestamp_relative_start?
-            std::min(*timestamp_relative_start, event.timestamp()) : event.timestamp();
-      }
-    }
-  }
-  return timestamp_relative_start;
-}
-
-/*
- * sample blueline output:
- *
- * $ adb shell cat /d/tracing/events/filemap/mm_filemap_add_to_page_cache/format
- *
- * name: mm_filemap_add_to_page_cache
- * ID: 178
- * format:
- * 	field:unsigned short common_type;	offset:0;	size:2;	signed:0;
- * 	field:unsigned char common_flags;	offset:2;	size:1;	signed:0;
- * 	field:unsigned char common_preempt_count;	offset:3;	size:1;	signed:0;
- * 	field:int common_pid;	offset:4;	size:4;	signed:1;
- *
- * 	field:unsigned long pfn;	offset:8;	size:8;	signed:0;
- * 	field:unsigned long i_ino;	offset:16;	size:8;	signed:0;
- * 	field:unsigned long index;	offset:24;	size:8;	signed:0;
- * 	field:dev_t s_dev;	offset:32;	size:4;	signed:0;
- *
- * print fmt: "dev %d:%d ino %lx page=%p pfn=%lu ofs=%lu", ((unsigned int) ((REC->s_dev) >> 20)),
- *            ((unsigned int) ((REC->s_dev) & ((1U << 20) - 1))), REC->i_ino,
- *             (((struct page *)(((0xffffffffffffffffUL) - ((1UL) << ((39) - 1)) + 1) -
- *                 ((1UL) << ((39) - 12 - 1 + 6))) - (memstart_addr >> 12)) + (REC->pfn)),
- *            REC->pfn, REC->index << 12
- */
-
-auto /*observable<PageCacheFtraceEvent>*/ SelectPageCacheFtraceEvents(
-    PerfettoTracePtrInfo trace_info) {
-  const ::perfetto::protos::Trace& trace = *(trace_info.trace_ptr);
-
-  constexpr bool kDebugFunction = true;
-
-  return rxcpp::observable<>::create<PageCacheFtraceEvent>(
-      [trace=std::move(trace),
-      timestamp_limit_ns=trace_info.timestamp_limit_ns,
-      app_pid=trace_info.pid]
-      (rxcpp::subscriber<PageCacheFtraceEvent> sub) {
-    uint64_t timestamp = 0;
-    uint64_t timestamp_relative = 0;
-
-    std::optional<uint64_t> timestamp_relative_start = GetStartTimestamp(trace);
-    uint32_t cpu = 0;
-    uint32_t pid = 0;
-    bool add_to_page_cache = true;
-
-    auto on_next_page_cache_event = [&](const auto& mm_event) {
-      PageCacheFtraceEvent out;
-      out.timestamp = timestamp;
-      out.cpu = cpu;
-      out.pid = pid;
-
-      out.timestamp_relative = timestamp_relative;
-      out.add_to_page_cache = add_to_page_cache;
-
-      out.pfn = mm_event.pfn();
-      out.i_ino = mm_event.i_ino();
-      out.index = mm_event.index();
-      out.s_dev = mm_event.s_dev();
-      out.page = mm_event.page();
-
-      sub.on_next(std::move(out));
-    };
-
-    for (const ::perfetto::protos::TracePacket& packet : trace.packet()) {
-      // Break out of all loops if we are unsubscribed.
-      if (!sub.is_subscribed()) {
-        if (kDebugFunction) LOG(VERBOSE) << "compiler::SelectPageCacheFtraceEvents unsubscribe";
-        return;
-      }
-
-      if (kDebugFunction) LOG(VERBOSE) << "compiler::SelectPageCacheFtraceEvents TracePacket";
-
-      if (packet.has_timestamp()) {
-        timestamp_relative_start = timestamp_relative_start.value_or(packet.timestamp());
-        timestamp = packet.timestamp();  // XX: should we call 'has_timestamp()' ?
-      } else {
-        timestamp = 0;
-      }
-
-      if (packet.has_ftrace_events()) {
-        const ::perfetto::protos::FtraceEventBundle& ftrace_event_bundle =
-            packet.ftrace_events();
-
-        cpu = ftrace_event_bundle.cpu();  // XX: has_cpu ?
-
-        for (const ::perfetto::protos::FtraceEvent& event : ftrace_event_bundle.event()) {
-          // Break out of all loops if we are unsubscribed.
-          if (!sub.is_subscribed()) {
-            return;
-          }
-
-          if (app_pid >= 0 &&
-              (!event.has_pid() ||
-               event.pid() != static_cast<uint32_t>(app_pid))) {
-            continue;
-          }
-
-          if (event.has_timestamp()) {
-            timestamp = event.timestamp();
-            if(timestamp > timestamp_limit_ns) {
-              LOG(VERBOSE) << "The timestamp is " << timestamp <<
-                           ", which exceeds the limit "<< timestamp_limit_ns;
-              continue;
-            }
-          } else {
-            DCHECK(packet.has_timestamp() == false)
-                << "Timestamp in outer packet but not inner packet";
-            // XX: use timestamp from the perfetto TracePacket ???
-            // REVIEWERS: not sure if this is ok, does it use the same clock source and
-            // is the packet data going to be the same clock sample as the Ftrace event?
-          }
-
-          if (timestamp_relative_start){
-            timestamp_relative = timestamp - *timestamp_relative_start;
-          } else {
-            timestamp_relative = 0;
-          }
-
-          pid = event.pid();  // XX: has_pid ?
-
-          if (event.has_mm_filemap_add_to_page_cache()) {
-            add_to_page_cache = true;
-
-            const ::perfetto::protos::MmFilemapAddToPageCacheFtraceEvent& mm_event =
-                event.mm_filemap_add_to_page_cache();
-
-            on_next_page_cache_event(mm_event);
-          } else if (event.has_mm_filemap_delete_from_page_cache()) {
-            add_to_page_cache = false;
-
-            const ::perfetto::protos::MmFilemapDeleteFromPageCacheFtraceEvent& mm_event =
-                event.mm_filemap_delete_from_page_cache();
-
-            on_next_page_cache_event(mm_event);
-          }
-        }
-      } else {
-        if (kDebugFunction) {
-          LOG(VERBOSE) << "compiler::SelectPageCacheFtraceEvents no ftrace event bundle";
-        }
-      }
-    }
-
-    if (kDebugFunction) {
-      LOG(VERBOSE) << "compiler::SelectPageCacheFtraceEvents#on_completed";
-    }
-
-    // Let subscriber know there are no more items.
-    sub.on_completed();
-  });
-}
-
-auto /*observable<Inode*/ SelectDistinctInodesFromTraces(
-    rxcpp::observable<PerfettoTracePtrInfo> traces) {
-  // Emit only unique (s_dev, i_ino) pairs from all Trace protos.
-  auto obs = traces
-    .flat_map([](PerfettoTracePtrInfo trace) {
-      rxcpp::observable<PageCacheFtraceEvent> obs = SelectPageCacheFtraceEvents(std::move(trace));
-      // FIXME: dont check this in
-      // return obs;
-      //return obs.take(100);   // for faster development
-      return obs;
-    })  // TODO: Upstream bug? using []()::perfetto::protos::Trace&) causes a compilation error.
-    .map([](const PageCacheFtraceEvent& event) -> Inode {
-      return Inode::FromDeviceAndInode(static_cast<dev_t>(event.s_dev),
-                                       static_cast<ino_t>(event.i_ino));
-    })
-    .tap([](const Inode& inode) {
-      LOG(VERBOSE) << "SelectDistinctInodesFromTraces (pre-distinct): " << inode;
-    })
-    .distinct()  // observable<Inode>*/
-    ;
-
-  return obs;
-}
-// TODO: static assert checks for convertible return values.
-
-auto/*observable<InodeResult>*/ ResolveInodesToFileNames(
-    rxcpp::observable<Inode> inodes,
-    inode2filename::InodeResolverDependencies dependencies) {
-  std::shared_ptr<inode2filename::InodeResolver> inode_resolver =
-      inode2filename::InodeResolver::Create(std::move(dependencies));
-  return inode_resolver->FindFilenamesFromInodes(std::move(inodes));
-}
-
-using InodeMap = std::unordered_map<Inode, std::string /*filename*/>;
-auto /*just observable<InodeMap>*/ ReduceResolvedInodesToMap(
-      rxcpp::observable<InodeResult> inode_results) {
-  return inode_results.reduce(
-    InodeMap{},
-    [](InodeMap m, InodeResult result) {
-      if (result) {
-        LOG(VERBOSE) << "compiler::ReduceResolvedInodesToMap insert " << result;
-        m.insert({std::move(result.inode), std::move(result.data.value())});
-      } else {
-        // TODO: side stats for how many of these are failed to resolve?
-        LOG(WARNING) << "compiler: Failed to resolve inode, " << result;
-      }
-      return m;
-    },
-    [](InodeMap m) {
-      return m;  // TODO: use an identity function
-    }); // emits exactly 1 InodeMap value.
-}
-
-struct ResolvedPageCacheFtraceEvent {
-  std::string filename;
-  PageCacheFtraceEvent event;
-};
-
-std::ostream& operator<<(std::ostream& os, const ResolvedPageCacheFtraceEvent& e) {
-  os << "{";
-  os << "filename:\"" << e.filename << "\",";
-  os << e.event;
-  os << "}";
-
-  return os;
-}
-
-struct CombinedState {
-  CombinedState() = default;
-  explicit CombinedState(InodeMap inode_map) : inode_map{std::move(inode_map)} {}
-  explicit CombinedState(PageCacheFtraceEvent event) : ftrace_event{std::move(event)} {}
-
-  CombinedState(InodeMap inode_map, PageCacheFtraceEvent event)
-    : inode_map(std::move(inode_map)),
-      ftrace_event{std::move(event)} {}
-
-  std::optional<InodeMap> inode_map;
-  std::optional<PageCacheFtraceEvent> ftrace_event;
-
-  bool HasAll() const {
-    return inode_map.has_value() && ftrace_event.has_value();
-  }
-
-  const InodeMap& GetInodeMap() const {
-    DCHECK(HasAll());
-    return inode_map.value();
-  }
-
-  InodeMap& GetInodeMap() {
-    DCHECK(HasAll());
-    return inode_map.value();
-  }
-
-  const PageCacheFtraceEvent& GetEvent() const {
-    DCHECK(HasAll());
-    return ftrace_event.value();
-  }
-
-  PageCacheFtraceEvent& GetEvent() {
-    DCHECK(HasAll());
-    return ftrace_event.value();
-  }
-
-  void Merge(CombinedState&& other) {
-    if (other.inode_map) {
-      inode_map = std::move(other.inode_map);
-    }
-    if (other.ftrace_event) {
-      ftrace_event = std::move(other.ftrace_event);
-    }
-  }
-};
-
-std::ostream& operator<<(std::ostream& os, const CombinedState& s) {
-  os << "CombinedState{inode_map:";
-  if (s.inode_map) {
-    os << "|sz=" << (s.inode_map.value().size()) << "|";
-  } else {
-    os << "(null)";
-  }
-  os << ",event:";
-  if (s.ftrace_event) {
-    //os << s.ftrace_event.value().timestamp << "ns";
-    os << s.ftrace_event.value();
-  } else {
-    os << "(null)";
-  }
-  os << "}";
-  return os;
-}
-
-auto/*observable<ResolvedPageCacheFtraceEvent>*/ ResolvePageCacheEntriesFromProtos(
-    rxcpp::observable<PerfettoTracePtrInfo> traces,
-    inode2filename::InodeResolverDependencies dependencies) {
-
-  // 1st chain = emits exactly 1 InodeMap.
-
-  // [proto, proto, proto...] -> [inode, inode, inode, ...]
-  auto/*observable<Inode>*/ distinct_inodes = SelectDistinctInodesFromTraces(traces);
-  rxcpp::observable<Inode> distinct_inodes_obs = distinct_inodes.as_dynamic();
-  // [inode, inode, inode, ...] -> [(inode, {filename|error}), ...]
-  auto/*observable<InodeResult>*/ inode_names = ResolveInodesToFileNames(distinct_inodes_obs,
-                                                                         std::move(dependencies));
-  // rxcpp has no 'join' operators, so do a manual join with concat.
-  auto/*observable<InodeMap>*/ inode_name_map = ReduceResolvedInodesToMap(inode_names);
-
-  // 2nd chain = emits all PageCacheFtraceEvent
-  auto/*observable<PageCacheFtraceEvent>*/ page_cache_ftrace_events = traces
-    .flat_map([](PerfettoTracePtrInfo trace) {
-      rxcpp::observable<PageCacheFtraceEvent> obs = SelectPageCacheFtraceEvents(std::move(trace));
-      return obs;
-    });
-
-  auto inode_name_map_precombine = inode_name_map
-    .map([](InodeMap inode_map) {
-      LOG(VERBOSE) << "compiler::ResolvePageCacheEntriesFromProtos#inode_name_map_precombine ";
-      return CombinedState{std::move(inode_map)};
-    });
-
-  auto page_cache_ftrace_events_precombine = page_cache_ftrace_events
-    .map([](PageCacheFtraceEvent event) {
-      LOG(VERBOSE)
-          << "compiler::ResolvePageCacheEntriesFromProtos#page_cache_ftrace_events_precombine "
-          << event;
-      return CombinedState{std::move(event)};
-    });
-
-  // Combine 1st+2nd chain.
-  //
-  // concat subscribes to each observable, waiting until its completed, before subscribing
-  // to the next observable and waiting again.
-  //
-  // During all this, every #on_next is immediately forwarded to the downstream observables.
-  // In our case, we want to block until InodeNameMap is ready, and re-iterate all ftrace events.
-  auto/*observable<ResolvedPageCacheFtraceEvent>*/ resolved_events = inode_name_map_precombine
-    .concat(page_cache_ftrace_events_precombine)
-    .scan(CombinedState{},
-          [](CombinedState current_state, CombinedState delta_state) {
-            LOG(VERBOSE) << "compiler::ResolvePageCacheEntriesFromProtos#scan "
-                          << "current=" << current_state << ","
-                          << "delta=" << delta_state;
-            // IT0    = (,)               + (InodeMap,)
-            // IT1    = (InodeMap,)       + (,Event)
-            // IT2..N = (InodeMap,Event1) + (,Event2)
-            current_state.Merge(std::move(delta_state));
-            return current_state;
-          })
-    .filter([](const CombinedState& state) {
-      return state.HasAll();
-    })
-    .map([](CombinedState& state) -> std::optional<ResolvedPageCacheFtraceEvent> {
-      PageCacheFtraceEvent& event = state.GetEvent();
-      const InodeMap& inode_map = state.GetInodeMap();
-
-      auto it = inode_map.find(event.inode());
-      if (it != inode_map.end()) {
-        std::string filename = it->second;
-        LOG(VERBOSE) << "compiler::ResolvePageCacheEntriesFromProtos combine_latest " << event;
-        return ResolvedPageCacheFtraceEvent{std::move(filename), std::move(event)};
-      } else {
-        LOG(ERROR) << "compiler: FtraceEvent's inode did not have resolved filename: " << event;
-        return std::nullopt;
-      }
-    })
-    .filter(
-      [](std::optional<ResolvedPageCacheFtraceEvent> maybe_event) {
-        return maybe_event.has_value();
-      })
-    .map([](std::optional<ResolvedPageCacheFtraceEvent> maybe_event) {
-      return std::move(maybe_event.value());
-    });
-    // -> observable<ResolvedPageCacheFtraceEvent>
-
-  return resolved_events;
-}
-
-namespace detail {
-bool multiless_one(const std::string& a, const std::string& b) {
-  return std::lexicographical_compare(a.begin(), a.end(),
-                                      b.begin(), b.end());
-}
-
-template <typename T>
-constexpr bool multiless_one(T&& a, T&& b) {   // a < b
-  using std::less;  // ADL
-  return less<std::decay_t<T>>{}(std::forward<T>(a), std::forward<T>(b));
-}
-
-constexpr bool multiless() {
-  return false;  // [] < [] is always false.
-}
-
-template <typename T, typename ... Args>
-constexpr bool multiless(T&& a, T&& b, Args&&... args) {
-  if (a != b) {
-    return multiless_one(std::forward<T>(a), std::forward<T>(b));
-  } else {
-    return multiless(std::forward<Args>(args)...);
-  }
-}
-
-}  // namespace detail
-
-// Return [A0...An] < [B0...Bn] ; vector-like scalar comparison of each field.
-// Arguments are passed in the order A0,B0,A1,B1,...,An,Bn.
-template <typename ... Args>
-constexpr bool multiless(Args&&... args) {
-  return detail::multiless(std::forward<Args>(args)...);
-}
-
-struct CompilerPageCacheEvent {
-  std::string filename;
-  uint64_t timestamp_relative;  // use relative timestamp because absolute values aren't comparable
-                                // across different trace protos.
-                                // relative timestamps can be said to be 'approximately' comparable.
-                                // assuming we compare the same application startup's trace times.
-  bool add_to_page_cache;  // AddToPageCache=true, DeleteFromPageCache=false.
-  uint64_t index;          // offset into file: this is a multiple of the page size (usually 4096).
-
-  // All other data from the ftrace is dropped because we don't currently use it in the
-  // compiler algorithms.
-
-  CompilerPageCacheEvent() = default;
-  CompilerPageCacheEvent(const ResolvedPageCacheFtraceEvent& resolved)
-    : CompilerPageCacheEvent(resolved.filename, resolved.event) {
-  }
-
-  CompilerPageCacheEvent(ResolvedPageCacheFtraceEvent&& resolved)
-    : CompilerPageCacheEvent(std::move(resolved.filename), std::move(resolved.event)) {
-  }
-
-  // Compare all fields (except the timestamp field).
-  static bool LessIgnoringTimestamp(const CompilerPageCacheEvent& a,
-                                    const CompilerPageCacheEvent& b) {
-    return multiless(a.filename, b.filename,
-                     a.add_to_page_cache, b.add_to_page_cache,
-                     a.index, b.index);
-  }
-
-  // Compare all fields. Timestamps get highest precedence.
-  bool operator<(const CompilerPageCacheEvent& rhs) const {
-    return multiless(timestamp_relative, rhs.timestamp_relative,
-                     filename, rhs.filename,
-                     add_to_page_cache, rhs.add_to_page_cache,
-                     index, rhs.index);
-  }
-
- private:
-  CompilerPageCacheEvent(std::string filename, const PageCacheFtraceEvent& event)
-    : filename(std::move(filename)),
-      timestamp_relative(event.timestamp_relative),
-      add_to_page_cache(event.add_to_page_cache),
-      index(event.index) {
-   }
-};
-
-std::ostream& operator<<(std::ostream& os, const CompilerPageCacheEvent& e) {
-  os << "{";
-  os << "filename:\"" << e.filename << "\",";
-  os << "timestamp:" << e.timestamp_relative << ",";
-  os << "add_to_page_cache:" << e.add_to_page_cache << ",";
-  os << "index:" << e.index;
-  os << "}";
-  return os;
-}
-
-// Filter an observable chain of 'ResolvedPageCacheFtraceEvent'
-// into an observable chain of 'ResolvedPageCacheFtraceEvent'.
-//
-// Any items emitted by the input chain that match the regular expression
-// specified by blacklist_filter are not emitted into the output chain.
-auto/*observable<ResolvedPageCacheFtraceEvent>*/ ApplyBlacklistToPageCacheEvents(
-    rxcpp::observable<ResolvedPageCacheFtraceEvent> resolved_events,
-    std::optional<std::string> blacklist_filter) {
-  bool has_re = blacklist_filter.has_value();
-  // default regex engine is ecmascript.
-  std::regex reg_exp{blacklist_filter ? *blacklist_filter : std::string("")};
-
-  return resolved_events.filter(
-    [reg_exp, has_re](const ResolvedPageCacheFtraceEvent& event) {
-      if (!has_re) {
-        return true;
-      }
-      // Remove any entries that match the regex in --blacklist-filter/-bf.
-      bool res = std::regex_search(event.filename, reg_exp);
-      if (res) {
-        LOG(VERBOSE) << "Blacklist filter removed '" << event.filename << "' from chain.";
-      }
-      return !res;
-    });
-}
-
-// Compile an observable chain of 'ResolvedPageCacheFtraceEvent' into
-// an observable chain of distinct, timestamp-ordered, CompilerPageCacheEvent.
-//
-// This is a reducing operation: No items are emitted until resolved_events is completed.
-auto/*observable<CompilerPageCacheEvent>*/ CompilePageCacheEvents(
-    rxcpp::observable<ResolvedPageCacheFtraceEvent> resolved_events) {
-
-  struct CompilerPageCacheEventIgnoringTimestampLess {
-    bool operator()(const CompilerPageCacheEvent& lhs,
-                    const CompilerPageCacheEvent& rhs) const {
-      return CompilerPageCacheEvent::LessIgnoringTimestamp(lhs, rhs);
-    }
-  };
-
-  // Greedy O(N) compilation algorithm.
-  //
-  // This produces an inoptimal result (e.g. a small timestamp
-  // that might occur only 1% of the time nevertheless wins out), but the
-  // algorithm itself is quite simple, and doesn't require any heuristic tuning.
-
-  // First pass: *Merge* into set that ignores the timestamp value for order, but retains
-  //             the smallest timestamp value if the same key is re-inserted.
-  using IgnoreTimestampForOrderingSet =
-      std::set<CompilerPageCacheEvent, CompilerPageCacheEventIgnoringTimestampLess>;
-  // Second pass: *Sort* data by smallest timestamp first.
-  using CompilerPageCacheEventSet =
-      std::set<CompilerPageCacheEvent>;
-
-  return resolved_events
-    .map(
-      [](ResolvedPageCacheFtraceEvent event) {
-        // Drop all the extra metadata like pid, cpu, etc.
-        // When we merge we could keep a list of the original data, but there is no advantage
-        // to doing so.
-        return CompilerPageCacheEvent{std::move(event)};
-      }
-    )
-   .reduce(
-    IgnoreTimestampForOrderingSet{},
-    [](IgnoreTimestampForOrderingSet set, CompilerPageCacheEvent event) {
-      // Add each event to the set, keying by everything but the timestamp.
-      // If the key is already inserted, re-insert with the smaller timestamp value.
-      auto it = set.find(event);
-
-      if (it == set.end()) {
-        // Need to insert new element.
-        set.insert(std::move(event));
-      } else if (it->timestamp_relative > event.timestamp_relative) {
-        // Replace existing element: the new element has a smaller timestamp.
-        it = set.erase(it);
-        // Amortized O(1) time if insertion happens in the position before the hint.
-        set.insert(it, std::move(event));
-      } // else: Skip insertion. Element already present with the minimum timestamp.
-
-      return set;
-    },
-    [](IgnoreTimestampForOrderingSet set) {
-      // Extract all elements from 'set', re-insert into 'ts_set'.
-      // The values are now ordered by timestamp (and then the rest of the fields).
-      CompilerPageCacheEventSet ts_set;
-      ts_set.merge(std::move(set));
-
-
-      std::shared_ptr<CompilerPageCacheEventSet> final_set{
-          new CompilerPageCacheEventSet{std::move(ts_set)}};
-      return final_set;
-      // return ts_set;
-    })  // observable<CompilerPageCacheEventSet> (just)
-  .flat_map(
-    [](std::shared_ptr<CompilerPageCacheEventSet> final_set) {
-      // TODO: flat_map seems to make a copy of the parameter _every single iteration_
-      // without the shared_ptr it would just make a copy of the set every time it went
-      // through the iterate function.
-      // Causing absurdly slow compile times x1000 slower than we wanted.
-      // TODO: file a bug upstream and/or fix upstream.
-      CompilerPageCacheEventSet& ts_set = *final_set;
-    // [](CompilerPageCacheEventSet& ts_set) {
-      LOG(DEBUG) << "compiler: Merge-pass completed (" << ts_set.size() << " entries).";
-      //return rxcpp::sources::iterate(std::move(ts_set));
-      return rxcpp::sources::iterate(ts_set).map([](CompilerPageCacheEvent e) { return e; });
-    }
-  );   // observable<CompilerPageCacheEvent>
-}
-
-/** Makes a vector of info that includes filename and timestamp limit. */
-std::vector<CompilationInput> MakeCompilationInputs(
-    std::vector<std::string> input_file_names,
-    std::vector<uint64_t> timestamp_limit_ns,
-    std::vector<int32_t> pids){
-  // If the timestamp limit is empty, set the limit to max value
-  // for each trace file.
-  if (timestamp_limit_ns.empty()) {
-    for (size_t i = 0; i < input_file_names.size(); i++) {
-      timestamp_limit_ns.push_back(std::numeric_limits<uint64_t>::max());
-    }
-  }
-
-  // If the pids is empty, set all of them to -1. Because negative pid means any.
-  if (pids.empty()) {
-    for (size_t i = 0; i < input_file_names.size(); i++) {
-      pids.push_back(-1);
-    }
-  }
-
-  DCHECK_EQ(input_file_names.size(), timestamp_limit_ns.size());
-  std::vector<CompilationInput> file_infos;
-  for (size_t i = 0; i < input_file_names.size(); i++) {
-    file_infos.push_back({input_file_names[i], timestamp_limit_ns[i], pids[i]});
-  }
-  return file_infos;
-}
-
-bool PerformCompilation(std::vector<CompilationInput> perfetto_traces,
-                        std::string output_file_name,
-                        bool output_proto,
-                        std::optional<std::string> blacklist_filter,
-                        inode2filename::InodeResolverDependencies dependencies) {
-  auto trace_protos = ReadPerfettoTraceProtos(std::move(perfetto_traces));
-  auto resolved_events = ResolvePageCacheEntriesFromProtos(std::move(trace_protos),
-                                                           std::move(dependencies));
-  auto filtered_events =
-      ApplyBlacklistToPageCacheEvents(std::move(resolved_events), blacklist_filter);
-  auto compiled_events = CompilePageCacheEvents(std::move(filtered_events));
-
-  std::ofstream ofs;
-  if (!output_file_name.empty()) {
-
-    if (!output_proto) {
-      ofs.open(output_file_name);
-
-      if (!ofs) {
-        LOG(ERROR) << "compiler: Failed to open output file for writing: " << output_file_name;
-        return false;
-      }
-    }
-  }
-
-  auto trace_file_proto = serialize::ArenaPtr<serialize::proto::TraceFile>::Make();
-
-  // Fast lookup of filename -> FileIndex id.
-  std::unordered_map<std::string, int64_t /*file handle id*/> file_path_map;
-  int64_t file_handle_id = 0;
-
-  int counter = 0;
-  compiled_events
-    // .as_blocking()
-    .tap([&](CompilerPageCacheEvent& event) {
-      if (!output_proto) {
-        return;
-      }
-
-      if (!event.add_to_page_cache) {
-        // Skip DeleteFromPageCache events, they are only used for intermediate.
-        return;
-      }
-
-      DCHECK(trace_file_proto->mutable_index() != nullptr);
-      serialize::proto::TraceFileIndex& index = *trace_file_proto->mutable_index();
-      int64_t file_handle;
-
-      // Add TraceFileIndexEntry if it doesn't exist.
-
-      auto it = file_path_map.find(event.filename);
-      if (it == file_path_map.end()) {
-        file_handle = file_handle_id++;
-        file_path_map[event.filename] = file_handle;
-
-        serialize::proto::TraceFileIndexEntry* entry = index.add_entries();
-        DCHECK(entry != nullptr);
-        entry->set_id(file_handle);
-        entry->set_file_name(event.filename);
-
-        if (kIsDebugBuild) {
-          int i = static_cast<int>(file_handle);
-          const serialize::proto::TraceFileIndexEntry& entry_ex = index.entries(i);
-          DCHECK_EQ(entry->id(), entry_ex.id());
-          DCHECK_EQ(entry->file_name(), entry_ex.file_name());
-        }
-      } else {
-        file_handle = it->second;
-      }
-      int kPageSize = 4096;  // TODO: don't hardcode the page size.
-
-      int entry_size = trace_file_proto->list().entries_size();
-      bool merged = false;
-      if (entry_size > 0) {
-        serialize::proto::TraceFileEntry* entry =
-            trace_file_proto->mutable_list()->mutable_entries(entry_size-1);
-        if (entry->index_id() == file_handle &&
-            entry->file_offset() + entry->file_length() ==
-            static_cast<int64_t>(event.index) * kPageSize) {
-          entry->set_file_length(entry->file_length() + kPageSize);
-          merged = true;
-        }
-      }
-
-      if (!merged) {
-        // Add TraceFileEntry.
-        DCHECK(trace_file_proto->mutable_list() != nullptr);
-        serialize::proto::TraceFileEntry* entry = trace_file_proto->mutable_list()->add_entries();
-        DCHECK(entry != nullptr);
-
-        entry->set_index_id(file_handle);
-        // Page index -> file offset in bytes.
-        entry->set_file_offset(static_cast<int64_t>(event.index) * kPageSize);
-        entry->set_file_length(kPageSize);
-      }
-    })
-    .subscribe([&](CompilerPageCacheEvent event) {
-      if (!output_proto) {
-        if (output_file_name.empty()) {
-          LOG(INFO) << "CompilerPageCacheEvent" << event << std::endl;
-        } else {
-          ofs << event << "\n";  // TODO: write in proto format instead.
-        }
-      }
-      ++counter;
-    });
-
-  if (output_proto) {
-    LOG(DEBUG) << "compiler: WriteFully to begin into " << output_file_name;
-    ::google::protobuf::MessageLite& message = *trace_file_proto.get();
-    if (auto res = serialize::ProtobufIO::WriteFully(message, output_file_name); !res) {
-      errno = res.error();
-      PLOG(ERROR) << "compiler: Failed to write protobuf to file: " << output_file_name;
-      return false;
-    } else {
-      LOG(INFO) << "compiler: Wrote protobuf " << output_file_name;
-    }
-  }
-
-  LOG(DEBUG) << "compiler: Compilation completed (" << counter << " events).";
-
-  return true;
-}
-
-}  // namespace iorap::compiler
diff --git a/src/compiler/compiler.h b/src/compiler/compiler.h
deleted file mode 100644
index 243ab36..0000000
--- a/src/compiler/compiler.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_COMPILER_COMPILER_H_
-#define IORAP_SRC_COMPILER_COMPILER_H_
-
-#include "inode2filename/inode_resolver.h"
-
-#include <optional>
-#include <string>
-#include <vector>
-
-namespace iorap::compiler {
-struct  CompilationInput {
-  /* The name of the perfetto trace. */
-  std::string filename;
-  /*
-   * The timestamp limit of the trace.
-   * It's used to truncate the trace file.
-   */
-  uint64_t timestamp_limit_ns;
-
-  /*
-   * The pid of the app.
-   * If positive, it's used to filter out other page cache events.
-   */
-  int32_t pid;
-};
-
-// Compile one or more perfetto TracePacket protobufs that are stored on the filesystem
-// by the filenames given with `input_file_names` and timestamp limit given with
-// timestamp_limit_ns.
-//
-// For each input file name and timestamp limit, ignore any events from the input that
-// exceed the associated timestamp limit.
-//
-// If blacklist_filter is non-null, ignore any file entries whose file path matches the
-// regular expression in blacklist_filter.
-//
-// The result is stored into the file path specified by `output_file_name`.
-//
-// This is a blocking function which returns only when compilation finishes. The return value
-// determines success/failure.
-//
-// Operation is transactional -- that is if there is a failure, `output_file_name` is untouched.
-bool PerformCompilation(std::vector<iorap::compiler::CompilationInput> perfetto_traces,
-                        std::string output_file_name,
-                        bool output_proto,
-                        std::optional<std::string> blacklist_filter,
-                        inode2filename::InodeResolverDependencies dependencies);
-
-// The size and order of timestamp_limit_ns should match that of
-// input_file_names, if not empty.
-// If timestamp_limit_ns is empty, will use the max uint64_t.
-std::vector<CompilationInput> MakeCompilationInputs(
-    std::vector<std::string> input_file_names,
-    std::vector<uint64_t> timestamp_limit_ns,
-    std::vector<int32_t> pids);
-}
-
-#endif  // IORAP_SRC_COMPILER_COMPILER_H_
diff --git a/src/compiler/main.cc b/src/compiler/main.cc
deleted file mode 100644
index 3036936..0000000
--- a/src/compiler/main.cc
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "common/cmd_utils.h"
-#include "common/debug.h"
-#include "compiler/compiler.h"
-#include "inode2filename/inode_resolver.h"
-
-#include <android-base/parseint.h>
-#include <android-base/logging.h>
-
-#include <iostream>
-#include <limits>
-#include <optional>
-#include <string>
-
-#if defined(IORAP_COMPILER_MAIN)
-
-namespace iorap::compiler {
-
-// Log everything to stderr.
-// Log errors and higher to logd.
-class StderrAndLogdErrorLogger {
- public:
-  explicit StderrAndLogdErrorLogger(android::base::LogId default_log_id = android::base::MAIN)
-#ifdef __ANDROID__
-      : logd_(default_log_id)
-#endif
-  {
-  }
-
-  void operator()(::android::base::LogId id,
-                  ::android::base::LogSeverity sev,
-                  const char* tag,
-                  const char* file,
-                  unsigned int line,
-                  const char* message) {
-#ifdef __ANDROID__
-    if (static_cast<int>(sev) >= static_cast<int>(::android::base::ERROR)) {
-      logd_(id, sev, tag, file, line, message);
-    }
-#endif
-    StderrLogger(id, sev, tag, file, line, message);
-  }
-
- private:
-#ifdef __ANDROID__
-  ::android::base::LogdLogger logd_;
-#endif
-};
-
-void Usage(char** argv) {
-  std::cerr << "Usage: " << argv[0] << " [--output-proto=output.pb] input1.pb [input2.pb ...]" << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "  Request a compilation of multiple inputs (format: PerfettoTraceProto)." << std::endl;
-  std::cerr << "  The result is a TraceFile, representing a merged compiled trace with inodes resolved." << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "  Optional flags:" << std::endl;
-  std::cerr << "    --help,-h                  Print this Usage." << std::endl;
-  std::cerr << "    --denylist-filter,-df     Specify regex acting as a denylist filter."
-            << std::endl;
-  std::cerr << "                               Filepaths matching this regex are removed from the output file." << std::endl;
-  std::cerr << "    --output-text,-ot          Output ascii text instead of protobuf (default off)." << std::endl;
-  std::cerr << "    --output-proto $,-op $     TraceFile tracebuffer output file (default stdout)." << std::endl;
-  std::cerr << "    --inode-textcache $,-it $  Resolve inode->filename from textcache (disables diskscan)." << std::endl;
-  std::cerr << "    --verbose,-v               Set verbosity (default off)." << std::endl;
-  std::cerr << "    --wait,-w                  Wait for key stroke before continuing (default off)." << std::endl;
-  std::cerr << "    --pid,-p                   Set the pid for the compiled trace" << std::endl;
-  std::cerr << "    --timestamp_limit_ns,-tl   Set the limit timestamp in nanoseconds for the compiled trace. "
-                                              "The order and size of the timestamp should match that of "
-                                              "the input trace files. If not specified at all, All of"
-                                              "the timestamps are set to max."<< std::endl;
-  exit(1);
-}
-
-int Main(int argc, char** argv) {
-  android::base::InitLogging(argv);
-  android::base::SetLogger(StderrAndLogdErrorLogger{});
-
-  bool wait_for_keystroke = false;
-  bool enable_verbose = false;
-
-  std::optional<std::string> arg_blacklist_filter;
-  std::string arg_output_proto;
-  bool arg_output_text = false;
-  std::optional<std::string> arg_inode_textcache;
-
-  std::vector<uint64_t> timestamp_limit_ns;
-  std::vector<int32_t> pids;
-
-  if (argc == 1) {
-    // Need at least 1 input file to do anything.
-    Usage(argv);
-  }
-
-  std::vector<std::string> arg_input_filenames;
-
-  for (int arg = 1; arg < argc; ++arg) {
-    std::string argstr = argv[arg];
-    bool has_arg_next = (arg+1)<argc;
-    std::string arg_next = has_arg_next ? argv[arg+1] : "";
-
-    if (argstr == "--help" || argstr == "-h") {
-      Usage(argv);
-    } else if (argstr == "--output-proto" || argstr == "-op") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --output-proto <value>" << std::endl;
-        return 1;
-      }
-      arg_output_proto = arg_next;
-      ++arg;
-    } else if (argstr == "--output-text" || argstr == "-ot") {
-      arg_output_text = true;
-    } else if (argstr == "--inode-textcache" || argstr == "-it") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --inode-textcache <value>" << std::endl;
-        return 1;
-      }
-      arg_inode_textcache = arg_next;
-      ++arg;
-    } else if (argstr == "--denylist-filter" || argstr == "-df") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --denylist-filter <value>" << std::endl;
-        return 1;
-      }
-      arg_blacklist_filter = arg_next;
-      ++arg;
-    }
-    else if (argstr == "--verbose" || argstr == "-v") {
-      enable_verbose = true;
-    } else if (argstr == "--wait" || argstr == "-w") {
-      wait_for_keystroke = true;
-    } else if (argstr == "--pid" || argstr == "-p") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --pid <value>" << std::endl;
-        return 1;
-      }
-      int32_t pid;
-      if (!::android::base::ParseInt<int32_t>(arg_next, &pid)) {
-        std::cerr << "Invalid --pid "<< arg_next << std::endl;
-        return 1;
-      }
-      pids.push_back(pid);
-      ++arg;
-    } else if (argstr == "--timestamp_limit_ns" || argstr == "-tl") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --timestamp_limit_ns <value>" << std::endl;
-        return 1;
-      }
-      uint64_t timestamp;
-      if (!::android::base::ParseUint<uint64_t>(arg_next, &timestamp)) {
-        std::cerr << "Invalid --timestamp-limit-ns "<< arg_next << std::endl;
-        return 1;
-      }
-      timestamp_limit_ns.push_back(timestamp);
-      ++arg;
-    } else {
-      arg_input_filenames.push_back(argstr);
-    }
-  }
-
-  if (!timestamp_limit_ns.empty() &&
-      timestamp_limit_ns.size() != arg_input_filenames.size()) {
-    std::cerr << "The size of timestamp limits doesn't match the size of input files."
-              << std::endl;
-    return 1;
-  }
-
-  if (!pids.empty() && pids.size() != arg_input_filenames.size()) {
-    std::cerr << "The size of pids doesn't match the size of input files."
-              << std::endl;
-    return 1;
-  }
-  if (enable_verbose) {
-    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
-
-    LOG(VERBOSE) << "Verbose check";
-    LOG(VERBOSE) << "Debug check: " << ::iorap::kIsDebugBuild;
-  } else {
-    android::base::SetMinimumLogSeverity(android::base::DEBUG);
-  }
-
-  // Useful to attach a debugger...
-  // 1) $> iorap.cmd.compiler -w <args>
-  // 2) $> gdbclient <pid>
-  if (wait_for_keystroke) {
-    LOG(INFO) << "Self pid: " << getpid();
-    LOG(INFO) << "Press any key to continue...";
-    std::cin >> wait_for_keystroke;
-  }
-
-  auto system_call = std::make_unique<SystemCallImpl>();
-
-  using namespace inode2filename;
-
-  InodeResolverDependencies ir_dependencies;
-  // Passed from command-line.
-  if (arg_inode_textcache) {
-    ir_dependencies.data_source = DataSourceKind::kTextCache;
-    ir_dependencies.text_cache_filename = arg_inode_textcache;
-    ir_dependencies.verify = VerifyKind::kNone;  // required for determinism.
-  } else {
-    ir_dependencies.data_source = DataSourceKind::kDiskScan;
-    LOG(WARNING) << "--inode-textcache unspecified. "
-                 << "Inodes will be resolved by scanning the disk, which makes compilation "
-                 << "non-deterministic.";
-  }
-  // TODO: add command line.
-  ir_dependencies.root_directories.push_back("/system");
-  ir_dependencies.root_directories.push_back("/apex");
-  ir_dependencies.root_directories.push_back("/data");
-  ir_dependencies.root_directories.push_back("/vendor");
-  ir_dependencies.root_directories.push_back("/product");
-  ir_dependencies.root_directories.push_back("/metadata");
-  // Hardcoded.
-  if (iorap::common::GetBoolEnvOrProperty("iorap.inode2filename.out_of_process", true)) {
-    ir_dependencies.process_mode = ProcessMode::kOutOfProcessIpc;
-  } else {
-    ir_dependencies.process_mode = ProcessMode::kInProcessDirect;
-  }
-  ir_dependencies.system_call = /*borrowed*/system_call.get();
-
-  int return_code = 0;
-  std::vector<CompilationInput> perfetto_traces =
-      MakeCompilationInputs(arg_input_filenames, timestamp_limit_ns, pids);
-  return_code =
-      !PerformCompilation(std::move(perfetto_traces),
-                          std::move(arg_output_proto),
-                          !arg_output_text,
-                          arg_blacklist_filter,
-                          std::move(ir_dependencies));
-
-  // Uncomment this if we want to leave the process around to inspect it from adb shell.
-  // sleep(100000);
-
-  // 0 -> successfully wrote the proto out to file.
-  // 1 -> failed along the way (#on_error and also see the error logs).
-  return return_code;
-}
-
-}  // namespace iorap::compiler
-
-int main(int argc, char** argv) {
-  return ::iorap::compiler::Main(argc, argv);
-}
-
-#endif  // IORAP_COMPILER_MAIN
diff --git a/src/db/app_component_name.h b/src/db/app_component_name.h
deleted file mode 100644
index e364163..0000000
--- a/src/db/app_component_name.h
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_DB_APP_COMPONENT_NAME_H_
-#define IORAP_SRC_DB_APP_COMPONENT_NAME_H_
-
-namespace iorap::db {
-
-struct AppComponentName {
-  std::string package;
-  std::string activity_name;
-
-  // Turns the activity name to the fully qualified name.
-  // For example, if the activity name is ".MainActivity" and the package is
-  // foo.bar. Then the fully qualified name is foo.bar.MainActivity.
-  AppComponentName Canonicalize() const {
-    if (!activity_name.empty() && activity_name[0] == '.') {
-      return {package, package + activity_name};
-    }
-    return {package, activity_name};
-  }
-
-  static bool HasAppComponentName(const std::string& s) {
-    return s.find('/') != std::string::npos;
-  }
-
-  // "com.foo.bar/.A" -> {"com.foo.bar", ".A"}
-  static AppComponentName FromString(const std::string& s) {
-    constexpr const char delimiter = '/';
-
-    if (!HasAppComponentName(s)) {
-      return {std::move(s), ""};
-    }
-
-    std::string package = s.substr(0, s.find(delimiter));
-
-    std::string activity_name = s;
-    activity_name.erase(0, s.find(delimiter) + sizeof(delimiter));
-
-    return {std::move(package), std::move(activity_name)};
-  }
-
-  // {"com.foo.bar", ".A"} -> "com.foo.bar/.A"
-  std::string ToString() const {
-    return package + "/" + activity_name;
-  }
-
-  /*
-   * '/' is encoded into %2F
-   * '%' is encoded into %25
-   *
-   * This allows the component name to be be used as a file name
-   * ('/' is illegal due to being a path separator) with minimal
-   * munging.
-   */
-
-  // "com.foo.bar%2F.A%25" -> {"com.foo.bar", ".A%"}
-  static AppComponentName FromUrlEncodedString(const std::string& s) {
-    std::string cpy = s;
-    Replace(cpy, "%2F", "/");
-    Replace(cpy, "%25", "%");
-
-    return FromString(cpy);
-  }
-
-  // {"com.foo.bar", ".A%"} -> "com.foo.bar%2F.A%25"
-  std::string ToUrlEncodedString() const {
-    std::string s = ToString();
-    Replace(s, "%", "%25");
-    Replace(s, "/", "%2F");
-    return s;
-  }
-
-  /*
-   * '/' is encoded into @@
-   * '%' is encoded into ^^
-   *
-   * Two purpose:
-   * 1. This allows the package name to be used as a file name
-   * ('/' is illegal due to being a path separator) with minimal
-   * munging.
-   * 2. This allows the package name to be used in .mk file because
-   * '%' is a special char and cannot be easily escaped in Makefile.
-   *
-   * This is a workround for test purpose.
-   * Only package name is used because activity name varies on
-   * different testing framework.
-   * Hopefully, the double "@@" and "^^" are not used in other cases.
-   */
-  // {"com.foo.bar", ".A%"} -> "com.foo.bar"
-  std::string ToMakeFileSafeEncodedPkgString() const {
-    std::string s = package;
-    Replace(s, "/", "@@");
-    Replace(s, "%", "^^");
-    return s;
-  }
-
- private:
-  static bool Replace(std::string& str, const std::string& from, const std::string& to) {
-    // TODO: call in a loop to replace all occurrences, not just the first one.
-    const size_t start_pos = str.find(from);
-    if (start_pos == std::string::npos) {
-      return false;
-    }
-
-    str.replace(start_pos, from.length(), to);
-
-    return true;
-}
-};
-
-inline std::ostream& operator<<(std::ostream& os, const AppComponentName& name) {
-  os << name.ToString();
-  return os;
-}
-
-}  // namespace iorap::db
-
-#endif  // IORAP_SRC_DB_APP_COMPONENT_NAME_H_
diff --git a/src/db/clean_up.cc b/src/db/clean_up.cc
deleted file mode 100644
index de1412d..0000000
--- a/src/db/clean_up.cc
+++ /dev/null
@@ -1,115 +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 "db/clean_up.h"
-
-#include <android-base/file.h>
-
-#include <cstdio>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <limits>
-#include <optional>
-#include <string>
-#include <vector>
-
-#include "db/file_models.h"
-#include "db/models.h"
-
-namespace iorap::db {
-
-void CleanUpFilesForActivity(const db::DbHandle& db,
-                             const db::VersionedComponentName& vcn) {
-  LOG(DEBUG) << "Clean up files for activity " << vcn.GetActivity();
-  // Remove perfetto traces.
-  std::vector<db::RawTraceModel> raw_traces =
-      db::RawTraceModel::SelectByVersionedComponentName(db, vcn);
-  for (db::RawTraceModel raw_trace : raw_traces) {
-    std::string file_path = raw_trace.file_path;
-    LOG(DEBUG) << "Remove file: " << file_path;
-    std::filesystem::remove(file_path.c_str());
-    raw_trace.Delete();
-  }
-
-  // Remove compiled traces.
-  std::optional<db::PrefetchFileModel> prefetch_file =
-      db::PrefetchFileModel::SelectByVersionedComponentName(db, vcn);
-
-  if (prefetch_file) {
-    std::string file_path = prefetch_file->file_path;
-    LOG(DEBUG) << "Remove file: " << file_path;
-    std::filesystem::remove(file_path.c_str());
-    prefetch_file->Delete();
-  }
-}
-
-void CleanUpFilesForPackage(const db::DbHandle& db,
-                            int package_id,
-                            const std::string& package_name,
-                            int64_t version) {
-  LOG(DEBUG) << "Clean up files for package " << package_name << " with version "
-             << version;
-  std::vector<db::ActivityModel> activities =
-      db::ActivityModel::SelectByPackageId(db, package_id);
-
-  for (db::ActivityModel activity : activities) {
-    db::VersionedComponentName vcn{package_name, activity.name, version};
-    CleanUpFilesForActivity(db, vcn);
-  }
-}
-
-void CleanUpFilesForPackage(const db::DbHandle& db,
-                            const std::string& package_name,
-                            int64_t version) {
-  std::optional<PackageModel> package =
-        PackageModel::SelectByNameAndVersion(db, package_name.c_str(), version);
-
-  if (!package) {
-    LOG(DEBUG) << "No package to clean up " << package_name << " with version " << version;
-    return;
-  }
-
-  CleanUpFilesForPackage(db, package->id, package_name, version);
-}
-
-void CleanUpFilesForDb(const db::DbHandle& db) {
-  std::vector<db::PackageModel> packages = db::PackageModel::SelectAll(db);
-  for (db::PackageModel package : packages) {
-      CleanUpFilesForPackage(db, package.id, package.name, package.version);
-  }
-}
-
-void CleanUpFilesForPackage(const std::string& db_path,
-                            const std::string& package_name) {
-  iorap::db::SchemaModel db_schema = db::SchemaModel::GetOrCreate(db_path);
-  db::DbHandle db{db_schema.db()};
-  CleanUpFilesForPackage(db, package_name);
-}
-
-
-void CleanUpFilesForPackage(const db::DbHandle& db,
-                            const std::string& package_name) {
-  std::vector<PackageModel> packages = PackageModel::SelectByName(db, package_name.c_str());;
-
-  for (PackageModel& package : packages) {
-    CleanUpFilesForPackage(db, package.id, package.name, package.version);
-  }
-
-  if (packages.empty()) {
-    LOG(DEBUG) << "No package rows to clean up " << package_name;
-  }
-}
-
-}  // namespace iorap::db
diff --git a/src/db/clean_up.h b/src/db/clean_up.h
deleted file mode 100644
index 08b7bde..0000000
--- a/src/db/clean_up.h
+++ /dev/null
@@ -1,54 +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.
-
-#ifndef IORAP_SRC_DB_CLEANER_H_
-#define IORAP_SRC_DB_CLEANER_H_
-
-#include <android/content/pm/IPackageManagerNative.h>
-
-#include <string>
-#include <vector>
-
-#include "binder/package_version_map.h"
-#include "db/file_models.h"
-
-namespace iorap::db {
-
-// Clean up perfetto traces and compiled traces in disk and rows
-// in raw_traces and prefetch_files in the db.
-void CleanUpFilesForDb(const db::DbHandle& db);
-
-// Clean up perfetto traces and compiled traces in disk and rows
-// in raw_traces and prefetch_files in the db for a package id.
-void CleanUpFilesForPackage(const db::DbHandle& db,
-                            int package_id,
-                            const std::string& package_name,
-                            int64_t version);
-
-// Clean up all package rows (and files) associated with a package by name.
-void CleanUpFilesForPackage(const std::string& db_path,
-                            const std::string& package_name);
-
-// Clean up all package rows (and files) associated with a package by name.
-void CleanUpFilesForPackage(const db::DbHandle& db,
-                            const std::string& package_name);
-// Clean up perfetto traces and compiled traces in disk and rows
-// in raw_traces and prefetch_files in the db for a package name
-// and version.
-void CleanUpFilesForPackage(const db::DbHandle& db,
-                            const std::string& package_name,
-                            int64_t version);
-}  // namespace iorap::db
-
-#endif  // IORAP_SRC_DB_CLEANER_H_
diff --git a/src/db/file_models.cc b/src/db/file_models.cc
deleted file mode 100644
index d962d49..0000000
--- a/src/db/file_models.cc
+++ /dev/null
@@ -1,194 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "common/cmd_utils.h"
-#include "db/file_models.h"
-#include "db/models.h"
-
-#include <android-base/file.h>
-#include <android-base/properties.h>
-
-#include <algorithm>
-#include <sstream>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-namespace iorap::db {
-
-static constexpr const char* kRootPathProp = "iorapd.root.dir";
-static const unsigned int kPerfettoMaxTraces =
-    ::android::base::GetUintProperty("iorapd.perfetto.max_traces", /*default*/2u);
-
-static uint64_t GetTimeNanoseconds() {
-  struct timespec now;
-  clock_gettime(CLOCK_REALTIME, &now);
-
-  uint64_t now_ns = (now.tv_sec * 1000000000LL + now.tv_nsec);
-  return now_ns;
-}
-
-static bool IsDir(const std::string& dirpath) {
-  struct stat st;
-  if (stat(dirpath.c_str(), &st) == 0) {
-    if (S_ISDIR(st.st_mode)) {
-      return true;
-    }
-  }
-  return false;
-}
-
-// Given some path /a/b/c create all of /a, /a/b, /a/b/c/ recursively.
-static bool MkdirWithParents(const std::string& path) {
-  size_t prev_end = 0;
-  while (prev_end < path.size()) {
-    size_t next_end = path.find('/', prev_end + 1);
-
-    std::string dir_path = path.substr(0, next_end);
-    if (!IsDir(dir_path)) {
-#if defined(_WIN32)
-      int ret = mkdir(dir_path.c_str());
-#else
-      mode_t old_mask = umask(0);
-      // The user permission is 5 to allow system server to
-      // read the files. No other users could do that because
-      // the upper directory only allows system server and iorapd
-      // to access. Also selinux rules prevent other users to
-      // read files here.
-      int ret = mkdir(dir_path.c_str(), 0755);
-      umask(old_mask);
-#endif
-      if (ret != 0) {
-        PLOG(ERROR) << "failed to create dir " << dir_path;
-        return false;
-      }
-    }
-    prev_end = next_end;
-
-    if (next_end == std::string::npos) {
-      break;
-    }
-  }
-  return true;
-}
-
-FileModelBase::FileModelBase(VersionedComponentName vcn)
-  : vcn_{std::move(vcn)} {
-    root_path_ = common::GetEnvOrProperty(kRootPathProp,
-                                          /*default*/"/data/misc/iorapd");
-}
-
-std::string FileModelBase::BaseDir() const {
-  std::stringstream ss;
-
-  ss << root_path_ << "/" << vcn_.GetPackage() << "/";
-  ss << vcn_.GetVersion();
-  ss << "/";
-  ss << vcn_.GetActivity() << "/";
-  ss << SubDir();
-
-  return ss.str();
-}
-
-std::string FileModelBase::FilePath() const {
-  std::stringstream ss;
-  ss << BaseDir();
-  ss << "/";
-  ss << BaseFile();
-
-  return ss.str();
-}
-
-bool FileModelBase::MkdirWithParents() {
-  LOG(VERBOSE) << "MkdirWithParents: " << BaseDir();
-  return ::iorap::db::MkdirWithParents(BaseDir());
-}
-
-PerfettoTraceFileModel::PerfettoTraceFileModel(VersionedComponentName vcn,
-                                               uint64_t timestamp)
-  : FileModelBase{std::move(vcn)}, timestamp_{timestamp} {
-}
-
-PerfettoTraceFileModel PerfettoTraceFileModel::CalculateNewestFilePath(VersionedComponentName vcn) {
-  uint64_t timestamp = GetTimeNanoseconds();
-  return PerfettoTraceFileModel{vcn, timestamp};
-}
-
-std::string PerfettoTraceFileModel::BaseFile() const {
-  std::stringstream ss;
-  ss << timestamp_ << ".perfetto_trace.pb";
-  return ss.str();
-}
-
-bool PerfettoTraceFileModel::NeedMorePerfettoTraces(DbHandle& db,
-                                                    VersionedComponentName vcn) {
-  std::vector<RawTraceModel> raw_traces =
-      RawTraceModel::SelectByVersionedComponentName(db, vcn);
-
-  size_t raw_traces_size = raw_traces.size();
-  LOG(VERBOSE) << "The number of perfetto traces is "
-               << raw_traces_size
-               << " The cap is "
-               << kPerfettoMaxTraces ;
-  return raw_traces_size < kPerfettoMaxTraces;
-}
-
-void PerfettoTraceFileModel::DeleteOlderFiles(DbHandle& db, VersionedComponentName vcn) {
-  std::vector<RawTraceModel> raw_traces =
-      RawTraceModel::SelectByVersionedComponentName(db, vcn);
-
-  if (WOULD_LOG(VERBOSE)) {
-    size_t raw_traces_size = raw_traces.size();
-    for (size_t i = 0; i < raw_traces_size; ++i) {
-      LOG(VERBOSE) << "DeleteOlderFiles - selected " << raw_traces[i];
-    }
-    LOG(VERBOSE) << "DeleteOlderFiles - queried total " << raw_traces_size << " records";
-  }
-
-  size_t items_to_delete = 0;
-  if (raw_traces.size() > kPerfettoMaxTraces) {
-    items_to_delete = raw_traces.size() - kPerfettoMaxTraces;
-  } else {
-    LOG(VERBOSE) << "DeleteOlderFiles - don't delete older raw traces, too few files: "
-                 << " wanted at least " << kPerfettoMaxTraces << ", but got " << raw_traces.size();
-  }
-
-  for (size_t i = 0; i < items_to_delete; ++i) {
-    RawTraceModel& raw_trace = raw_traces[i];  // sorted ascending -> items to delete are first.
-    std::string err_msg;
-
-    if (!::android::base::RemoveFileIfExists(raw_trace.file_path, /*out*/&err_msg)) {
-      LOG(ERROR) << "Failed to remove raw trace file: " << raw_trace.file_path
-                 << ", reason: " << err_msg;
-    } else {
-      raw_trace.Delete();
-      LOG(DEBUG) << "Deleted raw trace for " << vcn << " at " << raw_trace.file_path;
-    }
-  }
-}
-
-CompiledTraceFileModel::CompiledTraceFileModel(VersionedComponentName vcn)
-  : FileModelBase{std::move(vcn)} {
-}
-
-CompiledTraceFileModel CompiledTraceFileModel::CalculateNewestFilePath(VersionedComponentName vcn) {
-  return CompiledTraceFileModel{vcn};
-}
-
-std::string CompiledTraceFileModel::BaseFile() const {
-  return "compiled_trace.pb";
-}
-
-}  // namespace iorap::db
diff --git a/src/db/file_models.h b/src/db/file_models.h
deleted file mode 100644
index 984c206..0000000
--- a/src/db/file_models.h
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_DB_FILE_MODELS_H_
-#define IORAP_SRC_DB_FILE_MODELS_H_
-
-#include <optional>
-#include <ostream>
-#include <string>
-
-namespace iorap::db {
-
-struct VersionedComponentName {
-  VersionedComponentName(std::string package,
-                         std::string activity,
-                         int64_t version)
-    : package_{std::move(package)},
-      activity_{std::move(activity)},
-      version_{version} {
-  }
-
-  const std::string& GetPackage() const {
-    return package_;
-  }
-
-  const std::string& GetActivity() const {
-    return activity_;
-  }
-
-  int GetVersion() const {
-    return version_;
-  }
-
- private:
-  std::string package_;
-  std::string activity_;
-  int64_t version_;
-};
-
-inline std::ostream& operator<<(std::ostream& os, const VersionedComponentName& vcn) {
-  os << vcn.GetPackage() << "/" << vcn.GetActivity() << "@" << vcn.GetVersion();
-  return os;
-}
-
-class FileModelBase {
- protected:
-  FileModelBase(VersionedComponentName vcn);
-
-  virtual std::string SubDir() const = 0;
-  // Include the last file component only (/a/b/c.txt -> c.txt)
-  virtual std::string BaseFile() const = 0;
-
-  virtual ~FileModelBase() {}
-
- public:
-  virtual std::string ModelName() const = 0;
-  // Return the absolute file path to this FileModel.
-  std::string FilePath() const;
-
-  // Include the full path minus the basefile (/a/b/c.txt -> /a/b)
-  std::string BaseDir() const;
-
-  // Create the base dir recursively (e.g. mkdir -p $basedir).
-  bool MkdirWithParents();
- private:
-  VersionedComponentName vcn_;
-  std::string subdir_;
-  std::string filename_;
-  std::string root_path_;
-};
-
-inline std::ostream& operator<<(std::ostream& os, const FileModelBase& fmb) {
-  os << fmb.ModelName() << "{'" << fmb.FilePath() << "'}";
-  return os;
-}
-
-class DbHandle;
-
-class PerfettoTraceFileModel : public FileModelBase {
- protected:
-  virtual std::string ModelName() const override { return "PerfettoTrace"; }
-  virtual std::string SubDir() const override { return "raw_traces"; }
-  virtual std::string BaseFile() const override;
-
-  PerfettoTraceFileModel(VersionedComponentName vcn,
-                         uint64_t timestamp);
-
- public:
-  static PerfettoTraceFileModel CalculateNewestFilePath(VersionedComponentName vcn);
-  static void DeleteOlderFiles(DbHandle& db, VersionedComponentName vcn);
-  static bool NeedMorePerfettoTraces(DbHandle& db, VersionedComponentName vcn);
-
-  virtual ~PerfettoTraceFileModel() {}
- private:
-  uint64_t timestamp_;
-};
-
-class CompiledTraceFileModel : public FileModelBase {
- protected:
-  virtual std::string ModelName() const override { return "CompiledTrace"; }
-  virtual std::string SubDir() const override { return "compiled_traces"; }
-  virtual std::string BaseFile() const override;
-
-  CompiledTraceFileModel(VersionedComponentName vcn);
-
- public:
-  static CompiledTraceFileModel CalculateNewestFilePath(VersionedComponentName vcn);
-
-  virtual ~CompiledTraceFileModel() {}
-};
-
-}   // namespace iorap::db
-
-#endif  // IORAP_SRC_DB_FILE_MODELS_H_
diff --git a/src/db/main.cc b/src/db/main.cc
deleted file mode 100644
index 2edd961..0000000
--- a/src/db/main.cc
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "common/debug.h"
-#include "common/loggers.h"
-#include "db/app_component_name.h"
-#include "db/models.h"
-
-#include <android-base/parseint.h>
-#include <android-base/logging.h>
-
-#include <iostream>
-#include <optional>
-#include <string_view>
-#include <string>
-#include <vector>
-
-#include <sqlite3.h>
-
-#include <signal.h>
-
-namespace iorap::db {
-
-void Usage(char** argv) {
-  std::cerr << "Usage: " << argv[0] << " <path-to-sqlite.db>" << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "  Interface with the iorap sqlite database and issue commands." << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "  Optional flags:" << std::endl;
-  std::cerr << "    --help,-h                  Print this Usage." << std::endl;
-  std::cerr << "    --register-raw-trace,-rrt  Register raw trace file path." << std::endl;
-  std::cerr << "    --register-compiled-trace,-rct  Register compiled trace file path." << std::endl;
-  std::cerr << "    --insert-component,-ic     Add component if it doesn't exist." << std::endl;
-  std::cerr << "    --initialize,-i            Initialize new database." << std::endl;
-  std::cerr << "    --rescan,-rs               Update all from canonical directories." << std::endl;
-  std::cerr << "    --prune,-pr                Remove any stale file paths." << std::endl;
-  std::cerr << "    --verbose,-v               Set verbosity (default off)." << std::endl;
-  std::cerr << "    --wait,-w                  Wait for key stroke before continuing (default off)." << std::endl;
-  exit(1);
-}
-
-void error_log_sqlite_callback(void *pArg, int iErrCode, const char *zMsg) {
-  LOG(ERROR) << "SQLite error (" << iErrCode << "): " << zMsg;
-}
-
-const constexpr int64_t kNoVersion = -1;
-
-int Main(int argc, char** argv) {
-  // Go to system logcat + stderr when running from command line.
-  android::base::InitLogging(argv, iorap::common::StderrAndLogdLogger{android::base::SYSTEM});
-
-  bool wait_for_keystroke = false;
-  bool enable_verbose = false;
-
-  bool command_format_text = false; // false = binary.
-
-  int arg_input_fd = -1;
-  int arg_output_fd = -1;
-
-  std::vector<std::string> arg_input_filenames;
-  bool arg_use_sockets = false;
-
-  std::vector<std::pair<std::string,std::string>> arg_register_raw_trace;
-  std::vector<std::pair<std::string,std::string>> arg_register_compiled_trace;
-
-  std::vector<std::string> arg_insert_component;
-
-  bool arg_initialize = false;
-  bool arg_rescan = false;
-  bool arg_prune = false;
-
-  LOG(VERBOSE) << "argparse: argc=" << argc;
-
-  for (int arg = 1; arg < argc; ++arg) {
-    std::string argstr = argv[arg];
-    bool has_arg_next = (arg+1)<argc;
-    std::string arg_next = has_arg_next ? argv[arg+1] : "";
-
-    bool has_arg_next_next = (arg+2)<argc;
-    std::string arg_next_next = has_arg_next_next ? argv[arg+2] : "";
-
-    LOG(VERBOSE) << "argparse: argv[" << arg << "]=" << argstr;
-
-    if (argstr == "--help" || argstr == "-h") {
-      Usage(argv);
-    } else if (argstr == "--register-raw-trace" || argstr == "-rrt") {
-      if (!has_arg_next_next) {
-        LOG(ERROR) << "--register-raw-trace <component/name> <filepath>";
-        Usage(argv);
-      }
-      arg_register_raw_trace.push_back({arg_next, arg_next_next});
-    } else if (argstr == "--register-compiled-trace" || argstr == "-rct") {
-      if (!has_arg_next_next) {
-        LOG(ERROR) << "--register-compiled-trace <component/name> <filepath>";
-        Usage(argv);
-      }
-      arg_register_compiled_trace.push_back({arg_next, arg_next_next});
-    } else if (argstr == "--insert-component" || argstr == "-ic") {
-      if (!has_arg_next) {
-        LOG(ERROR) << "--insert-component <component/name>";
-        Usage(argv);
-      }
-      arg_insert_component.push_back(arg_next);
-    } else if (argstr == "--initialize" || argstr == "-i") {
-      arg_initialize = true;
-    } else if (argstr == "--rescan" || argstr == "-rs") {
-      arg_rescan = true;
-    } else if (argstr == "--prune" || argstr == "-pr") {
-      arg_prune = true;
-    } else if (argstr == "--verbose" || argstr == "-v") {
-      enable_verbose = true;
-    } else if (argstr == "--wait" || argstr == "-w") {
-      wait_for_keystroke = true;
-    } else {
-      arg_input_filenames.push_back(argstr);
-    }
-  }
-
-  if (arg_input_filenames.empty()) {
-    LOG(ERROR) << "Missing positional filename to a sqlite database.";
-    Usage(argv);
-  }
-
-  if (enable_verbose) {
-    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
-
-    LOG(VERBOSE) << "Verbose check";
-    LOG(VERBOSE) << "Debug check: " << ::iorap::kIsDebugBuild;
-  } else {
-    android::base::SetMinimumLogSeverity(android::base::DEBUG);
-  }
-
-  LOG(VERBOSE) << "argparse: argc=" << argc;
-
-  for (int arg = 1; arg < argc; ++arg) {
-    std::string argstr = argv[arg];
-
-    LOG(VERBOSE) << "argparse: argv[" << arg << "]=" << argstr;
-  }
-
-  // Useful to attach a debugger...
-  // 1) $> iorap.cmd.readahead -w <args>
-  // 2) $> gdbclient <pid>
-  if (wait_for_keystroke) {
-    LOG(INFO) << "Self pid: " << getpid();
-
-    raise(SIGSTOP);
-    // LOG(INFO) << "Press any key to continue...";
-    // std::cin >> wait_for_keystroke;
-  }
-
-  // auto system_call = std::make_unique<SystemCallImpl>();
-  // TODO: mock readahead calls?
-  //
-  // Uncomment this if we want to leave the process around to inspect it from adb shell.
-  // sleep(100000);
-
-  int return_code = 0;
-
-  LOG(VERBOSE) << "Hello world";
-
-
-  do {
-    SchemaModel schema_model = SchemaModel::GetOrCreate(arg_input_filenames[0]);
-    DbHandle db = schema_model.db();
-    if (arg_initialize) {
-      // Drop tables and restart from scratch. All rows are effectively dropped.
-      schema_model.Reinitialize();
-    }
-
-    for (const auto& component_and_file_name : arg_register_raw_trace) {
-      AppComponentName component_name = AppComponentName::FromString(component_and_file_name.first);
-      const std::string& file_path = component_and_file_name.second;
-
-      LOG(VERBOSE) << "--register-raw-trace " << component_name << ", file_path: " << file_path;
-
-      std::optional<ActivityModel> activity =
-          ActivityModel::SelectOrInsert(db,
-                                        component_name.package,
-                                        kNoVersion,
-                                        component_name.activity_name);
-      DCHECK(activity.has_value());
-      LOG(DEBUG) << "Component selected/inserted: " << *activity;
-    }
-
-    for (const std::string& component : arg_insert_component) {
-      AppComponentName component_name = AppComponentName::FromString(component);
-
-      LOG(VERBOSE) << "raw component: " << component;
-      LOG(VERBOSE) << "package: " << component_name.package;
-      LOG(VERBOSE) << "activity name: " << component_name.activity_name;
-
-      LOG(VERBOSE) << "--insert-component " << component_name;
-
-      std::optional<ActivityModel> activity =
-          ActivityModel::SelectOrInsert(db,
-                                        component_name.package,
-                                        kNoVersion,
-                                        component_name.activity_name);
-
-      DCHECK(activity.has_value());
-      LOG(DEBUG) << "Component selected/inserted: " << *activity;
-    }
-  } while (false);
-
-  LOG(VERBOSE) << "main: Terminating";
-
-  // 0 -> successfully executed all commands.
-  // 1 -> failed along the way (#on_error and also see the error logs).
-  return return_code;
-}
-
-}  // namespace iorap::db
-
-#if defined(IORAP_DB_MAIN)
-int main(int argc, char** argv) {
-  return ::iorap::db::Main(argc, argv);
-}
-#endif  // IORAP_DB_MAIN
diff --git a/src/db/models.cc b/src/db/models.cc
deleted file mode 100644
index 851a061..0000000
--- a/src/db/models.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "db/models.h"
-
-namespace iorap::db {
-
-std::optional<DbHandle> SchemaModel::s_singleton_;
-
-}  // namespace iorap::db
diff --git a/src/db/models.h b/src/db/models.h
deleted file mode 100644
index 79823fd..0000000
--- a/src/db/models.h
+++ /dev/null
@@ -1,1140 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_DB_MODELS_H_
-#define IORAP_SRC_DB_MODELS_H_
-
-#include "clean_up.h"
-#include "file_models.h"
-
-#include <android-base/logging.h>
-#include <utils/String8.h>
-
-#include <filesystem>
-#include <iostream>
-#include <optional>
-#include <ostream>
-#include <string>
-#include <sstream>
-#include <type_traits>
-#include <vector>
-
-#include <sqlite3.h>
-
-namespace iorap::db {
-
-const constexpr int kDbVersion = 3;
-
-struct SqliteDbDeleter {
-  void operator()(sqlite3* db) {
-    if (db != nullptr) {
-      LOG(VERBOSE) << "sqlite3_close for: " << db;
-      sqlite3_close(db);
-    }
-  }
-};
-
-class DbHandle {
- public:
-  // Take over ownership of sqlite3 db.
-  explicit DbHandle(sqlite3* db)
-    : db_{std::shared_ptr<sqlite3>{db, SqliteDbDeleter{}}},
-      mutex_{std::make_shared<std::mutex>()} {
-  }
-
-  sqlite3* get() {
-    return db_.get();
-  }
-
-  operator sqlite3*() {
-    return db_.get();
-  }
-
-  std::mutex& mutex() {
-    return *mutex_.get();
-  }
-
- private:
-  std::shared_ptr<sqlite3> db_;
-  std::shared_ptr<std::mutex> mutex_;
-};
-
-class ScopedLockDb {
- public:
-  ScopedLockDb(std::mutex& mutex) : mutex(mutex) {
-    mutex.lock();
-  }
-
-  ScopedLockDb(DbHandle& handle) : ScopedLockDb(handle.mutex()) {
-  }
-
-  ~ScopedLockDb() {
-    mutex.unlock();
-  }
- private:
-  std::mutex& mutex;
-};
-
-class DbStatement {
- public:
-  template <typename ... Args>
-  static DbStatement Prepare(DbHandle db, const std::string& sql, Args&&... args) {
-    return Prepare(db, sql.c_str(), std::forward<Args>(args)...);
-  }
-
-  template <typename ... Args>
-  static DbStatement Prepare(DbHandle db, const char* sql, Args&&... args) {
-    DCHECK(db.get() != nullptr);
-    DCHECK(sql != nullptr);
-
-    // LOG(VERBOSE) << "Prepare DB=" << db.get();
-
-    sqlite3_stmt* stmt = nullptr;
-    int rc = sqlite3_prepare_v2(db.get(), sql, -1, /*out*/&stmt, nullptr);
-
-    DbStatement db_stmt{db, stmt};
-    DCHECK(db_stmt.CheckOk(rc)) << sql;
-    db_stmt.BindAll(std::forward<Args>(args)...);
-
-    return db_stmt;
-  }
-
-  DbStatement(DbHandle db, sqlite3_stmt* stmt) : db_(db), stmt_(stmt) {
-  }
-
-  sqlite3_stmt* get() {
-    return stmt_;
-  }
-
-  DbHandle db() {
-    return db_;
-  }
-
-  // Successive BindAll calls *do not* start back at the 0th bind position.
-  template <typename T, typename ... Args>
-  void BindAll(T&& arg, Args&&... args) {
-    Bind(std::forward<T>(arg));
-    BindAll(std::forward<Args>(args)...);
-  }
-
-  void BindAll() {}
-
-  template <typename T>
-  void Bind(const std::optional<T>& value) {
-    if (value) {
-      Bind(*value);
-    } else {
-      BindNull();
-    }
-  }
-
-  void Bind(bool value) {
-    CheckOk(sqlite3_bind_int(stmt_, bind_counter_++, value));
-  }
-
-  void Bind(int value) {
-    CheckOk(sqlite3_bind_int(stmt_, bind_counter_++, value));
-  }
-
-  void Bind(uint64_t value) {
-    CheckOk(sqlite3_bind_int64(stmt_, bind_counter_++, static_cast<int64_t>(value)));
-  }
-
-  void Bind(const char* value) {
-    if (value != nullptr) {
-      //sqlite3_bind_text(stmt_, /*index*/bind_counter_++, value, -1, SQLITE_STATIC);
-      CheckOk(sqlite3_bind_text(stmt_, /*index*/bind_counter_++, value, -1, SQLITE_TRANSIENT));
-    } else {
-      BindNull();
-    }
-  }
-
-  void Bind(const std::string& value) {
-    Bind(value.c_str());
-  }
-
-  template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>>
-  void Bind(E value) {
-    Bind(static_cast<std::underlying_type_t<E>>(value));
-  }
-
-  void BindNull() {
-    CheckOk(sqlite3_bind_null(stmt_, bind_counter_++));
-  }
-
-  int Step() {
-    ++step_counter_;
-    return sqlite3_step(stmt_);
-  }
-
-  bool Step(int expected) {
-    int rc = Step();
-    if (rc != expected) {
-      LOG(ERROR) << "SQLite error: " << sqlite3_errmsg(db_.get());
-      return false;
-    }
-    return true;
-  }
-
-  // Successive ColumnAll calls start at the 0th column again.
-  template <typename T, typename ... Args>
-  void ColumnAll(T& first, Args&... rest) {
-    Column(first);
-    ColumnAll(rest...);
-    // Reset column counter back to 0
-    column_counter_ = 0;
-  }
-
-  void ColumnAll() {}
-
-  template <typename T>
-  void Column(std::optional<T>& value) {
-    T tmp;
-    Column(/*out*/tmp);
-
-    if (!tmp) {  // disambiguate 0 and NULL
-      const unsigned char* text = sqlite3_column_text(stmt_, column_counter_ - 1);
-      if (text == nullptr) {
-        value = std::nullopt;
-        return;
-      }
-    }
-    value = std::move(tmp);
-  }
-
-  template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>>
-  void Column(E& value) {
-    std::underlying_type_t<E> tmp;
-    Column(/*out*/tmp);
-    value = static_cast<E>(tmp);
-  }
-
-  void Column(bool& value) {
-    value = sqlite3_column_int(stmt_, column_counter_++);
-  }
-
-  void Column(int& value) {
-    value = sqlite3_column_int(stmt_, column_counter_++);
-  }
-
-  void Column(uint64_t& value) {
-    value = static_cast<uint64_t>(sqlite3_column_int64(stmt_, column_counter_++));
-  }
-
-  void Column(std::string& value) {
-    const unsigned char* text = sqlite3_column_text(stmt_, column_counter_++);
-
-    DCHECK(text != nullptr) << "Column should be marked NOT NULL, otherwise use optional<string>";
-    if (text == nullptr) {
-      LOG(ERROR) << "Got NULL back for column " << column_counter_-1
-                 << "; is this column marked NOT NULL?";
-      value = "(((null)))";  // Don't segfault, keep going.
-      return;
-    }
-
-    value = std::string{reinterpret_cast<const char*>(text)};
-  }
-
-  const char* ExpandedSql() {
-    char* p = sqlite3_expanded_sql(stmt_);
-    if (p == nullptr) {
-      return "(nullptr)";
-    }
-    return p;
-  }
-
-  const char* Sql() {
-    const char* p = sqlite3_sql(stmt_);
-    if (p == nullptr) {
-      return "(nullptr)";
-    }
-    return p;
-  }
-
-
-  DbStatement(DbStatement&& other)
-    : db_{other.db_}, stmt_{other.stmt_}, bind_counter_{other.bind_counter_},
-      step_counter_{other.step_counter_} {
-    other.db_ = DbHandle{nullptr};
-    other.stmt_ = nullptr;
-  }
-
-  ~DbStatement() {
-    if (stmt_ != nullptr) {
-      DCHECK_GT(step_counter_, 0) << " forgot to call Step()?";
-      sqlite3_finalize(stmt_);
-    }
-  }
-
- private:
-  bool CheckOk(int rc, int expected = SQLITE_OK) {
-    if (rc != expected) {
-      LOG(ERROR) << "Got error for SQL query: '" << Sql() << "'"
-                 << ", expanded: '" << ExpandedSql() << "'";
-      LOG(ERROR) << "Failed SQLite api call (" << rc << "): " << sqlite3_errstr(rc);
-    }
-    return rc == expected;
-  }
-
-  DbHandle db_;
-  sqlite3_stmt* stmt_;
-  int bind_counter_ = 1;
-  int step_counter_ = 0;
-  int column_counter_ = 0;
-};
-
-class DbQueryBuilder {
- public:
-  // Returns the row ID that was inserted last.
-  template <typename... Args>
-  static std::optional<int> Insert(DbHandle db, const std::string& sql, Args&&... args) {
-    ScopedLockDb lock{db};
-
-    sqlite3_int64 last_rowid = sqlite3_last_insert_rowid(db.get());
-    DbStatement stmt = DbStatement::Prepare(db, sql, std::forward<Args>(args)...);
-
-    if (!stmt.Step(SQLITE_DONE)) {
-      return std::nullopt;
-    }
-
-    last_rowid = sqlite3_last_insert_rowid(db.get());
-    DCHECK_GT(last_rowid, 0);
-
-    return static_cast<int>(last_rowid);
-  }
-
-  template <typename... Args>
-  static bool Delete(DbHandle db, const std::string& sql, Args&&... args) {
-    return ExecuteOnce(db, sql, std::forward<Args>(args)...);
-  }
-
-  template <typename... Args>
-  static bool Update(DbHandle db, const std::string& sql, Args&&... args) {
-    return ExecuteOnce(db, sql, std::forward<Args>(args)...);
-  }
-
-  template <typename... Args>
-  static bool ExecuteOnce(DbHandle db, const std::string& sql, Args&&... args) {
-    ScopedLockDb lock{db};
-
-    DbStatement stmt = DbStatement::Prepare(db, sql, std::forward<Args>(args)...);
-
-    if (!stmt.Step(SQLITE_DONE)) {
-      return false;
-    }
-
-    return true;
-  }
-
-  template <typename... Args>
-  static bool SelectOnce(DbStatement& stmt, Args&... args) {
-    int rc = stmt.Step();
-    switch (rc) {
-      case SQLITE_ROW:
-        stmt.ColumnAll(/*out*/args...);
-        return true;
-      case SQLITE_DONE:
-        return false;
-      default:
-        LOG(ERROR) << "Failed to step (" << rc << "): " << sqlite3_errmsg(stmt.db());
-        return false;
-    }
-  }
-};
-
-class Model {
- public:
-  DbHandle db() const {
-    return db_;
-  }
-
-  Model(DbHandle db) : db_{db} {
-  }
-
- private:
-  DbHandle db_;
-};
-
-class SchemaModel : public Model {
- public:
-  static SchemaModel GetOrCreate(std::string location) {
-    int rc = sqlite3_config(SQLITE_CONFIG_LOG, ErrorLogCallback, /*data*/nullptr);
-
-    if (rc != SQLITE_OK) {
-      LOG(FATAL) << "Failed to configure logging";
-    }
-
-    sqlite3* db = nullptr;
-    bool is_deprecated = false;
-    if (location != ":memory:") {
-      // Try to open DB if it already exists.
-      rc = sqlite3_open_v2(location.c_str(), /*out*/&db, SQLITE_OPEN_READWRITE, /*vfs*/nullptr);
-
-      if (rc == SQLITE_OK) {
-        LOG(INFO) << "Opened existing database at '" << location << "'";
-        SchemaModel schema{DbHandle{db}, location};
-        if (schema.Version() == kDbVersion) {
-          return schema;
-        } else {
-          LOG(DEBUG) << "The version is old, reinit the db."
-                     << " old version is "
-                     << schema.Version()
-                     << " and new version is "
-                     << kDbVersion;
-          CleanUpFilesForDb(schema.db());
-          is_deprecated = true;
-       }
-      }
-    }
-
-    if (is_deprecated) {
-      // Remove the db and recreate it.
-      // TODO: migrate to a newer version without deleting the old one.
-      std::filesystem::remove(location.c_str());
-    }
-
-    // Create a new DB if one didn't exist already.
-    rc = sqlite3_open(location.c_str(), /*out*/&db);
-
-    if (rc != SQLITE_OK) {
-      LOG(FATAL) << "Failed to open DB: " << sqlite3_errmsg(db);
-    }
-
-    SchemaModel schema{DbHandle{db}, location};
-    schema.Reinitialize();
-    // TODO: migrate versions upwards when we rev the schema version
-
-    int old_version = schema.Version();
-    LOG(VERBOSE) << "Loaded schema version: " << old_version;
-
-    return schema;
-  }
-
-  void MarkSingleton() {
-    s_singleton_ = db();
-  }
-
-  static DbHandle GetSingleton() {
-    DCHECK(s_singleton_.has_value());
-    return *s_singleton_;
-  }
-
-  void Reinitialize() {
-    const char* sql_to_initialize = R"SQLC0D3(
-        DROP TABLE IF EXISTS schema_versions;
-        DROP TABLE IF EXISTS packages;
-        DROP TABLE IF EXISTS activities;
-        DROP TABLE IF EXISTS app_launch_histories;
-        DROP TABLE IF EXISTS raw_traces;
-        DROP TABLE IF EXISTS prefetch_files;
-)SQLC0D3";
-    char* err_msg = nullptr;
-    int rc = sqlite3_exec(db().get(),
-                          sql_to_initialize,
-                          /*callback*/nullptr,
-                          /*arg*/0,
-                          /*out*/&err_msg);
-    if (rc != SQLITE_OK) {
-      LOG(FATAL) << "Failed to drop tables: " << err_msg ? err_msg : "nullptr";
-    }
-
-    CreateSchema();
-    LOG(INFO) << "Reinitialized database at '" << location_ << "'";
-  }
-
-  int Version() {
-    std::string query = "SELECT MAX(version) FROM schema_versions;";
-    DbStatement stmt = DbStatement::Prepare(db(), query);
-
-    int return_value = 0;
-    if (!DbQueryBuilder::SelectOnce(stmt, /*out*/return_value)) {
-      LOG(ERROR) << "Failed to query schema version";
-      return -1;
-    }
-
-    return return_value;
-  }
-
- protected:
-  SchemaModel(DbHandle db, std::string location) : Model{db}, location_(location) {
-  }
-
- private:
-  static std::optional<DbHandle> s_singleton_;
-
-  void CreateSchema() {
-    const char* sql_to_initialize = R"SQLC0D3(
-        CREATE TABLE schema_versions(
-            version INTEGER NOT NULL
-        );
-
-        CREATE TABLE packages(
-            id INTEGER NOT NULL,
-            name TEXT NOT NULL,
-            version INTEGER NOT NULL,
-
-            PRIMARY KEY(id)
-        );
-
-        CREATE TABLE activities(
-            id INTEGER NOT NULL,
-            name TEXT NOT NULL,
-            package_id INTEGER NOT NULL,
-
-            PRIMARY KEY(id),
-            FOREIGN KEY (package_id) REFERENCES packages (id) ON DELETE CASCADE
-        );
-
-        CREATE TABLE app_launch_histories(
-            id INTEGER NOT NULL PRIMARY KEY,
-            activity_id INTEGER NOT NULL,
-            -- 1:Cold, 2:Warm, 3:Hot
-            temperature INTEGER CHECK (temperature IN (1, 2, 3)) NOT NULL,
-            trace_enabled INTEGER CHECK(trace_enabled in (TRUE, FALSE)) NOT NULL,
-            readahead_enabled INTEGER CHECK(trace_enabled in (TRUE, FALSE)) NOT NULL,
-            -- absolute timestamp since epoch
-            intent_started_ns INTEGER CHECK(intent_started_ns IS NULL or intent_started_ns >= 0),
-            -- absolute timestamp since epoch
-            total_time_ns INTEGER CHECK(total_time_ns IS NULL or total_time_ns >= 0),
-            -- absolute timestamp since epoch
-            report_fully_drawn_ns INTEGER CHECK(report_fully_drawn_ns IS NULL or report_fully_drawn_ns >= 0),
-            -- pid of the app
-            pid INTEGER CHECK(pid IS NULL or pid >= 0),
-
-            FOREIGN KEY (activity_id) REFERENCES activities (id) ON DELETE CASCADE
-        );
-
-        CREATE TABLE raw_traces(
-            id INTEGER NOT NULL PRIMARY KEY,
-            history_id INTEGER NOT NULL,
-            file_path TEXT NOT NULL,
-
-            FOREIGN KEY (history_id) REFERENCES app_launch_histories (id) ON DELETE CASCADE
-        );
-
-        CREATE TABLE prefetch_files(
-          id INTEGER NOT NULL PRIMARY KEY,
-          activity_id INTEGER NOT NULL,
-          file_path TEXT NOT NULL,
-
-          FOREIGN KEY (activity_id) REFERENCES activities (id) ON DELETE CASCADE
-        );
-)SQLC0D3";
-
-    char* err_msg = nullptr;
-    int rc = sqlite3_exec(db().get(),
-                          sql_to_initialize,
-                          /*callback*/nullptr,
-                          /*arg*/0,
-                          /*out*/&err_msg);
-
-    if (rc != SQLITE_OK) {
-      LOG(FATAL) << "Failed to create tables: " << err_msg ? err_msg : "nullptr";
-    }
-
-    const char* sql_to_insert_schema_version = R"SQLC0D3(
-      INSERT INTO schema_versions VALUES(%d)
-      )SQLC0D3";
-    rc = sqlite3_exec(db().get(),
-                      android::String8::format(sql_to_insert_schema_version,
-                                               kDbVersion),
-                      /*callback*/nullptr,
-                      /*arg*/0,
-                      /*out*/&err_msg);
-
-    if (rc != SQLITE_OK) {
-      LOG(FATAL) << "Failed to insert the schema version: "
-                 << err_msg ? err_msg : "nullptr";
-    }
-  }
-
-  static void ErrorLogCallback(void *pArg, int iErrCode, const char *zMsg) {
-    LOG(ERROR) << "SQLite error (" << iErrCode << "): " << zMsg;
-  }
-
-  std::string location_;
-};
-
-class PackageModel : public Model {
- protected:
-  PackageModel(DbHandle db) : Model{db} {
-  }
-
- public:
-  static std::optional<PackageModel> SelectById(DbHandle db, int id) {
-    ScopedLockDb lock{db};
-    int original_id = id;
-
-    std::string query = "SELECT * FROM packages WHERE id = ?1 LIMIT 1;";
-    DbStatement stmt = DbStatement::Prepare(db, query, id);
-
-    PackageModel p{db};
-    if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.version)) {
-      return std::nullopt;
-    }
-
-    return p;
-  }
-
-  static std::vector<PackageModel> SelectByName(DbHandle db, const char* name) {
-    ScopedLockDb lock{db};
-
-    std::string query = "SELECT * FROM packages WHERE name = ?1;";
-    DbStatement stmt = DbStatement::Prepare(db, query, name);
-
-    std::vector<PackageModel> packages;
-
-    PackageModel p{db};
-    while (DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.version)) {
-      packages.push_back(p);
-    }
-
-    return packages;
-  }
-
-  static std::optional<PackageModel> SelectByNameAndVersion(DbHandle db,
-                                                            const char* name,
-                                                            int version) {
-    ScopedLockDb lock{db};
-
-    std::string query =
-        "SELECT * FROM packages WHERE name = ?1 AND version = ?2 LIMIT 1;";
-    DbStatement stmt = DbStatement::Prepare(db, query, name, version);
-
-    PackageModel p{db};
-    if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.version)) {
-      return std::nullopt;
-    }
-
-    return p;
-  }
-
-  static std::vector<PackageModel> SelectAll(DbHandle db) {
-    ScopedLockDb lock{db};
-
-    std::string query = "SELECT * FROM packages;";
-    DbStatement stmt = DbStatement::Prepare(db, query);
-
-    std::vector<PackageModel> packages;
-    PackageModel p{db};
-    while (DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.version)) {
-      packages.push_back(p);
-    }
-
-    return packages;
-  }
-
-  static std::optional<PackageModel> Insert(DbHandle db,
-                                            std::string name,
-                                            int version) {
-    const char* sql = "INSERT INTO packages (name, version) VALUES (?1, ?2);";
-
-    std::optional<int> inserted_row_id =
-        DbQueryBuilder::Insert(db, sql, name, version);
-    if (!inserted_row_id) {
-      return std::nullopt;
-    }
-
-    PackageModel p{db};
-    p.name = name;
-    p.version = version;
-    p.id = *inserted_row_id;
-
-    return p;
-  }
-
-  bool Delete() {
-    const char* sql = "DELETE FROM packages WHERE id = ?";
-
-    return DbQueryBuilder::Delete(db(), sql, id);
-  }
-
-  int id;
-  std::string name;
-  int version;
-};
-
-inline std::ostream& operator<<(std::ostream& os, const PackageModel& p) {
-  os << "PackageModel{id=" << p.id << ",name=" << p.name << ",";
-  os << "version=";
-  os << p.version;
-  os << "}";
-  return os;
-}
-
-class ActivityModel : public Model {
- protected:
-  ActivityModel(DbHandle db) : Model{db} {
-  }
-
- public:
-  static std::optional<ActivityModel> SelectById(DbHandle db, int id) {
-    ScopedLockDb lock{db};
-    int original_id = id;
-
-    std::string query = "SELECT * FROM activities WHERE id = ? LIMIT 1;";
-    DbStatement stmt = DbStatement::Prepare(db, query, id);
-
-    ActivityModel p{db};
-    if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.package_id)) {
-      return std::nullopt;
-    }
-
-    return p;
-  }
-
-  static std::optional<ActivityModel> SelectByNameAndPackageId(DbHandle db,
-                                                               const char* name,
-                                                               int package_id) {
-    ScopedLockDb lock{db};
-
-    std::string query = "SELECT * FROM activities WHERE name = ? AND package_id = ? LIMIT 1;";
-    DbStatement stmt = DbStatement::Prepare(db, query, name, package_id);
-
-    ActivityModel p{db};
-    if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.package_id)) {
-      return std::nullopt;
-    }
-
-    return p;
-  }
-
-  static std::vector<ActivityModel> SelectByPackageId(DbHandle db,
-                                                      int package_id) {
-    ScopedLockDb lock{db};
-
-    std::string query = "SELECT * FROM activities WHERE package_id = ?;";
-    DbStatement stmt = DbStatement::Prepare(db, query, package_id);
-
-    std::vector<ActivityModel> activities;
-    ActivityModel p{db};
-    while (DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.package_id)) {
-      activities.push_back(p);
-    }
-
-    return activities;
-  }
-
-  static std::optional<ActivityModel> Insert(DbHandle db,
-                                             std::string name,
-                                             int package_id) {
-    const char* sql = "INSERT INTO activities (name, package_id) VALUES (?1, ?2);";
-
-    std::optional<int> inserted_row_id =
-        DbQueryBuilder::Insert(db, sql, name, package_id);
-    if (!inserted_row_id) {
-      return std::nullopt;
-    }
-
-    ActivityModel p{db};
-    p.id = *inserted_row_id;
-    p.name = name;
-    p.package_id = package_id;
-
-    return p;
-  }
-
-  // Try to select by package_name+activity_name, otherwise insert into both tables.
-  // Package version is ignored for selects.
-  static std::optional<ActivityModel> SelectOrInsert(
-      DbHandle db,
-      std::string package_name,
-      int package_version,
-      std::string activity_name) {
-    std::optional<PackageModel> package = PackageModel::SelectByNameAndVersion(db,
-                                                                               package_name.c_str(),
-                                                                               package_version);
-    if (!package) {
-      package = PackageModel::Insert(db, package_name, package_version);
-      DCHECK(package.has_value());
-    }
-
-    std::optional<ActivityModel> activity =
-        ActivityModel::SelectByNameAndPackageId(db,
-                                                activity_name.c_str(),
-                                                package->id);
-    if (!activity) {
-      activity = Insert(db, activity_name, package->id);
-      // XX: should we really return an optional here? This feels like it should never fail.
-    }
-
-    return activity;
-  }
-
-  int id;
-  std::string name;
-  int package_id;  // PackageModel::id
-};
-
-inline std::ostream& operator<<(std::ostream& os, const ActivityModel& p) {
-  os << "ActivityModel{id=" << p.id << ",name=" << p.name << ",";
-  os << "package_id=" << p.package_id << "}";
-  return os;
-}
-
-class AppLaunchHistoryModel : public Model {
- protected:
-  AppLaunchHistoryModel(DbHandle db) : Model{db} {
-  }
-
- public:
-  enum class Temperature : int32_t {
-    kUninitialized = -1,  // Note: Not a valid SQL value.
-    kCold = 1,
-    kWarm = 2,
-    kHot = 3,
-  };
-
-  static std::optional<AppLaunchHistoryModel> SelectById(DbHandle db, int id) {
-    ScopedLockDb lock{db};
-    int original_id = id;
-
-    std::string query = "SELECT * FROM app_launch_histories WHERE id = ? LIMIT 1;";
-    DbStatement stmt = DbStatement::Prepare(db, query, id);
-
-    AppLaunchHistoryModel p{db};
-    if (!DbQueryBuilder::SelectOnce(stmt,
-                                    p.id,
-                                    p.activity_id,
-                                    p.temperature,
-                                    p.trace_enabled,
-                                    p.readahead_enabled,
-                                    p.intent_started_ns,
-                                    p.total_time_ns,
-                                    p.report_fully_drawn_ns,
-                                    p.pid)) {
-      return std::nullopt;
-    }
-
-    return p;
-  }
-
-  // Selects the activity history for an activity id.
-  // The requirements are:
-  // * Should be cold run.
-  // * Pefetto trace is enabled.
-  // * intent_start_ns is *NOT* null.
-  static std::vector<AppLaunchHistoryModel> SelectActivityHistoryForCompile(
-      DbHandle db,
-      int activity_id) {
-    ScopedLockDb lock{db};
-    std::string query = "SELECT * FROM app_launch_histories "
-                        "WHERE activity_id = ?1 AND"
-                        "  temperature = 1 AND"
-                        "  trace_enabled = TRUE AND"
-                        "  intent_started_ns IS NOT NULL;";
-    DbStatement stmt = DbStatement::Prepare(db, query, activity_id);
-    std::vector<AppLaunchHistoryModel> result;
-
-    AppLaunchHistoryModel p{db};
-    while (DbQueryBuilder::SelectOnce(stmt,
-                                      p.id,
-                                      p.activity_id,
-                                      p.temperature,
-                                      p.trace_enabled,
-                                      p.readahead_enabled,
-                                      p.intent_started_ns,
-                                      p.total_time_ns,
-                                      p.report_fully_drawn_ns,
-                                      p.pid)) {
-      result.push_back(p);
-    }
-    return result;
-  }
-
-  static std::optional<AppLaunchHistoryModel> Insert(DbHandle db,
-                                                     int activity_id,
-                                                     AppLaunchHistoryModel::Temperature temperature,
-                                                     bool trace_enabled,
-                                                     bool readahead_enabled,
-                                                     std::optional<uint64_t> intent_started_ns,
-                                                     std::optional<uint64_t> total_time_ns,
-                                                     std::optional<uint64_t> report_fully_drawn_ns,
-                                                     int32_t pid)
-  {
-    const char* sql = "INSERT INTO app_launch_histories (activity_id, temperature, trace_enabled, "
-                                                        "readahead_enabled, intent_started_ns, "
-                                                        "total_time_ns, report_fully_drawn_ns, pid) "
-                      "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8);";
-
-    std::optional<int> inserted_row_id =
-        DbQueryBuilder::Insert(db,
-                               sql,
-                               activity_id,
-                               temperature,
-                               trace_enabled,
-                               readahead_enabled,
-                               intent_started_ns,
-                               total_time_ns,
-                               report_fully_drawn_ns,
-                               pid);
-    if (!inserted_row_id) {
-      return std::nullopt;
-    }
-
-    AppLaunchHistoryModel p{db};
-    p.id = *inserted_row_id;
-    p.activity_id = activity_id;
-    p.temperature = temperature;
-    p.trace_enabled = trace_enabled;
-    p.readahead_enabled = readahead_enabled;
-    p.intent_started_ns = intent_started_ns;
-    p.total_time_ns = total_time_ns;
-    p.report_fully_drawn_ns = report_fully_drawn_ns;
-    p.pid = pid;
-
-    return p;
-  }
-
-  static bool UpdateReportFullyDrawn(DbHandle db,
-                                     int history_id,
-                                     uint64_t report_fully_drawn_ns)
-  {
-    const char* sql = "UPDATE app_launch_histories "
-                      "SET report_fully_drawn_ns = ?1 "
-                      "WHERE id = ?2;";
-
-    bool result = DbQueryBuilder::Update(db, sql, report_fully_drawn_ns, history_id);
-
-    if (!result) {
-      LOG(ERROR)<< "Failed to update history_id:"<< history_id
-                << ", report_fully_drawn_ns: " << report_fully_drawn_ns;
-    }
-    return result;
-  }
-
-  int id;
-  int activity_id;  // ActivityModel::id
-  Temperature temperature = Temperature::kUninitialized;
-  bool trace_enabled;
-  bool readahead_enabled;
-  std::optional<uint64_t> intent_started_ns;
-  std::optional<uint64_t> total_time_ns;
-  std::optional<uint64_t> report_fully_drawn_ns;
-  int32_t pid;
-};
-
-inline std::ostream& operator<<(std::ostream& os, const AppLaunchHistoryModel& p) {
-  os << "AppLaunchHistoryModel{id=" << p.id << ","
-     << "activity_id=" << p.activity_id << ","
-     << "temperature=" << static_cast<int>(p.temperature) << ","
-     << "trace_enabled=" << p.trace_enabled << ","
-     << "readahead_enabled=" << p.readahead_enabled << ","
-     << "intent_started_ns=";
-  if (p.intent_started_ns) {
-    os << *p.intent_started_ns;
-  } else {
-    os << "(nullopt)";
-  }
-  os << ",";
-  os << "total_time_ns=";
-  if (p.total_time_ns) {
-    os << *p.total_time_ns;
-  } else {
-    os << "(nullopt)";
-  }
-  os << ",";
-  os << "report_fully_drawn_ns=";
-  if (p.report_fully_drawn_ns) {
-    os << *p.report_fully_drawn_ns;
-  } else {
-    os << "(nullopt)";
-  }
-  os << ",";
-  os << "pid=" << p.pid;
-  os << "}";
-  return os;
-}
-
-class RawTraceModel : public Model {
- protected:
-  RawTraceModel(DbHandle db) : Model{db} {
-  }
-
- public:
-
-  // Return raw_traces, sorted ascending by the id.
-  static std::vector<RawTraceModel> SelectByVersionedComponentName(DbHandle db,
-                                                                   VersionedComponentName vcn) {
-    ScopedLockDb lock{db};
-
-    const char* sql =
-      "SELECT raw_traces.id, raw_traces.history_id, raw_traces.file_path "
-      "FROM raw_traces "
-      "INNER JOIN app_launch_histories ON raw_traces.history_id = app_launch_histories.id "
-      "INNER JOIN activities ON activities.id = app_launch_histories.activity_id "
-      "INNER JOIN packages ON packages.id = activities.package_id "
-      "WHERE packages.name = ? AND activities.name = ? AND packages.version = ?"
-      "ORDER BY raw_traces.id ASC";
-
-    DbStatement stmt = DbStatement::Prepare(db,
-                                            sql,
-                                            vcn.GetPackage(),
-                                            vcn.GetActivity(),
-                                            vcn.GetVersion());
-
-    std::vector<RawTraceModel> results;
-
-    RawTraceModel p{db};
-    while (DbQueryBuilder::SelectOnce(stmt, p.id, p.history_id, p.file_path)) {
-      results.push_back(p);
-    }
-
-    return results;
-  }
-
-  static std::optional<RawTraceModel> SelectByHistoryId(DbHandle db, int history_id) {
-    ScopedLockDb lock{db};
-
-    const char* sql =
-      "SELECT id, history_id, file_path "
-      "FROM raw_traces "
-      "WHERE history_id = ?1 "
-      "LIMIT 1;";
-
-    DbStatement stmt = DbStatement::Prepare(db, sql, history_id);
-
-    RawTraceModel p{db};
-    if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.history_id, p.file_path)) {
-      return std::nullopt;
-    }
-
-    return p;
-  }
-
-  static std::optional<RawTraceModel> Insert(DbHandle db,
-                                             int history_id,
-                                             std::string file_path) {
-    const char* sql = "INSERT INTO raw_traces (history_id, file_path) VALUES (?1, ?2);";
-
-    std::optional<int> inserted_row_id =
-        DbQueryBuilder::Insert(db, sql, history_id, file_path);
-    if (!inserted_row_id) {
-      return std::nullopt;
-    }
-
-    RawTraceModel p{db};
-    p.id = *inserted_row_id;
-    p.history_id = history_id;
-    p.file_path = file_path;
-
-    return p;
-  }
-
-  bool Delete() {
-    const char* sql = "DELETE FROM raw_traces WHERE id = ?";
-
-    return DbQueryBuilder::Delete(db(), sql, id);
-  }
-
-  int id;
-  int history_id;
-  std::string file_path;
-};
-
-inline std::ostream& operator<<(std::ostream& os, const RawTraceModel& p) {
-  os << "RawTraceModel{id=" << p.id << ",history_id=" << p.history_id << ",";
-  os << "file_path=" << p.file_path << "}";
-  return os;
-}
-
-class PrefetchFileModel : public Model {
- protected:
-  PrefetchFileModel(DbHandle db) : Model{db} {
-  }
-
- public:
-  static std::optional<PrefetchFileModel> SelectByVersionedComponentName(
-      DbHandle db,
-      VersionedComponentName vcn) {
-    ScopedLockDb lock{db};
-
-    const char* sql =
-      "SELECT prefetch_files.id, prefetch_files.activity_id, prefetch_files.file_path "
-      "FROM prefetch_files "
-      "INNER JOIN activities ON activities.id = prefetch_files.activity_id "
-      "INNER JOIN packages ON packages.id = activities.package_id "
-      "WHERE packages.name = ? AND activities.name = ? AND packages.version = ?";
-
-    DbStatement stmt = DbStatement::Prepare(db,
-                                            sql,
-                                            vcn.GetPackage(),
-                                            vcn.GetActivity(),
-                                            vcn.GetVersion());
-
-    PrefetchFileModel p{db};
-
-    if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.activity_id, p.file_path)) {
-      return std::nullopt;
-    }
-
-    return p;
-  }
-
-  static std::vector<PrefetchFileModel> SelectAll(DbHandle db) {
-    ScopedLockDb lock{db};
-
-    std::string query =
-      "SELECT prefetch_files.id, prefetch_files.activity_id, prefetch_files.file_path "
-      "FROM prefetch_files";
-    DbStatement stmt = DbStatement::Prepare(db, query);
-
-    std::vector<PrefetchFileModel> prefetch_files;
-    PrefetchFileModel p{db};
-    while (DbQueryBuilder::SelectOnce(stmt, p.id, p.activity_id, p.file_path)) {
-      prefetch_files.push_back(p);
-    }
-
-    return prefetch_files;
-  }
-
-  static std::optional<PrefetchFileModel> Insert(DbHandle db,
-                                                 int activity_id,
-                                                 std::string file_path) {
-    const char* sql = "INSERT INTO prefetch_files (activity_id, file_path) VALUES (?1, ?2);";
-
-    std::optional<int> inserted_row_id =
-        DbQueryBuilder::Insert(db, sql, activity_id, file_path);
-    if (!inserted_row_id) {
-      return std::nullopt;
-    }
-
-    PrefetchFileModel p{db};
-    p.id = *inserted_row_id;
-    p.activity_id = activity_id;
-    p.file_path = file_path;
-
-    return p;
-  }
-
-  bool Delete() {
-    const char* sql = "DELETE FROM prefetch_files WHERE id = ?";
-
-    return DbQueryBuilder::Delete(db(), sql, id);
-  }
-
-  int id;
-  int activity_id;
-  std::string file_path;
-};
-
-inline std::ostream& operator<<(std::ostream& os, const PrefetchFileModel& p) {
-  os << "PrefetchFileModel{id=" << p.id << ",activity_id=" << p.activity_id << ",";
-  os << "file_path=" << p.file_path << "}";
-  return os;
-}
-
-}  // namespace iorap::db
-
-#endif  // IORAP_SRC_DB_MODELS_H_
diff --git a/src/inode2filename/data_source.cc b/src/inode2filename/data_source.cc
deleted file mode 100644
index 5fcce73..0000000
--- a/src/inode2filename/data_source.cc
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "inode2filename/data_source.h"
-
-#include "common/cmd_utils.h"
-#include "inode2filename/inode_resolver.h"
-#include "inode2filename/search_directories.h"
-
-#include <android-base/logging.h>
-
-#include <fstream>
-#include <stdio.h>
-
-namespace rx = rxcpp;
-
-namespace iorap::inode2filename {
-
-std::vector<std::string> ToArgs(DataSourceKind data_source_kind) {
-  const char* value = nullptr;
-
-  switch (data_source_kind) {
-    case DataSourceKind::kDiskScan:
-      value = "diskscan";
-      break;
-    case DataSourceKind::kTextCache:
-      value = "textcache";
-      break;
-    case DataSourceKind::kBpf:
-      value = "bpf";
-      break;
-  }
-
-  std::vector<std::string> args;
-  iorap::common::AppendNamedArg(args, "--data-source", value);
-  return args;
-}
-
-std::vector<std::string> ToArgs(const DataSourceDependencies& deps) {
-  std::vector<std::string> args;
-
-  iorap::common::AppendArgsRepeatedly(args, ToArgs(deps.data_source));
-  // intentionally skip system_call; it does not have a command line equivalent
-  iorap::common::AppendNamedArgRepeatedly(args, "--root", deps.root_directories);
-
-  if (deps.text_cache_filename) {
-    iorap::common::AppendNamedArg(args, "--textcache", *(deps.text_cache_filename));
-  }
-
-  return args;
-}
-
-class DiskScanDataSource : public DataSource {
- public:
-  DiskScanDataSource(DataSourceDependencies dependencies)
-    : DataSource(std::move(dependencies)) {
-    DCHECK_NE(dependencies_.root_directories.size(), 0u) << "Root directories can't be empty";
-  }
-
-  virtual rxcpp::observable<InodeResult> EmitInodes() const override {
-    SearchDirectories searcher{/*borrow*/dependencies_.system_call};
-    return searcher.ListAllFilenames(dependencies_.root_directories);
-  }
-
-  // Since not all Inodes emitted are the ones searched for, doing additional stat(2) calls here
-  // would be redundant.
-  //
-  // We set the device number to a dummy value here (-1) so that InodeResolver
-  // can fill it in later with stat(2). This is effectively the same thing as always doing
-  // verification.
-  virtual bool ResultIncludesDeviceNumber() const { return false; };
-
-  virtual ~DiskScanDataSource() {}
-};
-
-static inline void LeftTrim(/*inout*/std::string& s) {
-  s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
-    return !std::isspace(ch);
-  }));
-}
-
-class TextCacheDataSource : public DataSource {
- public:
-  TextCacheDataSource(DataSourceDependencies dependencies)
-    : DataSource(std::move(dependencies)) {
-    DCHECK(dependencies_.text_cache_filename.has_value()) << "Must have text cache filename";
-  }
-
-  virtual rxcpp::observable<InodeResult> EmitInodes() const override {
-    const std::string& file_name = *dependencies_.text_cache_filename;
-
-    return rx::observable<>::create<InodeResult>(
-      [file_name](rx::subscriber<InodeResult> dest) {
-        LOG(VERBOSE) << "TextCacheDataSource (lambda)";
-
-        std::ifstream ifs{file_name};
-
-        if (!ifs.is_open()) {
-          dest.on_error(rxcpp::util::make_error_ptr(
-              std::ios_base::failure("Could not open specified text cache filename")));
-          return;
-        }
-
-        while (dest.is_subscribed() && ifs) {
-          LOG(VERBOSE) << "TextCacheDataSource (read line)";
-          // TODO.
-
-          uint64_t device_number = 0;
-          uint64_t inode_number = 0;
-          uint64_t file_size = 0;
-
-          // Parse lines of form:
-          //   "$device_number $inode $filesize $filename..."
-          // This format conforms to system/extras/pagecache/pagecache.py
-
-          ifs >> device_number;
-          ifs >> inode_number;
-          ifs >> file_size;
-          (void)file_size;  // Not used in iorapd.
-
-          std::string value_filename;
-          std::getline(/*inout*/ifs, /*out*/value_filename);
-
-          if (value_filename.empty()) {
-            // Ignore empty lines.
-            continue;
-          }
-
-          // getline, unlike ifstream, does not ignore spaces.
-          // There's always at least 1 space in a textcache output file.
-          // However, drop *all* spaces on the left since filenames starting with a space are
-          // ambiguous to us.
-          LeftTrim(/*inout*/value_filename);
-
-          Inode inode = Inode::FromDeviceAndInode(static_cast<dev_t>(device_number),
-                                                  static_cast<ino_t>(inode_number));
-
-          LOG(VERBOSE) << "TextCacheDataSource (on_next) " << inode << "->" << value_filename;
-          dest.on_next(InodeResult::makeSuccess(inode, value_filename));
-        }
-
-        dest.on_completed();
-      }
-    );
-
-    // TODO: plug into the filtering and verification graph.
-  }
-
-  virtual ~TextCacheDataSource() {}
-};
-
-DataSource::DataSource(DataSourceDependencies dependencies)
-  : dependencies_{std::move(dependencies)} {
-  DCHECK(dependencies_.system_call != nullptr);
-}
-
-std::shared_ptr<DataSource> DataSource::Create(DataSourceDependencies dependencies) {
-  switch (dependencies.data_source) {
-    case DataSourceKind::kDiskScan:
-      return std::shared_ptr<DataSource>{new DiskScanDataSource{std::move(dependencies)}};
-    case DataSourceKind::kTextCache:
-      return std::shared_ptr<DataSource>{new TextCacheDataSource{std::move(dependencies)}};
-    case DataSourceKind::kBpf:
-      // TODO: BPF-based data source.
-      LOG(FATAL) << "Not implemented yet";
-      return nullptr;
-    default:
-      LOG(FATAL) << "Invalid data source value";
-      return nullptr;
-  }
-}
-
-void DataSource::StartRecording() {}
-void DataSource::StopRecording() {}
-
-}  // namespace iorap::inode2filename
diff --git a/src/inode2filename/data_source.h b/src/inode2filename/data_source.h
deleted file mode 100644
index 36c8383..0000000
--- a/src/inode2filename/data_source.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_INODE2FILENAME_DATA_SOURCE_H_
-#define IORAP_SRC_INODE2FILENAME_DATA_SOURCE_H_
-
-#include "inode2filename/inode_result.h"
-#include "inode2filename/system_call.h"
-
-#include <rxcpp/rx.hpp>
-
-#include <memory>
-#include <optional>
-#include <string>
-#include <vector>
-namespace iorap::inode2filename {
-
-enum class DataSourceKind {
-  kDiskScan,
-  kTextCache,
-  kBpf,
-};
-
-std::vector<std::string> ToArgs(DataSourceKind data_source_kind);
-
-struct DataSourceDependencies {
-  DataSourceKind data_source = DataSourceKind::kDiskScan;
-  borrowed<SystemCall*> system_call = nullptr;
-
-  // kDiskScan-specific options. Other data sources ignore these fields.
-  std::vector<std::string> root_directories;
-  // kTextCache-specific options. Other data sources ignore these fields.
-  std::optional<std::string> text_cache_filename;
-};
-
-std::vector<std::string> ToArgs(const DataSourceDependencies& deps);
-
-class DataSource : std::enable_shared_from_this<DataSource> {
- public:
-  static std::shared_ptr<DataSource> Create(DataSourceDependencies dependencies);
-
-  virtual void StartRecording();  // XX: feels like this should be BPF-specific.
-  virtual void StopRecording();
-
-  // Emit all inode->filename mappings (i.e. an infinite lazy list).
-  // The specific order is determined by the extra dependency options.
-  //
-  // The work must terminate if all subscriptions are removed.
-  virtual rxcpp::observable<InodeResult> EmitInodes() const = 0;
-
-  // Does the InodeResult include a valid device number?
-  // If returning false, the InodeResolver fills in the missing device number with stat(2).
-  virtual bool ResultIncludesDeviceNumber() const { return true; };
-
- protected:
-  virtual ~DataSource() {}
-  DataSource(DataSourceDependencies dependencies);
-  DataSourceDependencies dependencies_;
-};
-
-}  // namespace iorap::inode2filename
-
-#endif  // IORAP_SRC_INODE2FILENAME_DATA_SOURCE_H_
diff --git a/src/inode2filename/inode.cc b/src/inode2filename/inode.cc
deleted file mode 100644
index cc665ea..0000000
--- a/src/inode2filename/inode.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "inode2filename/inode.h"
-
-#include <android-base/logging.h>
-#include <android-base/parseint.h>
-#include <android-base/strings.h>
-
-#include <string>
-#include <vector>
-
-#include <sys/sysmacros.h>
-
-using android::base::ParseUint;
-
-namespace iorap::inode2filename {
-
-// TODO: refactor to return expected<Inode, string>
-bool Inode::Parse(const std::string& str, Inode* out, std::string* error_msg) {
-  DCHECK(out != nullptr);
-  DCHECK(error_msg != nullptr);
-
-  // Major:minor:inode OR dev_t@inode
-  std::vector<std::string> lst_pair = android::base::Split(str, "@");
-  if (lst_pair.size() == 2) {
-    size_t dev_whole = 0;
-    if (!ParseUint(lst_pair[0], &dev_whole)) {
-      *error_msg = "Failed to parse the whole device id as uint.";
-      return false;
-    }
-
-    dev_t dev_w = static_cast<dev_t>(dev_whole);
-    out->device_major = major(dev_w);
-    out->device_minor = minor(dev_w);
-
-    if (!ParseUint(lst_pair[1], &out->inode)) {
-      *error_msg = "Failed to parse inode as uint.";
-      return false;
-    }
-
-    return true;
-  }
-
-  std::vector<std::string> lst = android::base::Split(str, ":");
-
-  if (lst.size() != 3) {
-    *error_msg = "Too few : separated items";
-    return false;
-  }
-
-  if (!ParseUint(lst[0], &out->device_major)) {
-    *error_msg = "Failed to parse 0th element as a uint";
-    return false;
-  }
-
-  if (!ParseUint(lst[1], &out->device_minor)) {
-    *error_msg = "Failed to parse 1st element as a uint";
-    return false;
-  }
-
-  if (!ParseUint(lst[2], &out->inode)) {
-    *error_msg = "Failed to parse 2nd element as a uint";
-    return false;
-  }
-
-  return true;
-}
-
-}  // namespace iorap::inode2filename
-
-// Ensure our pollution-free aliases match the typedefs in the system headers.
-static_assert(std::is_same_v<iorap::inode2filename::dev_t, dev_t>);
-static_assert(std::is_same_v<iorap::inode2filename::ino_t, ino_t>);
-
-// TODO: consider some tests for major, minor, etc.
\ No newline at end of file
diff --git a/src/inode2filename/inode.h b/src/inode2filename/inode.h
deleted file mode 100644
index f336a14..0000000
--- a/src/inode2filename/inode.h
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_INODE2FILENAME_INODE_H_
-#define IORAP_SRC_INODE2FILENAME_INODE_H_
-
-#include <functional>
-#include <ostream>
-#include <string>
-
-#include <stddef.h>
-
-namespace iorap::inode2filename {
-
-// Avoid polluting headers.
-#if defined(__ANDROID__)
-#  if !defined(__LP64__)
-/* This historical accident means that we had a 32-bit dev_t on 32-bit architectures. */
-using dev_t = uint32_t;
-#  else
-using dev_t = uint64_t;
-#  endif
-using ino_t = unsigned long;
-#else
-#  if !defined(__x86_64__)
-using dev_t = unsigned long long;
-using ino_t = unsigned long long;
-#  else
-using dev_t = unsigned long;
-using ino_t = unsigned long;
-#  endif
-#endif
-
-#ifdef makedev
-#undef makedev
-#endif
-
-/** Combines `major` and `minor` into a device number. */
-constexpr inline dev_t makedev(unsigned int major, unsigned int minor) {
-  return
-      (((major) & 0xfffff000ULL) << 32) | (((major) & 0xfffULL) << 8) |
-      (((minor) & 0xffffff00ULL) << 12) | (((minor) & 0xffULL));
-}
-
-#ifdef major
-#undef major
-#endif
-
-/** Extracts the major part of a device number. */
-constexpr inline unsigned int major(dev_t dev) {
-  return
-      ((unsigned) ((((unsigned long long) (dev) >> 32) & 0xfffff000) | (((dev) >> 8) & 0xfff)));
-}
-
-#ifdef minor
-#undef minor
-#endif
-
-/** Extracts the minor part of a device number. */
-constexpr inline unsigned int minor(dev_t dev) {
-  return
-      ((unsigned) ((((dev) >> 12) & 0xffffff00) | ((dev) & 0xff)));
-};
-// Note: above definitions copied from sysmacros.h, to avoid polluting global namespace in a header.
-
-/*
- * A convenient datum representing a (dev_t, ino_t) tuple.
- *
- * ino_t values may be reused across different devices (e.g. different partitions),
- * so we need the full tuple to uniquely identify an inode on a system.
- */
-struct Inode {
-  size_t device_major;  // dev_t = makedev(major, minor)
-  size_t device_minor;
-  size_t inode;         // ino_t = inode
-
-  // "Major:minor:inode" OR "dev_t@inode"
-  static bool Parse(const std::string& str, /*out*/Inode* out, /*out*/std::string* error_msg);
-
-  constexpr bool operator==(const Inode& rhs) const {
-    return device_major == rhs.device_major &&
-        device_minor == rhs.device_minor &&
-        inode == rhs.inode;
-  }
-
-  constexpr bool operator!=(const Inode& rhs) const {
-    return !(*this == rhs);
-  }
-
-  Inode() = default;
-  constexpr Inode(size_t device_major, size_t device_minor, size_t inode)
-    : device_major{device_major}, device_minor{device_minor}, inode{inode} {
-  }
-
-  static constexpr Inode FromDeviceAndInode(dev_t dev, ino_t inode) {
-    return Inode{major(dev), minor(dev), static_cast<size_t>(inode)};
-  }
-
-  constexpr dev_t GetDevice() const {
-    return makedev(device_major, device_minor);
-  }
-
-  constexpr ino_t GetInode() const {
-    return static_cast<ino_t>(inode);
-  }
-};
-
-inline std::ostream& operator<<(std::ostream& os, const Inode& inode) {
-  os << inode.device_major << ":" << inode.device_minor << ":" << inode.inode;
-  return os;
-}
-
-}  // namespace iorap::inode2filename
-
-namespace std {
-  template <>
-  struct hash<iorap::inode2filename::Inode> {
-      using argument_type = iorap::inode2filename::Inode;
-      using result_type = size_t;
-      result_type operator()(argument_type const& s) const noexcept {
-        // Hash the inode by using only the inode#. Ignore devices, we are extremely unlikely
-        // to ever collide on the devices.
-        result_type const h1 = std::hash<size_t>{}(s.inode);
-        return h1;
-      }
-  };
-}  // namespace std
-
-namespace rxcpp {
-template <class T, typename>
-struct filtered_hash;
-
-// support for the 'distinct' rx operator.
-template <>
-struct filtered_hash<iorap::inode2filename::Inode, void> : std::hash<iorap::inode2filename::Inode> {
-};
-}  // namespace rxcpp
-
-#endif  // IORAP_SRC_INODE2FILENAME_INODE_H_
diff --git a/src/inode2filename/inode_resolver.cc b/src/inode2filename/inode_resolver.cc
deleted file mode 100644
index 5e2945d..0000000
--- a/src/inode2filename/inode_resolver.cc
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "inode2filename/inode_resolver.h"
-
-#include "common/cmd_utils.h"
-#include "inode2filename/out_of_process_inode_resolver.h"
-#include "inode2filename/search_directories.h"
-
-#include <android-base/logging.h>
-
-#include <fstream>
-#include <stdio.h>
-
-namespace rx = rxcpp;
-
-namespace iorap::inode2filename {
-
-std::vector<std::string> ToArgs(ProcessMode process_mode) {
-  const char* value = nullptr;
-
-  switch (process_mode) {
-    case ProcessMode::kInProcessDirect:
-      value = "in";
-      break;
-    case ProcessMode::kInProcessIpc:
-      value = "in-ipc";
-      break;
-    case ProcessMode::kOutOfProcessIpc:
-      value = "out";
-      break;
-  }
-
-  std::vector<std::string> args;
-  iorap::common::AppendNamedArg(args, "--process-mode", value);
-  return args;
-}
-
-std::vector<std::string> ToArgs(VerifyKind verify_kind) {
-  const char* value = nullptr;
-
-  switch (verify_kind) {
-    case VerifyKind::kNone:
-      value = "none";
-      break;
-    case VerifyKind::kStat:
-      value = "stat";
-      break;
-  }
-
-  std::vector<std::string> args;
-  iorap::common::AppendNamedArg(args, "--verify", value);
-  return args;
-}
-
-std::vector<std::string> ToArgs(const InodeResolverDependencies& deps) {
-  std::vector<std::string> args = ToArgs(*static_cast<const DataSourceDependencies*>(&deps));
-  iorap::common::AppendArgsRepeatedly(args, ToArgs(deps.process_mode));
-  iorap::common::AppendArgsRepeatedly(args, ToArgs(deps.verify));
-
-  return args;
-}
-
-struct InodeResolver::Impl {
-  Impl(InodeResolverDependencies dependencies)
-    : dependencies_{std::move(dependencies)} {
-    DCHECK(dependencies_.system_call != nullptr);
-    data_source_ = DataSource::Create(/*downcast*/dependencies_);
-  }
-  Impl(InodeResolverDependencies dependencies, std::shared_ptr<DataSource> data_source)
-    : dependencies_{std::move(dependencies)} {
-    DCHECK(dependencies_.system_call != nullptr);
-    data_source_ = std::move(data_source);
-    DCHECK(data_source_ != nullptr);
-  }
-  InodeResolverDependencies dependencies_;
-  std::shared_ptr<DataSource> data_source_;
-};
-
-InodeResolver::InodeResolver(InodeResolverDependencies dependencies)
-  : impl_(new InodeResolver::Impl{std::move(dependencies)}) {
-}
-
-InodeResolver::InodeResolver(InodeResolverDependencies dependencies,
-                             std::shared_ptr<DataSource> data_source)
-  : impl_(new InodeResolver::Impl{std::move(dependencies), std::move(data_source)}) {
-}
-
-std::shared_ptr<InodeResolver> InodeResolver::Create(InodeResolverDependencies dependencies) {
-  if (dependencies.process_mode == ProcessMode::kInProcessDirect) {
-    return std::shared_ptr<InodeResolver>{
-        new InodeResolver{std::move(dependencies)}};
-  } else if (dependencies.process_mode == ProcessMode::kOutOfProcessIpc) {
-    return std::shared_ptr<InodeResolver>{
-        new OutOfProcessInodeResolver{std::move(dependencies)}};
-  } else {
-    CHECK(false);
-  }
-  return nullptr;
-}
-
-std::shared_ptr<InodeResolver> InodeResolver::Create(InodeResolverDependencies dependencies,
-                                                     std::shared_ptr<DataSource> data_source) {
-  if (dependencies.process_mode == ProcessMode::kInProcessDirect) {
-    return std::shared_ptr<InodeResolver>{
-        new InodeResolver{std::move(dependencies), std::move(data_source)}};
-  } else if (dependencies.process_mode == ProcessMode::kOutOfProcessIpc) {
-    CHECK(false);  // directly providing a DataSource only makes sense in-process
-  } else {
-    CHECK(false);
-  }
-  return nullptr;
-}
-
-rxcpp::observable<InodeResult>
-    InodeResolver::FindFilenamesFromInodes(rxcpp::observable<Inode> inodes) const {
-
-  // It's inefficient to search for inodes until the full search list is available,
-  // so first reduce to a vector so we can access all the inodes simultaneously.
-  return inodes.reduce(std::vector<Inode>{},
-                       [](std::vector<Inode> vec, Inode inode) {
-                         vec.push_back(inode);
-                         return vec;
-                       },
-                       [](std::vector<Inode> v) {
-                         return v;  // TODO: use an identity function
-                       })
-    .flat_map([self=shared_from_this()](std::vector<Inode> vec) {
-      // All borrowed values (e.g. SystemCall) must outlive the observable.
-      return self->FindFilenamesFromInodes(vec);
-    }
-  );
-}
-
-rxcpp::observable<InodeResult>
-InodeResolver::FindFilenamesFromInodes(std::vector<Inode> inodes) const {
-  const DataSource& data_source = *impl_->data_source_;
-  const InodeResolverDependencies& dependencies = impl_->dependencies_;
-
-  // Get lazy list of inodes from the data source.
-  rxcpp::observable<InodeResult> all_inodes = impl_->data_source_->EmitInodes();
-
-  // Filter it according to the source+dependency requirements.
-  // Unsubscribe from 'all_inodes' early if all inodes are matched early.
-  const bool needs_device_number = !data_source.ResultIncludesDeviceNumber();
-  const bool needs_verification = dependencies.verify == VerifyKind::kStat;
-  SearchDirectories search{impl_->dependencies_.system_call};
-  return search.FilterFilenamesForSpecificInodes(all_inodes,
-                                                 inodes,
-                                                 needs_device_number,
-                                                 needs_verification);
-}
-
-rxcpp::observable<InodeResult>
-InodeResolver::EmitAll() const {
-  const DataSource& data_source = *impl_->data_source_;
-  const InodeResolverDependencies& dependencies = impl_->dependencies_;
-
-  // Get lazy list of inodes from the data source.
-  rxcpp::observable<InodeResult> all_inodes = impl_->data_source_->EmitInodes();
-
-  // Apply verification and fill-in missing device numbers.
-  const bool needs_device_number = !data_source.ResultIncludesDeviceNumber();
-  const bool needs_verification = dependencies.verify == VerifyKind::kStat;
-  SearchDirectories search{impl_->dependencies_.system_call};
-  return search.EmitAllFilenames(all_inodes,
-                                 needs_device_number,
-                                 needs_verification);
-}
-
-InodeResolver::~InodeResolver() {
-  // std::unique_ptr requires complete types, but we hide the definition in the header.
-  delete impl_;
-  // XX: Does this work if we just force the dtor definition into the .cc file with a unique_ptr?
-}
-
-InodeResolverDependencies& InodeResolver::GetDependencies() {
-  return impl_->dependencies_;
-}
-
-const InodeResolverDependencies& InodeResolver::GetDependencies() const {
-  return impl_->dependencies_;
-}
-
-void InodeResolver::StartRecording() {
-  impl_->data_source_->StartRecording();
-}
-
-void InodeResolver::StopRecording() {
-  impl_->data_source_->StopRecording();
-}
-
-// TODO: refactor more code from search_directories into this file.
-// XX: do we also need a DataSink class? lets see if recording gets more complicated.
-
-}  // namespace iorap::inode2filename
diff --git a/src/inode2filename/inode_resolver.h b/src/inode2filename/inode_resolver.h
deleted file mode 100644
index 218640f..0000000
--- a/src/inode2filename/inode_resolver.h
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_INODE2FILENAME_INODE_RESOLVER_H_
-#define IORAP_SRC_INODE2FILENAME_INODE_RESOLVER_H_
-
-#include "common/expected.h"
-#include "inode2filename/data_source.h"
-#include "inode2filename/inode.h"
-#include "inode2filename/system_call.h"
-
-#include <rxcpp/rx.hpp>
-
-#include <memory>
-#include <optional>
-#include <string>
-#include <vector>
-namespace iorap::inode2filename {
-
-enum class ProcessMode {
-  // Test modes:
-  kInProcessDirect,  // Execute the code directly.
-  kInProcessIpc,     // Execute code via IPC layer using multiple threads.
-  // Shipping mode:
-  kOutOfProcessIpc,  // Execute code via fork+exec with IPC.
-
-  // Note: in-process system-wide stat(2)/readdir/etc is blocked by selinux.
-  // Attempting to call the test modes will fail with -EPERM.
-  //
-  // Use fork+exec mode in shipping configurations, which spawns inode2filename
-  // as a separate command.
-};
-
-enum class VerifyKind {
-  kNone,
-  kStat,
-};
-
-std::vector<std::string> ToArgs(VerifyKind verify_kind);
-
-struct InodeResolverDependencies : public DataSourceDependencies {
-  ProcessMode process_mode = ProcessMode::kInProcessDirect;
-  VerifyKind verify{VerifyKind::kStat};  // Filter out results that aren't up-to-date with stat(2) ?
-};
-
-std::vector<std::string> ToArgs(const InodeResolverDependencies& deps);
-
-// Create an rx-observable chain that allows searching for inode->filename mappings given
-// a set of inode keys.
-class InodeResolver : public std::enable_shared_from_this<InodeResolver> {
- public:
-  static std::shared_ptr<InodeResolver> Create(InodeResolverDependencies dependencies,
-                                               std::shared_ptr<DataSource> data_source);  // nonnull
-
-  // Convenience function for above: Uses DataSource::Create for the data-source.
-  static std::shared_ptr<InodeResolver> Create(InodeResolverDependencies dependencies);
-
-  // Search the associated data source to map each inode in 'inodes' to a file path.
-  //
-  // Observes DataSource::EmitInodes(), which is unsubscribed from early once all inodes are found.
-  //
-  // Notes:
-  // * Searching does not begin until all 'inodes' are observed to avoid rescanning.
-  // * If the observable is unsubscribed to prior to completion, searching will halt.
-  //
-  // Post-condition: All emitted results are in inodes, and all inodes are in emitted results.
-  rxcpp::observable<InodeResult>
-      FindFilenamesFromInodes(rxcpp::observable<Inode> inodes) const;
-      // TODO: feels like we could turn this into a general helper?
-  // Convenience function for above.
-  virtual rxcpp::observable<InodeResult>
-      FindFilenamesFromInodes(std::vector<Inode> inodes) const;
-
-  // Enumerate *all* inodes available from the data source, associating it with a filepath.
-  //
-  // Depending on the data source (e.g. diskscan), it can take a very long time for this observable
-  // to complete. The intended use-case is for development/debugging, not for production.
-  //
-  // Observes DataSource::EmitInodes() until it reaches #on_completed.
-  //
-  // Notes:
-  // * If the observable is unsubscribed to prior to completion, searching will halt.
-  virtual rxcpp::observable<InodeResult>
-      EmitAll() const;
-
-  // Notifies the DataSource to begin recording.
-  // Some DataSources may be continuously refreshing, but only if recording is enabled.
-  // To get the most up-to-date data, toggle recording before reading the inodes out.
-  void StartRecording();  // XX: feels like this should be BPF-specific.
-
-  // Notifies the DataSource to stop recording.
-  // Some DataSources may be continuously refreshing, but only if recording is enabled.
-  // The snapshot of data returned by e.g. #EmitAll would then not change outside of recording.
-  void StopRecording();
-
-  virtual ~InodeResolver();
- private:
-  struct Impl;
-  Impl* impl_;
-
- protected:
-  InodeResolver(InodeResolverDependencies dependencies);
-  InodeResolver(InodeResolverDependencies dependencies, std::shared_ptr<DataSource> data_source);
-  InodeResolverDependencies& GetDependencies();
-  const InodeResolverDependencies& GetDependencies() const;
-};
-
-}
-
-#endif  // IORAP_SRC_INODE2FILENAME_INODE_RESOLVER_H_
diff --git a/src/inode2filename/inode_result.cc b/src/inode2filename/inode_result.cc
deleted file mode 100644
index 139b038..0000000
--- a/src/inode2filename/inode_result.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "inode2filename/inode_result.h"
-
-#include <string.h>
-
-namespace iorap::inode2filename {
-
-std::optional<std::string_view> InodeResult::ErrorMessage() const {
-  if (data) {
-    return std::nullopt;
-  }
-
-  const int err_no = data.error();
-  return std::string_view{
-    [=]() -> const char * {
-      switch (err_no) {
-        case InodeResult::kCouldNotFindFilename:
-          return "Could not find filename";
-        case InodeResult::kVerificationFailed:
-          return "Verification failed";
-        default:
-          return strerror(err_no);
-      }
-    }()
-  };
-}
-
-std::ostream& operator<<(std::ostream& os, const InodeResult& result) {
-  os << "InodeResult{";
-  if (result) {
-      os << "OK,";
-  } else {
-      os << "ERR,";
-  }
-
-  os << result.inode << ",";
-
-  if (result) {
-    os << "\"" << result.data.value() << "\"";
-  } else {
-    os << result.data.error();
-    os << " (" << *result.ErrorMessage() << ")";
-  }
-
-  os << "}";
-  return os;
-}
-
-}  // namespace iorap::inode2filename
\ No newline at end of file
diff --git a/src/inode2filename/inode_result.h b/src/inode2filename/inode_result.h
deleted file mode 100644
index df352fb..0000000
--- a/src/inode2filename/inode_result.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_INODE2FILENAME_INODE_RESULT_H_
-#define IORAP_SRC_INODE2FILENAME_INODE_RESULT_H_
-
-#include "common/expected.h"
-#include "inode2filename/inode.h"
-#include "inode2filename/inode_result.h"
-#include "inode2filename/system_call.h"
-
-#include <rxcpp/rx.hpp>
-
-#include <memory>
-#include <optional>
-#include <string>
-#include <vector>
-namespace iorap::inode2filename {
-
-// Tuple of (Inode -> (Filename|Errno))
-struct InodeResult {
-  // We set this error when all root directories have been searched and
-  // yet we still could not find a corresponding filename for the inode under search.
-  static constexpr int kCouldNotFindFilename = ENOKEY;
-
-  // An initial inode->filename mapping was found, but subsequent verification for it failed.
-  static constexpr int kVerificationFailed = EKEYEXPIRED;
-
-  // There is always an inode, but sometimes we may fail to resolve the filename.
-  Inode inode;
-  // Value: Contains the filename (with a root directory as a prefix).
-  // Error: Contains the errno, usually one of the above, otherwise some system error.
-  iorap::expected<std::string /*filename*/, int /*errno*/> data;
-
-  static InodeResult makeSuccess(Inode inode, std::string filename) {
-    return InodeResult{inode, std::move(filename)};
-  }
-
-  static InodeResult makeFailure(Inode inode, int err_no) {
-    return InodeResult{inode, iorap::unexpected{err_no}};
-  }
-
-  constexpr explicit operator bool() const {
-    return data.has_value();
-  }
-
-  constexpr bool operator==(const InodeResult& other) const {
-    if (inode == other.inode) {
-      if (data && other.data) {
-        return *data == *other.data;
-      } else if (!data && !other.data) {
-        return data.error() == other.data.error();
-      }
-      // TODO: operator== for expected
-    }
-    return false;
-  }
-
-  constexpr bool operator!=(const InodeResult& other) const {
-    return !(*this == other);
-  }
-
-  // Returns a human-readable error message, or 'nullopt' if there was no error.
-  std::optional<std::string_view> ErrorMessage() const;
-};
-
-std::ostream& operator<<(std::ostream& os, const InodeResult& result);
-
-}  // namespace iorap::inode2filename
-
-#endif  // IORAP_SRC_INODE2FILENAME_INODE_RESULT_H_
\ No newline at end of file
diff --git a/src/inode2filename/main.cc b/src/inode2filename/main.cc
deleted file mode 100644
index 986f6ac..0000000
--- a/src/inode2filename/main.cc
+++ /dev/null
@@ -1,455 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "common/debug.h"
-#include "common/expected.h"
-#include "inode2filename/inode_resolver.h"
-
-#include <android-base/strings.h>
-
-#include <iostream>
-#include <fstream>
-#include <sstream>
-#include <string_view>
-
-#if defined(IORAP_INODE2FILENAME_MAIN)
-
-namespace iorap::inode2filename {
-
-void Usage(char** argv) {
-  std::cerr << "Usage: " << argv[0] << " <options> <<inode_syntax>> [inode_syntax1 inode_syntax2 ...]" << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "  Block until all inodes have been read in, then begin searching for filenames for those inodes." << std::endl;
-  std::cerr << "  Results are written immediately as they are available, and once all inodes are found, " << std::endl;
-  std::cerr << "  the program will terminate." << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "    Inode syntax:     ('dev_t@inode' | 'major:minor:inode')" << std::endl;
-  std::cerr << "" << std::endl;       // CLI-only flags.
-  std::cerr << "    --help,-h         Print this Usage." << std::endl;
-  std::cerr << "    --verbose,-v      Set verbosity (default off)." << std::endl;
-  std::cerr << "    --wait,-w         Wait for key stroke before continuing (default off)." << std::endl;
-  std::cerr << "" << std::endl;       // General flags.
-  std::cerr << "    --all,-a          Enumerate all inode->filename mappings in the dataset (default off)." << std::endl;
-  std::cerr << "                      All <<inode_syntaxN>> arguments are ignored." << std::endl;
-  std::cerr << "    --data-source=,   Choose a data source (default 'diskscan')." << std::endl;
-  std::cerr << "    -ds " << std::endl;
-  std::cerr << "        diskscan      Scan disk recursively using readdir." << std::endl;
-  std::cerr << "        textcache     Use the file from the '--output-format=text'." << std::endl;
-  std::cerr << "        bpf           Query kernel BPF maps (experimental)." << std::endl;
-  std::cerr << "    --output=,-o      Choose an output file (default 'stdout')." << std::endl;
-  std::cerr << "    --output-format=, Choose an output format (default 'log')." << std::endl;
-  std::cerr << "    -of " << std::endl;
-  std::cerr << "        log           Log human-readable, non-parsable format to stdout+logcat." << std::endl;
-  std::cerr << "        textcache     Results are in the same format as system/extras/pagecache." << std::endl;
-  std::cerr << "        ipc           Results are in a binary inter-process communications format" << std::endl;
-  std::cerr << "    --process-mode=,  Choose a process mode (default 'in'). Test-oriented." << std::endl;
-  std::cerr << "    -pm " << std::endl;
-  std::cerr << "        in            Use a single process to do the work in." << std::endl;
-  std::cerr << "        out           Out-of-process work (forks into a -pm=in)." << std::endl;
-  std::cerr << "    --verify=,-vy     Verification modes for the data source (default 'stat')." << std::endl;
-  std::cerr << "        stat          Use stat(2) call to validate data inodes are up-to-date. " << std::endl;
-  std::cerr << "        none          Trust that the data-source is up-to-date without checking." << std::endl;
-  std::cerr << "" << std::endl;       // --data-source=<?> specific flags.
-  std::cerr << "    Data-source-specific commands:" << std::endl;
-  std::cerr << "      --data-source=diskscan" << std::endl;
-  std::cerr << "          --root=,-r        Add root directory (default '.'). Repeatable." << std::endl;
-  std::cerr << "      --data-source=textcache" << std::endl;
-  std::cerr << "          --textcache=,-tc  Name of file that contains the textcache." << std::endl;
-  std::cerr << "" << std::endl;       // Programmatic flags.
-  std::cerr << "    --in-fd=#         Input file descriptor. Default input is from argv." << std::endl;
-  std::cerr << "    --out-fd=#        Output file descriptor. Default stdout." << std::endl;
-  exit(1);
-}
-
-static fruit::Component<SystemCall> GetSystemCallComponent() {
-    return fruit::createComponent().bind<SystemCall, SystemCallImpl>();
-}
-
-std::optional<DataSourceKind> ParseDataSourceKind(std::string_view str) {
-  if (str == "diskscan") {
-    return DataSourceKind::kDiskScan;
-  } else if (str == "textcache") {
-    return DataSourceKind::kTextCache;
-  } else if (str == "bpf") {
-    return DataSourceKind::kBpf;
-  }
-  return std::nullopt;
-}
-
-enum class OutputFormatKind {
-  kLog,
-  kTextCache,
-  kIpc,
-};
-
-std::optional<OutputFormatKind> ParseOutputFormatKind(std::string_view str) {
-  if (str == "log") {
-    return OutputFormatKind::kLog;
-  } else if (str == "textcache") {
-    return OutputFormatKind::kTextCache;
-  } else if (str == "ipc") {
-    return OutputFormatKind::kIpc;
-  }
-  return std::nullopt;
-}
-
-std::optional<VerifyKind> ParseVerifyKind(std::string_view str) {
-  if (str == "none") {
-    return VerifyKind::kNone;
-  } else if (str == "stat") {
-    return VerifyKind::kStat;
-  }
-  return std::nullopt;
-}
-
-std::optional<ProcessMode> ParseProcessMode(std::string_view str) {
-  if (str == "in") {
-    return ProcessMode::kInProcessDirect;
-  } else if (str == "out") {
-    return ProcessMode::kOutOfProcessIpc;
-  }
-  return std::nullopt;
-}
-
-bool StartsWith(std::string_view haystack, std::string_view needle) {
-  return haystack.size() >= needle.size()
-      && haystack.compare(0, needle.size(), needle) == 0;
-}
-
-bool EndsWith(std::string_view haystack, std::string_view needle) {
-  return haystack.size() >= needle.size()
-      && haystack.compare(haystack.size() - needle.size(), haystack.npos, needle) == 0;
-}
-
-bool StartsWithOneOf(std::string_view haystack,
-                     std::string_view needle,
-                     std::string_view needle2) {
-  return StartsWith(haystack, needle) || StartsWith(haystack, needle2);
-}
-
-enum ParseError {
-  kParseSkip,
-  kParseFailed,
-};
-
-std::optional<std::string> ParseNamedArgument(std::initializer_list<std::string> names,
-                                              std::string argstr,
-                                              std::optional<std::string> arg_next,
-                                              /*inout*/
-                                              int* arg_pos) {
-  for (const std::string& name : names) {
-    {
-      // Try parsing only 'argstr' for '--foo=bar' type parameters.
-      std::vector<std::string> split_str = ::android::base::Split(argstr, "=");
-      if (split_str.size() >= 2) {
-        /*
-        std::cerr << "ParseNamedArgument(name=" << name << ", argstr='"
-                  <<  argstr << "')" << std::endl;
-        */
-
-        if (split_str[0] + "=" == name) {
-          return split_str[1];
-        }
-      }
-    }
-    //if (EndsWith(name, "=")) {
-    //  continue;
-    /*} else */ {
-      // Try parsing 'argstr arg_next' for '-foo bar' type parameters.
-      if (argstr == name) {
-        ++(*arg_pos);
-
-        if (arg_next) {
-          return arg_next;
-        } else {
-          // Missing argument, e.g. '-foo' was the last token in the argv.
-          std::cerr << "Missing " << name << " flag value." << std::endl;
-          exit(1);
-        }
-      }
-    }
-  }
-
-  return std::nullopt;
-}
-
-int main(int argc, char** argv) {
-  android::base::InitLogging(argv);
-  android::base::SetLogger(android::base::StderrLogger);
-
-  bool all = false;
-  bool wait_for_keystroke = false;
-  bool enable_verbose = false;
-  std::vector<std::string> root_directories;
-  std::vector<Inode> inode_list;
-  int recording_time_sec = 0;
-
-  DataSourceKind data_source = DataSourceKind::kDiskScan;
-  OutputFormatKind output_format = OutputFormatKind::kLog;
-  VerifyKind verify = VerifyKind::kStat;
-  ProcessMode process_mode = ProcessMode::kInProcessDirect;
-
-  std::optional<std::string> output_filename;
-  std::optional<int /*fd*/> in_fd, out_fd;  // input-output file descriptors [for fork+exec].
-  std::optional<std::string> text_cache_filename;
-
-  if (argc == 1) {
-    Usage(argv);
-  }
-
-  for (int arg = 1; arg < argc; ++arg) {
-    std::string argstr = argv[arg];
-    std::optional<std::string> arg_next;
-    if ((arg + 1) < argc) {
-      arg_next = argv[arg+1];
-    }
-
-    if (argstr == "--help" || argstr == "-h") {
-      Usage(argv);
-    } else if (auto val = ParseNamedArgument({"--root=", "-r"}, argstr, arg_next, /*inout*/&arg);
-               val) {
-      root_directories.push_back(*val);
-    } else if (argstr == "--verbose" || argstr == "-v") {
-      enable_verbose = true;
-    } else if (argstr == "--wait" || argstr == "-w") {
-      wait_for_keystroke = true;
-    }
-     else if (argstr == "--all" || argstr == "-a") {
-      all = true;
-    } else if (auto val = ParseNamedArgument({"--data-source=", "-ds"},
-                                             argstr,
-                                             arg_next,
-                                             /*inout*/&arg);
-               val) {
-      auto ds = ParseDataSourceKind(*val);
-      if (!ds) {
-        std::cerr << "Invalid --data-source=<value>" << std::endl;
-        return 1;
-      }
-      data_source = *ds;
-    } else if (auto val = ParseNamedArgument({"--output=", "-o"},
-                                             argstr,
-                                             arg_next,
-                                             /*inout*/&arg);
-               val) {
-      output_filename = *val;
-    } else if (auto val = ParseNamedArgument({"--process-mode=", "-pm"},
-                                             argstr,
-                                             arg_next,
-                                             /*inout*/&arg);
-               val) {
-      auto pm = ParseProcessMode(*val);
-      if (!pm) {
-        std::cerr << "Invalid --process-mode=<value>" << std::endl;
-        return 1;
-      }
-      process_mode = *pm;
-    }
-    else if (auto val = ParseNamedArgument({"--output-format=", "-of"},
-                                             argstr,
-                                             arg_next,
-                                             /*inout*/&arg);
-               val) {
-      auto of = ParseOutputFormatKind(*val);
-      if (!of) {
-        std::cerr << "Missing --output-format=<value>" << std::endl;
-        return 1;
-      }
-      output_format = *of;
-    } else if (auto val = ParseNamedArgument({"--verify=", "-vy="},
-                                             argstr,
-                                             arg_next,
-                                             /*inout*/&arg);
-               val) {
-      auto vy = ParseVerifyKind(*val);
-      if (!vy) {
-        std::cerr << "Invalid --verify=<value>" << std::endl;
-        return 1;
-      }
-      verify = *vy;
-    } else if (auto val = ParseNamedArgument({"--textcache=", "-tc"},
-                                             argstr,
-                                             arg_next,
-                                             /*inout*/&arg);
-               val) {
-      text_cache_filename = *val;
-    } else {
-      Inode maybe_inode{};
-
-      std::string error_msg;
-      if (Inode::Parse(argstr, /*out*/&maybe_inode, /*out*/&error_msg)) {
-        inode_list.push_back(maybe_inode);
-      } else {
-        if (argstr.size() >= 1) {
-          if (argstr[0] == '-') {
-            std::cerr << "Unrecognized flag: " << argstr << std::endl;
-            return 1;
-          }
-        }
-
-        std::cerr << "Failed to parse inode (" << argstr << ") because: " << error_msg << std::endl;
-        return 1;
-      }
-    }
-  }
-
-  if (root_directories.size() == 0) {
-    root_directories.push_back(".");
-  }
-
-  if (inode_list.size() == 0 && !all) {
-    std::cerr << "Provide at least one inode. Or use --all to dump everything." << std::endl;
-    return 1;
-  } else if (all && inode_list.size() > 0) {
-    std::cerr << "[WARNING]: --all flag ignores all inodes passed on command line." << std::endl;
-  }
-
-  std::ofstream fout;
-  if (output_filename) {
-    fout.open(*output_filename);
-    if (!fout) {
-      std::cerr << "Failed to open output file for writing: \"" << *output_filename << "\"";
-      return 1;
-    }
-  } else {
-    fout.open("/dev/null");  // have to open *something* otherwise rdbuf fails.
-    fout.basic_ios<char>::rdbuf(std::cout.rdbuf());
-  }
-
-  if (enable_verbose) {
-    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
-
-    LOG(VERBOSE) << "Verbose check";
-    LOG(VERBOSE) << "Debug check: " << ::iorap::kIsDebugBuild;
-
-    for (auto& inode_num : inode_list) {
-      LOG(VERBOSE) << "Searching for inode " << inode_num;
-    }
-
-    LOG(VERBOSE) << "Dumping all inodes? " << all;
-  }
-  // else use
-  // $> ANDROID_LOG_TAGS='*:d' iorap.inode2filename <args>
-  // which will enable arbitrary log levels.
-
-  // Useful to attach a debugger...
-  // 1) $> inode2filename -w <args>
-  // 2) $> gdbclient <pid>
-  if (wait_for_keystroke) {
-    LOG(INFO) << "Self pid: " << getpid();
-    LOG(INFO) << "Press any key to continue...";
-    std::cin >> wait_for_keystroke;
-  }
-
-  fruit::Injector<SystemCall> injector(GetSystemCallComponent);
-
-  InodeResolverDependencies ir_dependencies;
-  // Passed from command-line.
-  ir_dependencies.data_source = data_source;
-  ir_dependencies.process_mode = process_mode;
-  ir_dependencies.root_directories = root_directories;
-  ir_dependencies.text_cache_filename = text_cache_filename;
-  ir_dependencies.verify = verify;
-  // Hardcoded.
-  ir_dependencies.system_call = injector.get<SystemCall*>();
-
-  std::shared_ptr<InodeResolver> inode_resolver =
-      InodeResolver::Create(ir_dependencies);
-
-  inode_resolver->StartRecording();
-  sleep(recording_time_sec);  // TODO: add cli flag for this when we add something that needs it.
-  inode_resolver->StopRecording();
-
-  auto/*observable<InodeResult>*/ inode_results = all
-      ? inode_resolver->EmitAll()
-      : inode_resolver->FindFilenamesFromInodes(std::move(inode_list));
-
-  int return_code = 2;
-  inode_results.subscribe(
-      /*on_next*/[&return_code, output_format, &fout](const InodeResult& result) {
-    if (result) {
-      LOG(DEBUG) << "Inode match: " << result;
-      if (output_format == OutputFormatKind::kLog) {
-        fout << "\033[1;32m[OK]\033[0m  "
-             << result.inode
-             << " \"" << result.data.value() << "\"" << std::endl;
-      } else if (output_format == OutputFormatKind::kIpc) {
-        std::stringstream stream;
-        stream << "K " << result.inode << " " << result.data.value();
-        std::string line = stream.str();
-
-        // Convert the size to 4 bytes.
-        int32_t size = line.size();
-        char buf[sizeof(int32_t)];
-        memcpy(buf, &size, sizeof(int32_t));
-        fout.write(buf, sizeof(int32_t));
-        fout.write(line.c_str(), size);
-      } else if (output_format == OutputFormatKind::kTextCache) {
-        // Same format as TextCacheDataSource (system/extras/pagecache/pagecache.py -d)
-        //   "$device_number $inode $filesize $filename..."
-        const Inode& inode = result.inode;
-        fout << inode.GetDevice() << " "
-             << inode.GetInode()
-             << " -1 "  // always -1 for filesize, since we don't track what it is.
-             << result.data.value() << "\n";  // don't use endl which flushes, for faster writes.
-      } else {
-        LOG(FATAL) << "Not implemented this kind of --output-format";
-      }
-
-      return_code = 0;
-    } else {
-      LOG(DEBUG) << "Failed to match inode: " << result;
-      if (output_format == OutputFormatKind::kLog) {
-        fout << "\033[1;31m[ERR]\033[0m "
-             << result.inode
-             << " '" << *result.ErrorMessage() << "'" << std::endl;
-      } else if (output_format == OutputFormatKind::kIpc) {
-        std::stringstream stream;
-        stream << "E " << result.inode << " " << result.data.error() << std::endl;
-        std::string line = stream.str();
-
-        // Convert the size to 4 bytes.
-        int32_t size = line.size();
-        char buf[sizeof(int32_t)];
-        memcpy(buf, &size, sizeof(int32_t));
-        fout.write(buf, sizeof(int32_t));
-        fout.write(line.c_str(), size);
-      }
-      else if (output_format == OutputFormatKind::kTextCache) {
-        // Don't add bad results to the textcache. They are dropped.
-      } else {
-        LOG(FATAL) << "Not implemented this kind of --output-format";
-      }
-    }
-  }, /*on_error*/[&return_code](rxcpp::util::error_ptr error) {
-    // Usually occurs very early on before we see the first result.
-    // In this case the error is terminal so we just end up exiting out soon.
-    return_code = 3;
-    LOG(ERROR) << "Critical error: " << rxcpp::util::what(error);
-  });
-
-  // 0 -> found at least a single match,
-  // 1 -> bad parameters,
-  // 2 -> could not find any matches,
-  // 3 -> rxcpp on_error.
-  return return_code;
-}
-
-}  // namespace iorap::inode2filename
-
-int main(int argc, char** argv) {
-  return ::iorap::inode2filename::main(argc, argv);
-}
-
-#endif
diff --git a/src/inode2filename/out_of_process_inode_resolver.cc b/src/inode2filename/out_of_process_inode_resolver.cc
deleted file mode 100644
index f409fd2..0000000
--- a/src/inode2filename/out_of_process_inode_resolver.cc
+++ /dev/null
@@ -1,402 +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 "common/cmd_utils.h"
-#include "inode2filename/inode_resolver.h"
-#include "inode2filename/out_of_process_inode_resolver.h"
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/unique_fd.h>
-
-#include <sstream>
-#include <stdio.h>
-#include <unistd.h>
-
-namespace rx = rxcpp;
-
-namespace iorap::inode2filename {
-
-using ::android::base::unique_fd;
-using ::android::base::borrowed_fd;
-
-static const char* GetCommandFileName() {
-  // Avoid ENOENT by execve by specifying the absolute path of inode2filename.
-#ifdef __ANDROID__
-  return "/system/bin/iorap.inode2filename";
-#else
-  static const char* file_name = nullptr;
-
-  if (file_name == nullptr) {
-    char* out_dir = getenv("ANDROID_HOST_OUT");
-    static std::string file_name_str = out_dir;
-    if (out_dir != nullptr) {
-      file_name_str += "/bin/";
-    } else {
-      // Assume it's in the same directory as the binary we are in.
-      std::string self_path;
-      CHECK(::android::base::Readlink("/proc/self/exe", /*out*/&self_path));
-
-      std::string self_dir = ::android::base::Dirname(self_path);
-      file_name_str = self_dir + "/";
-    }
-    file_name_str += "iorap.inode2filename";
-
-    file_name = file_name_str.c_str();
-  }
-
-  return file_name;
-#endif
-}
-
-std::error_code ErrorCodeFromErrno() {
-  int err = errno;
-  return std::error_code(err, std::system_category());
-}
-
-std::ios_base::failure IosBaseFailureWithErrno(const char* message) {
-  std::error_code ec = ErrorCodeFromErrno();
-  return std::ios_base::failure(message, ec);
-}
-
-static constexpr bool kDebugFgets = false;
-
-int32_t ReadLineLength(FILE* stream, bool* eof) {
-  char buf[sizeof(int32_t)];
-  size_t count = fread(buf, 1, sizeof(int32_t), stream);
-  if (feof(stream)) {
-    // If reaching the end of the stream when trying to read the first int, just
-    // return. This is legitimate, because after reading the last line, the next
-    // iteration will reach this.
-    *eof = true;
-    return 0;
-  }
-  int32_t length;
-  memcpy(&length, buf, sizeof(int32_t));
-  return length;
-}
-
-// The steam is like [size1][file1][size2][file2]...[sizeN][fileN].
-std::string ReadOneLine(FILE* stream, bool* eof) {
-  DCHECK(stream != nullptr);
-  DCHECK(eof != nullptr);
-
-  int32_t length = ReadLineLength(stream, eof);
-  if (length <= 0) {
-    PLOG(ERROR) << "unexpected 0 length line.";
-    *eof = true;
-    return "";
-  }
-
-  std::string str(length, '\0');
-  size_t count = fread(&str[0], sizeof(char), length, stream);
-  if (feof(stream) || ferror(stream) || count != (uint32_t)length) {
-    // error! :(
-    PLOG(ERROR) << "unexpected end of the line during fread";
-    *eof = true;
-    return "";
-  }
-  return str;
-}
-
-static inline void LeftTrim(/*inout*/std::string& s) {
-  s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
-    return !std::isspace(ch);
-  }));
-}
-
-// Parses an --output-format=ipc kind of line into an InodeResult.
-// Returns nullopt if parsing failed.
-std::optional<InodeResult> ParseFromLine(const std::string& line) {
-  // inode <- INT:INT:INT
-  // line_ok <- 'K ' inode ' ' STRING
-  // line_err <- 'E ' inode ' ' INT
-  //
-  // result <- line_ok | line_err
-
-  std::stringstream ss{line};
-
-  bool result_ok = false;
-
-  std::string ok_or_error;
-  ss >> ok_or_error;
-
-  if (ss.fail()) {
-    return std::nullopt;
-  }
-
-  if (ok_or_error == "K") {
-    result_ok = true;
-  } else if (ok_or_error == "E") {
-    result_ok = false;
-  } else {
-    return std::nullopt;
-  }
-
-  std::string inode_s;
-  ss >> inode_s;
-
-  if (ss.fail()) {
-    return std::nullopt;
-  }
-
-  Inode inode;
-
-  std::string inode_parse_error_msg;
-  if (!Inode::Parse(inode_s, /*out*/&inode, /*out*/&inode_parse_error_msg)) {
-    return std::nullopt;
-  }
-
-  if (result_ok == false) {
-    int error_code;
-    ss >> error_code;
-
-    if (ss.fail()) {
-      return std::nullopt;
-    }
-
-    return InodeResult::makeFailure(inode, error_code);
-  } else if (result_ok == true) {
-    std::string rest_of_line;
-    ss >> rest_of_line;
-
-    // parse " string with potential spaces"
-    // into "string with potential spaces"
-    LeftTrim(/*inout*/rest_of_line);
-
-    if (ss.fail()) {
-      return std::nullopt;
-    }
-
-    const std::string& file_name = rest_of_line;
-
-    return InodeResult::makeSuccess(inode, file_name);
-  }
-
-  return std::nullopt;
-}
-
-struct OutOfProcessInodeResolver::Impl {
-  Impl() {
-  }
-
- private:
-  // Create the argv we will pass to the forked inode2filename, corresponds to #EmitAll.
-  std::vector<std::string> CreateArgvAll(const InodeResolverDependencies& deps) const {
-    std::vector<std::string> argv;
-    argv.push_back("--all");
-
-    return CreateArgv(deps, std::move(argv));
-  }
-
-  // Create the argv we will pass to the forked inode2filename, corresponds to
-  // #FindFilenamesFromInodes.
-  std::vector<std::string> CreateArgvFind(const InodeResolverDependencies& deps,
-                                          const std::vector<Inode>& inodes) const {
-    std::vector<std::string> argv;
-    iorap::common::AppendArgsRepeatedly(argv, inodes);
-
-    return CreateArgv(deps, std::move(argv));
-  }
-
-  std::vector<std::string> CreateArgv(const InodeResolverDependencies& deps,
-                                      std::vector<std::string> append_argv) const {
-    InodeResolverDependencies deps_oop = deps;
-    deps_oop.process_mode = ProcessMode::kInProcessDirect;
-
-    std::vector<std::string> argv = ToArgs(deps_oop);
-
-    argv.push_back("--output-format=ipc");
-
-    if (iorap::common::GetBoolEnvOrProperty("iorap.inode2filename.log.verbose", false)) {
-      argv.push_back("--verbose");
-    }
-
-    iorap::common::AppendArgsRepeatedly(argv, std::move(append_argv));
-
-    return argv;
-  }
-
- public:
-  // fork+exec into inode2filename with 'inodes' as the search list.
-  // Each result is parsed into a dest#on_next(result).
-  // If a fatal error occurs, dest#on_error is called once and no other callbacks are called.
-  void EmitFromCommandFind(rxcpp::subscriber<InodeResult>& dest,
-                           const InodeResolverDependencies& deps,
-                           const std::vector<Inode>& inodes) {
-    // Trivial case: complete immediately.
-    // Executing inode2filename with empty search list will just print the --help menu.
-    if (inodes.empty()) {
-      dest.on_completed();
-    }
-
-    std::vector<std::string> argv = CreateArgvFind(deps, inodes);
-    EmitFromCommandWithArgv(/*inout*/dest, std::move(argv), inodes.size());
-  }
-
-  // fork+exec into inode2filename with --all (listing *all* inodes).
-  // Each result is parsed into a dest#on_next(result).
-  // If a fatal error occurs, dest#on_error is called once and no other callbacks are called.
-  void EmitFromCommandAll(rxcpp::subscriber<InodeResult>& dest,
-                           const InodeResolverDependencies& deps) {
-    std::vector<std::string> argv = CreateArgvAll(deps);
-    EmitFromCommandWithArgv(/*inout*/dest, std::move(argv), /*result_count*/std::nullopt);
-  }
-
- private:
-  void EmitFromCommandWithArgv(rxcpp::subscriber<InodeResult>& dest,
-                               std::vector<std::string> argv_vec,
-                               std::optional<size_t> result_count) {
-    unique_fd pipe_reader, pipe_writer;
-    if (!::android::base::Pipe(/*out*/&pipe_reader, /*out*/&pipe_writer)) {
-      dest.on_error(
-          rxcpp::util::make_error_ptr(
-              IosBaseFailureWithErrno("Failed to create out-going pipe for inode2filename")));
-      return;
-    }
-
-    pid_t child = fork();
-    if (child == -1) {
-      dest.on_error(
-          rxcpp::util::make_error_ptr(
-              IosBaseFailureWithErrno("Failed to fork process for inode2filename")));
-      return;
-    } else if (child > 0) {  // we are the caller of this function
-      LOG(DEBUG) << "forked into a process for inode2filename , pid = " << child;
-    } else {
-      // we are the child that was forked
-
-      const char* kCommandFileName = GetCommandFileName();
-
-      std::stringstream argv; // for debugging.
-      for (std::string arg : argv_vec) {
-        argv  << arg << ' ';
-      }
-      LOG(DEBUG) << "fork+exec: " << kCommandFileName << " " << argv.str();
-
-      // Redirect only stdout. stdin is unused, stderr is same as parent.
-      if (dup2(pipe_writer.get(), STDOUT_FILENO) == -1) {
-        // Trying to call #on_error does not make sense here because we are in a forked process,
-        // the only thing we can do is crash definitively.
-        PLOG(FATAL) << "Failed to dup2 for inode2filename";
-      }
-
-      std::unique_ptr<const char *[]> argv_ptr =
-                common::VecToArgv(kCommandFileName, argv_vec);
-
-      if (execve(kCommandFileName,
-                 (char **)argv_ptr.get(),
-                 /*envp*/nullptr) == -1) {
-        // Trying to call #on_error does not make sense here because we are in a forked process,
-        // the only thing we can do is crash definitively.
-        PLOG(FATAL) << "Failed to execve process for inode2filename";
-      }
-      // This should never return.
-    }
-
-    // Immediately close the writer end of the pipe because we never use it.
-    pipe_writer.reset();
-
-    // Convert pipe(reader) file descriptor into FILE*.
-    std::unique_ptr<FILE, int(*)(FILE*)> file_reader{
-        ::android::base::Fdopen(std::move(pipe_reader), /*mode*/"r"), fclose};
-    if (!file_reader) {
-      dest.on_error(
-          rxcpp::util::make_error_ptr(
-              IosBaseFailureWithErrno("Failed to fdopen for inode2filename")));
-      return;
-    }
-
-    size_t actual_result_count = 0;
-
-    bool file_eof = false;
-    while (!file_eof) {
-      std::string inode2filename_line = ReadOneLine(file_reader.get(), /*out*/&file_eof);
-
-      if (inode2filename_line.empty()) {
-        if (!file_eof) {
-          // Ignore empty lines.
-          LOG(WARNING) << "inode2filename: got empty line";
-        }
-        continue;
-      }
-
-      LOG(DEBUG) << "inode2filename output-line: " << inode2filename_line;
-
-      std::optional<InodeResult> res = ParseFromLine(inode2filename_line);
-      if (!res) {
-        std::string error_msg = "Invalid output: ";
-        error_msg += inode2filename_line;
-        dest.on_error(
-            rxcpp::util::make_error_ptr(std::ios_base::failure(error_msg)));
-        return;
-      }
-      dest.on_next(*res);
-
-      ++actual_result_count;
-    }
-
-    LOG(DEBUG) << "inode2filename output-eof";
-
-    // Ensure that the # of inputs into the rx stream match the # of outputs.
-    // This is validating the post-condition of FindFilenamesFromInodes.
-    if (result_count && actual_result_count != *result_count) {
-      std::stringstream ss;
-      ss << "Invalid number of results, expected: " << *result_count;
-      ss << ", actual: " << actual_result_count;
-
-      dest.on_error(
-          rxcpp::util::make_error_ptr(std::ios_base::failure(ss.str())));
-      return;
-    }
-
-    CHECK(child > 0);  // we are in the parent process, parse the IPC output of inode2filename
-    dest.on_completed();
-  }
-};
-
-rxcpp::observable<InodeResult>
-    OutOfProcessInodeResolver::FindFilenamesFromInodes(std::vector<Inode> inodes) const {
-  return rxcpp::observable<>::create<InodeResult>(
-    [self=std::static_pointer_cast<const OutOfProcessInodeResolver>(shared_from_this()),
-     inodes=std::move(inodes)](
-        rxcpp::subscriber<InodeResult> s) {
-      self->impl_->EmitFromCommandFind(s, self->GetDependencies(), inodes);
-  });
-}
-
-rxcpp::observable<InodeResult>
-    OutOfProcessInodeResolver::EmitAll() const {
-  auto self = std::static_pointer_cast<const OutOfProcessInodeResolver>(shared_from_this());
-  CHECK(self != nullptr);
-  CHECK(self->impl_ != nullptr);
-
-  return rxcpp::observable<>::create<InodeResult>(
-    [self](rxcpp::subscriber<InodeResult> s) {
-      CHECK(self != nullptr);
-      CHECK(self->impl_ != nullptr);
-      self->impl_->EmitFromCommandAll(s, self->GetDependencies());
-  });
-}
-
-OutOfProcessInodeResolver::OutOfProcessInodeResolver(InodeResolverDependencies dependencies)
-  : InodeResolver{std::move(dependencies)}, impl_{new Impl{}} {
-}
-
-OutOfProcessInodeResolver::~OutOfProcessInodeResolver() {
-  // std::unique_ptr requires complete types, but we hide the definition in the header.
-  delete impl_;
-}
-
-}  // namespace iorap::inode2filename
diff --git a/src/inode2filename/out_of_process_inode_resolver.h b/src/inode2filename/out_of_process_inode_resolver.h
deleted file mode 100644
index d41e93f..0000000
--- a/src/inode2filename/out_of_process_inode_resolver.h
+++ /dev/null
@@ -1,53 +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.
-
-#ifndef IORAP_SRC_INODE2FILENAME_OUT_OF_PROCESS_INDOE_RESOLVER_H_
-#define IORAP_SRC_INODE2FILENAME_OUT_OF_PROCESS_INDOE_RESOLVER_H_
-
-#include "common/expected.h"
-#include "inode2filename/inode_resolver.h"
-
-namespace iorap::inode2filename {
-
-// Create an InodeResolver that fork+exec+pipes into the binary 'iorap.inode2filename'
-// and transmits the results back via an IPC mechanism.
-//
-// This is instantiated by InodeResolver::Create + ProcessMode::kOutOfProcessIpc
-class OutOfProcessInodeResolver : public InodeResolver {
- public:
-  virtual rxcpp::observable<InodeResult>
-      FindFilenamesFromInodes(std::vector<Inode> inodes) const override;
-
-  virtual rxcpp::observable<InodeResult>
-      EmitAll() const override;
-
-  OutOfProcessInodeResolver(InodeResolverDependencies dependencies);
-  ~OutOfProcessInodeResolver();
- private:
-  struct Impl;
-  Impl* impl_;
-};
-
-// Reads one line data from the stream.
-// Each line is in the format of "<4 bytes line length><state> <inode info> <file path>"
-// The <4 bytes line length> is the length rest data of "<state> <inode info> <file path>".
-// The return string is "<state> <inode info> <file path>".
-// For example: for "<size>K 253:9:6 ./test", the return value is
-// "K 253:9:6 ./test". The <size> is encoded in the first 4 bytes.
-// Note: there is no newline in the end of each line and the line shouldn't be
-// empty unless there is some error.
-std::string ReadOneLine(FILE* stream, bool* eof);
-}
-
-#endif  // IORAP_SRC_INODE2FILENAME_OUT_OF_PROCESS_INDOE_RESOLVER_H_
diff --git a/src/inode2filename/search_directories.cc b/src/inode2filename/search_directories.cc
deleted file mode 100644
index 1d31671..0000000
--- a/src/inode2filename/search_directories.cc
+++ /dev/null
@@ -1,1366 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "common/debug.h"
-#include "inode2filename/search_directories.h"
-#include "inode2filename/system_call.h"
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/scopeguard.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-
-#include "rxcpp/rx.hpp"
-
-#include <iostream>
-#include <stdio.h>
-#include <fstream>
-#include <vector>
-#include <optional>
-
-#include <signal.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-
-#ifdef __ANDROID__
-#include <sys/sysmacros.h>
-#endif
-
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <dirent.h>
-
-#include <unordered_map>
-
-namespace rx = rxcpp;
-using android::base::unique_fd;  // NOLINT
-using android::base::StringPrintf;  // NOLINT
-
-namespace iorap::inode2filename {
-
-#define DEBUG_INODE_SET 0
-
-// A multimap of 'ino_t -> List[Inode]' (where the value Inodes have the same ino_t as the key).
-//
-// A flat list of Inodes is turned into the above map, then keys can be removed one at a time
-// until the InodeSet eventually becomes empty.
-struct InodeSet {
-
-  InodeSet() = default;
-#if DEBUG_INODE_SET
-  InodeSet(const InodeSet& other) {
-    LOG(INFO) << "InodeSet-copyctor";
-    set_ = other.set_;
-  }
-
-  InodeSet(InodeSet&& other) {
-    LOG(INFO) << "InodeSet-movector";
-    set_ = std::move(other.set_);
-  }
-
-  InodeSet& operator=(const InodeSet& other) {
-    LOG(INFO) << "InodeSet-opassign-copy";
-    set_ = other.set_;
-    return *this;
-  }
-
-  InodeSet& operator=(InodeSet&& other) {
-    LOG(INFO) << "InodeSet-opassign-move";
-    set_ = std::move(other.set_);
-    return *this;
-  }
-#else
-  InodeSet(InodeSet&& other) = default;
-  InodeSet& operator=(InodeSet&& other) = default;
-  // Copying InodeSet can be very expensive, refuse to even allow compiling such code.
-  InodeSet(const InodeSet& other) = delete;
-  InodeSet& operator=(const InodeSet& other) = delete;
-#endif
-
-  struct ValueRange {
-    auto/*Iterable<Inode>*/ begin() {
-      return begin_;
-    }
-
-    auto/*Iterable<Inode>*/ end() {
-      return end_;
-    }
-
-    bool empty() const {
-      return begin_ == end_;
-    }
-
-    explicit operator bool() const {
-      return !empty();
-    }
-
-    std::unordered_multimap<ino_t, Inode>::iterator begin_, end_;
-
-    friend std::ostream& operator<<(std::ostream& os, const ValueRange& s);
-  };
-
-  // Create an observable that emits the remaining inodes in the map.
-  //
-  // Mutation functions must not be called until this observable
-  // has been finished emitting all values (e.g. with on_completed) since that
-  // would cause the underlying iterators to go into an undefined state.
-  auto/*observable<Inode>*/ IterateValues() const {
-    return rxcpp::observable<>::iterate(set_).map(  // XX: should we use identity_immediate here?
-        [](const std::pair<const ino_t, Inode>& pair) {
-          return pair.second;
-        }
-    );
-    // TODO: this would be more efficient as a range-v3 view.
-  }
-
-  constexpr bool Empty() const {
-    return set_.empty();
-  }
-
-  static InodeSet OfList(const std::vector<Inode>& list) {
-    InodeSet new_inode_set;
-    std::unordered_multimap<ino_t, Inode>* map = &new_inode_set.set_;
-
-    for (const Inode& inode : list) {
-      map->insert({inode.inode, inode});
-    }
-
-    return new_inode_set;
-  }
-
-  // Return an optional list of 'Inode' structs whose 'inode' field matches the 'inode' parameter.
-  // Returns an empty range if there was nothing found.
-  ValueRange FindInodeList(ino_t inode) {
-    auto range = set_.equal_range(inode);
-    return ValueRange{range.first, range.second};
-  }
-
-  // Match all fields of an Inode against a 'struct stat' stat_buf.
-  //
-  // The returned Inode (if any) is removed from the InodeSet; it will not be returned by
-  // FindInodeList in future calls.
-  std::optional<Inode> FindAndRemoveInodeInList(ValueRange inode_list,
-                                                const struct stat& stat_buf) {
-    LOG(VERBOSE) << "FindAndRemoveInodeInList " << inode_list << ", "
-                 << "stat_buf{st_dev=" << stat_buf.st_dev << ",st_ino=" << stat_buf.st_ino << "}";
-
-    auto /*iterator*/ found = std::find_if(inode_list.begin(),
-                                           inode_list.end(),
-                                           [&](const std::pair<ino_t, Inode>& pair) {
-      const Inode& inode = pair.second;
-      if (inode.inode != stat_buf.st_ino) {
-        return false;
-      }
-
-      dev_t inode_dev =
-          makedev(static_cast<int>(inode.device_major), static_cast<int>(inode.device_minor));
-
-      // Inodes could be the same across different devices.
-      // Also match the device id.
-      if (inode_dev != stat_buf.st_dev) {
-        LOG(VERBOSE) << "InodeSet:FindAndRemoveInodeInList matched ino: " << inode.inode
-                     << " but not device"
-                     << ", expected dev: " << stat_buf.st_dev
-                     << ", actual dev: " << inode_dev;
-        return false;
-      }
-      return true;
-    });
-
-    if (found != inode_list.end()) {
-      Inode inode = found->second;
-      LOG(VERBOSE) << "InodeSet:FindAndRemoveInodeInList *success* inode+device " << inode;
-      DCHECK(found->second.inode == stat_buf.st_ino);
-      // Erase the inode from the list. This is important.
-      set_.erase(found);
-      return inode;
-    }
-
-    return std::nullopt;
-  }
-
-  // Match all fields of an Inode against another Inode.
-  //
-  // The returned Inode (if any) is removed from the InodeSet; it will not be returned by
-  // FindInodeList in future calls.
-  std::optional<Inode> FindAndRemoveInodeInList(ValueRange inode_list,
-                                                const Inode& inode) {
-    LOG(VERBOSE) << "FindAndRemoveInodeInList " << inode_list << ", "
-                 << inode << "}";
-
-    auto /*iterator*/ found = std::find_if(inode_list.begin(),
-                                           inode_list.end(),
-                                           [&](const std::pair<ino_t, Inode>& pair) {
-      return inode == pair.second;
-    });
-
-    if (found != inode_list.end()) {
-      Inode inode = found->second;
-      LOG(VERBOSE) << "InodeSet:FindAndRemoveInodeInList *success* inode+device " << inode;
-      DCHECK_EQ(found->second, inode);
-      // Erase the inode from the list. This is important.
-      set_.erase(found);
-      return inode;
-    }
-
-    return std::nullopt;
-  }
-
-  // TODO: equality and string operators for testing/logging.
- private:
-  // Explanation: readdir returns a 'file' -> 'ino_t inode' mapping.
-  //
-  // However inodes can be reused on different partitions (but they have a different device number).
-  // To handle this edge case, and to avoid calling stat whenever the inode definitely doesn't match
-  // store the inodes into a single-key,multi-value container.
-  //
-  // This enables fast scanning of readdir results by matching just the 'inode' portion,
-  // then calling stat only when the inode portion definitely matches to confirm the device.
-
-  // There are no single-key multi-value containers in standard C++, so pretend
-  // we have one by writing this simple facade around an unordered set.
-  //
-  // We expect that the vector size is usually size=1 (or 2 or 3) since the # of devices
-  // is fixed by however many partitions there are on the system, AND the same inode #
-  // would have to be reused across a different file.
-  std::unordered_multimap<ino_t, Inode> set_;  // TODO: Rename to map_.
-
-  friend std::ostream& operator<<(std::ostream& os, const InodeSet& s);
-};
-
-std::ostream& operator<<(std::ostream& os, const InodeSet& s) {
-  os << "InodeSet{";
-  for (const auto& kv : s.set_) {
-    // e.g. "123=>(1:2:123)" ... its expected for the 'ino_t' portion to be repeated.
-    os << "" << kv.first << "=>(" << kv.second << "),";
-  }
-  os << "}";
-  return os;
-}
-
-std::ostream& operator<<(std::ostream& os, const InodeSet::ValueRange& v) {
-  // Don't want to make a const and non const version of ValueRange.
-  InodeSet::ValueRange& s = const_cast<InodeSet::ValueRange&>(v);
-
-  os << "InodeSet::ValueRange{";
-  for (const auto& kv : s) {
-    // e.g. "123=>(1:2:123)" ... its expected for the 'ino_t' portion to be repeated.
-    os << "" << kv.first << "=>(" << kv.second << "),";
-  }
-  os << "}";
-  return os;
-}
-
-void search_for_inodes_in(std::vector<Inode>& inode_list, const std::string& dirpath);
-
-enum DirectoryEntryErrorCode {
-  kInvalid,    // not a real error code. to detect bad initialization.
-  kOpenDir,    // opendir failed.
-  kReadDir,    // readdir failed.
-  kDtUnknown,  // d_type was DT_UNKNOWN error.
-};
-
-struct DirectoryEntryError {
-  DirectoryEntryErrorCode code;
-  int err_no;
-  std::string filename;
-};
-
-std::ostream& operator<<(std::ostream& os, const DirectoryEntryError& e) {
-  os << "DirectoryEntryError{"
-     << static_cast<int>(e.code) << "," << e.err_no << "," << e.filename << "}";
-  return os;
-  // TODO: pretty-print code and err-no
-}
-
-static common::DebugCounter gDebugDirectoryEntryCounter{};
-static constexpr bool kDebugDirectoryEntry = false;
-
-#define DIRECTORY_ENTRY_MOVE_DCHECK() \
-    DCHECK_EQ(other.moved_from_, false) << __PRETTY_FUNCTION__ << "CNT:" << other.debug_counter_;
-#define DIRECTORY_ENTRY_TRACE_CTOR() \
-    if (kDebugDirectoryEntry) LOG(VERBOSE) << __PRETTY_FUNCTION__ << "@CNT:" << debug_counter_
-
-struct DirectoryEntry {
-  using ResultT = iorap::expected<DirectoryEntry, DirectoryEntryError>;
-  using ObservableT = rx::observable<ResultT>;
-
-  static constexpr ino_t kInvalidIno = std::numeric_limits<ino_t>::max();
-  static constexpr auto kInvalidFileName = "";
-
-  // Path to file, the prefix is one of the root directories.
-  std::string filename{kInvalidFileName};
-  // Inode number of the file. Not unique across different devices.
-  ino_t d_ino{kInvalidIno};
-  // File type (DT_LNK, DT_REG, DT_DIR, or DT_UNKNOWN)
-  unsigned char d_type{DT_UNKNOWN};  // Note: not seen outside of sentinel roots.
-  // TODO: Consider invariant checks for valid combinations of above fields?
-
-  // Debug-only flags.
-  bool moved_from_{false};
-  size_t debug_counter_{0};
-
- private:
-  // TODO: remove default constructor?
-  //
-  // SEEMS TO BE USED by std::vector etc. FIX DAT.
-  DirectoryEntry() noexcept {
-    debug_counter_ = gDebugDirectoryEntryCounter++;
-    DIRECTORY_ENTRY_TRACE_CTOR();
-  }
- public:
-  DirectoryEntry(std::string filename, ino_t d_ino, unsigned char d_type) noexcept
-    : filename{std::move(filename)},
-      d_ino{d_ino},
-      d_type{d_type} {
-    debug_counter_ = gDebugDirectoryEntryCounter++;
-    DIRECTORY_ENTRY_TRACE_CTOR();
-  }
-
-  DirectoryEntry(const DirectoryEntry& other) noexcept {
-    // Do not use member-initialization syntax so that this DCHECK can execute first.
-    DIRECTORY_ENTRY_MOVE_DCHECK();
-
-    filename = other.filename;
-    d_ino = other.d_ino;
-    d_type = other.d_type;
-    children_paths_ = other.children_paths_;
-    children_initialized_ = other.children_initialized_;
-    debug_counter_ = other.debug_counter_;
-    DIRECTORY_ENTRY_TRACE_CTOR();
-  }
-
-  DirectoryEntry& operator=(const DirectoryEntry& other) noexcept {
-    if (this == &other) {
-      return *this;
-    }
-
-    DIRECTORY_ENTRY_MOVE_DCHECK();
-
-    filename = other.filename;
-    d_ino = other.d_ino;
-    d_type = other.d_type;
-    children_paths_ = other.children_paths_;
-    children_initialized_ = other.children_initialized_;
-    debug_counter_ = other.debug_counter_;
-    DIRECTORY_ENTRY_TRACE_CTOR();
-
-    return *this;
-  }
-
-  DirectoryEntry& operator=(DirectoryEntry&& other) noexcept {
-    if (this == &other) {
-      return *this;
-    }
-
-    DIRECTORY_ENTRY_MOVE_DCHECK();
-
-    filename = std::move(other.filename);
-    d_ino = other.d_ino;
-    d_type = other.d_type;
-    children_paths_ = std::move(other.children_paths_);
-    children_initialized_ = other.children_initialized_;
-    debug_counter_ = other.debug_counter_;
-    DIRECTORY_ENTRY_TRACE_CTOR();
-
-    return *this;
-  }
-
-  DirectoryEntry(DirectoryEntry&& other) noexcept {
-    DIRECTORY_ENTRY_MOVE_DCHECK();
-    other.moved_from_ = true;
-
-    filename = std::move(other.filename);
-    d_ino = other.d_ino;
-    d_type = other.d_type;
-    children_paths_ = std::move(other.children_paths_);
-    children_initialized_ = other.children_initialized_;
-    debug_counter_ = other.debug_counter_;
-    DIRECTORY_ENTRY_TRACE_CTOR();
-  }
-
-  // Create a sentinel (root of roots) whose children entries are those specified by
-  // children_paths.
-  static DirectoryEntry CreateSentinel(std::vector<std::string> children_paths) {
-    DirectoryEntry e;
-    e.d_type = DT_DIR;
-    ++gDebugDirectoryEntryCounter;
-
-    for (std::string& child_path : children_paths) {
-      // TODO: Should we call Stat on the child path here to reconstitute the ino_t for a root dir?
-      // Otherwise it can look a little strange (i.e. the root dir itself will never match
-      // the searched inode).
-      //
-      // Probably not too big of a problem in practice.
-      DirectoryEntry child_entry{std::move(child_path), kInvalidIno, DT_DIR};
-      ResultT child_entry_as_result{std::move(child_entry)};
-      e.children_paths_.push_back(std::move(child_entry_as_result));
-    }
-
-    e.children_initialized_ = true;
-
-    return e;
-  }
-
-  // Return an observable which emits the direct children only.
-  // The children entries are now read from disk (with readdir) if they weren't read previously.
-  std::vector<ResultT> GetChildrenEntries(borrowed<SystemCall*> system_call) const& {
-    BuildChildrenPaths(system_call);
-    return children_paths_;
-  }
-
-  // Return an observable which emits the direct children only.
-  // The children entries are now read from disk (with readdir) if they weren't read previously.
-  // Movable overload.
-  std::vector<ResultT> GetChildrenEntries(borrowed<SystemCall*> system_call) && {
-    BuildChildrenPaths(system_call);
-    return std::move(children_paths_);
-  }
-
-  // Returns a (lazy) observable that emits every single node, in pre-order,
-  // rooted at this tree.
-  //
-  // New entries are only read from disk (with e.g. readdir) when more values are pulled
-  // from the observable. Only the direct children of any entry are read at any time.
-  //
-  // The emission can be stopped prematurely by unsubscribing from the observable.
-  // This means the maximum amount of 'redundant' IO reads is bounded by the children count
-  // of all entries emitted thus far minus entries actually emitted.
-  ObservableT GetSubTreePreOrderEntries(borrowed<SystemCall*> system_call) const;
-
- private:
-  // Out-of-line definition to avoid circular type dependency.
-  void BuildChildrenPaths(borrowed<SystemCall*> system_call) const;
-
-  // We need to lazily initialize children_paths_ only when we try to read them.
-  //
-  // Assuming the underlying file system doesn't change (which isn't strictly true),
-  // the directory children are referentially transparent.
-  //
-  // In practice we do not need to distinguish between the file contents changing out
-  // from under us in this code, so we don't need the more strict requirements.
-  mutable std::vector<ResultT> children_paths_;
-  mutable bool children_initialized_{false};
-
-  friend std::ostream& operator<<(std::ostream& os, const DirectoryEntry& d);
-};
-
-std::ostream& operator<<(std::ostream& os, const DirectoryEntry& d) {
-  os << "DirectoryEntry{" << d.filename << ",ino:" << d.d_ino << ",type:" << d.d_type << "}";
-  return os;
-}
-
-using DirectoryEntryResult = DirectoryEntry::ResultT;
-
-// Read all directory entries and return it as a vector. This must be an eager operation,
-// as readdir is not re-entrant.
-//
-// This could be considered as a limitation from the 'observable' perspective since
-// one can end up reading unnecessary extra directory entries that are then never consumed.
-//
-// The following entries are skipped:
-//  - '.' self
-//  - ".." parent
-//
-// All DT types except the following are removed:
-//  * DT_LNK - symbolic link (empty children)
-//  * DT_REG - regular file  (empty children)
-//  * DT_DIR - directory     (has children)
-static std::vector<DirectoryEntryResult>
-    ReadDirectoryEntriesFromDirectoryPath(std::string dirpath, borrowed<SystemCall*> system_call) {
-  DIR *dirp;
-  struct dirent *dp;
-
-  LOG(VERBOSE) << "ReadDirectoryEntriesFromDirectoryPath(" << dirpath << ")";
-
-  if ((dirp = system_call->opendir(dirpath.c_str())) == nullptr) {
-    PLOG(ERROR) << "Couldn't open directory: " << dirpath;
-    return {DirectoryEntryError{kOpenDir, errno, dirpath}};
-  }
-
-  // Read all the results up front because readdir is not re-entrant.
-  std::vector<DirectoryEntryResult> results;
-
-  // Get full path + the directory entry path.
-  auto child_path = [&] { return dirpath + "/" + dp->d_name; };
-
-  do {
-    errno = 0;
-    if ((dp = system_call->readdir(dirp)) != nullptr) {
-      if (dp->d_type == DT_DIR) {
-        if (strcmp(".", dp->d_name) == 0 || strcmp("..", dp->d_name) == 0) {
-          LOG(VERBOSE) << "Skip self/parent: " << dp->d_name;
-          continue;
-        }
-
-        LOG(VERBOSE) << "Find entry " << child_path()
-                     << ", ino: " << dp->d_ino << ", type: " << dp->d_type;
-        results.push_back(DirectoryEntry{child_path(),
-                                         static_cast<ino_t>(dp->d_ino),
-                                         dp->d_type});
-      } else if (dp->d_type == DT_UNKNOWN) {
-        // This seems bad if it happens. We should probably do something about this.
-        LOG(WARNING) << "Found unknown DT entry: " << child_path();
-
-        results.push_back(DirectoryEntryError{kDtUnknown, /*errno*/0, child_path()});
-      } else if (dp->d_type == DT_LNK || dp->d_type == DT_REG) {
-        // Regular non-directory file entry.
-        results.push_back(DirectoryEntry{child_path(),
-                                         static_cast<ino_t>(dp->d_ino),
-                                         dp->d_type});
-      } else {
-        // Block device, character device, socket, etc...
-        LOG(VERBOSE) << "Skip DT entry of type: " << dp->d_type << " " << child_path();
-      }
-    } else if (errno != 0) {
-      PLOG(ERROR) << "Error reading directory entry in " << dirpath;
-
-      results.push_back(DirectoryEntryError{kReadDir, errno, dirpath});
-    }
-  } while (dp != nullptr);
-
-  if (system_call->closedir(dirp) < 0) {
-    PLOG(ERROR) << "Failed to close directory " << dirpath;
-  }
-
-  return results;
-}
-
-void DirectoryEntry::BuildChildrenPaths(borrowed<SystemCall*> system_call) const {
-  if (children_initialized_) {
-    return;
-  }
-
-  if (d_type == DT_DIR) {
-    children_paths_ = ReadDirectoryEntriesFromDirectoryPath(filename, system_call);
-    // TODO: consider using dependency injection here to substitute this function during testing?
-  }
-}
-
-struct InodeSearchParameters {
-  std::vector<Inode> inode_list;
-  std::vector<std::string> root_dirs;
-};
-
-// [IN]
-// observable: expected<Value, Error>, ...
-// [OUT]
-// observable: Value, ...
-//
-// Any encountered 'Error' items are dropped after logging.
-template <typename T>
-auto MapExpectedOrLog(T&& observable,
-                      ::android::base::LogSeverity log_level) {
-  return observable.filter([log_level](const auto& result) {
-    if (result) {
-      return true;
-    } else {
-      LOG(log_level) << result.error();
-      return false;
-    }
-  }).map([](auto&& result) {
-    return IORAP_FORWARD_LAMBDA(result).value();
-  });
-}
-
-template <typename T>
-auto MapExpectedOrLogError(T&& observable) {
-  return MapExpectedOrLog(std::forward<T>(observable), ::android::base::ERROR);
-}
-
-template <typename T>
-auto MapOptionalOrDrop(T&& observable) {
-  return observable.filter([](const auto& result) {
-    return result.has_value();
-  }).map([](auto&& result) {
-    return IORAP_FORWARD_LAMBDA(result).value();
-  });
-  // TODO: static_assert this isn't used with an unexpected.
-}
-
-template <typename T, typename F>
-auto VisitValueOrLogError(T&& expected, F&& visit_func, const char* error_prefix = "") {
-  if (!expected) {
-    LOG(ERROR) << error_prefix << " " << expected.error();
-  } else {
-    visit_func(std::forward<T>(expected).value());
-  }
-  // TODO: Could be good to make this more monadic by returning an optional.
-}
-
-template <typename TSimple, typename T, typename F>
-void TreeTraversalPreOrderObservableImpl(rx::subscriber<TSimple> dest, T&& node, F&& fn) {
-  LOG(VERBOSE) << "TreeTraversalPreOrderObservableImpl (begin) " << __PRETTY_FUNCTION__;
-
-  if (!dest.is_subscribed()) {
-    LOG(VERBOSE) << "TreeTraversalPreOrderObservableImpl (unsubscribed)";
-    return;
-  } else {
-    LOG(VERBOSE) << "TreeTraversalPreOrderObservableImpl (on_next node)";
-
-    // Copy the node here. This is less bad than it seems since we haven't yet
-    // calculated its children (except in the root), so its just doing a shallow memcpy (sizeof(T)).
-    //
-    // This assumes the children are calculated lazily, otherwise we'd need to have a separate
-    // NodeBody class which only holds the non-children elements.
-
-    TSimple copy = std::forward<T>(node);
-    dest.on_next(std::move(copy));
-
-    if (!node.has_value()) {
-      return;
-    }
-
-    // Whenever we call 'on_next' also check if we end up unsubscribing.
-    // This avoids the expensive call into the children.
-    if (!dest.is_subscribed()) {
-      LOG(VERBOSE) << "TreeTraversalPreOrderObservableImpl (post-self unsubscribe)";
-      return;
-    }
-
-    // Eagerly get the childrem, moving them instead of copying them.
-    auto&& children = fn(std::forward<T>(node));
-    for (auto&& child : children) {
-      TreeTraversalPreOrderObservableImpl(dest, IORAP_FORWARD_LAMBDA(child), fn);
-      // TODO: double check this is doing the std::move properly for rvalues.
-
-      if (!dest.is_subscribed()) {
-        LOG(VERBOSE) << "TreeTraversalPreOrderObservableImpl (unsubscribed in children)";
-        break;
-      }
-    };
-  }
-}
-
-// Creates an observable over all the nodes in the tree rooted at node.
-// fn is a function that returns the children of that node.
-//
-// The items are emitted left-to-right pre-order, and stop early if the
-// observable is unsubscribed from.
-//
-// Implementation requirement:
-//    typeof(node) -> expected<V, E> or optional<V> or similar.
-//    fn(node) -> iterable<typeof(node)>
-//
-// preorder(self):
-//   visit(self)
-//   for child in fn(self):
-//     preorder(child)
-template <typename T, typename F>
-auto/*observable<T>*/ TreeTraversalPreOrderObservable(T&& node, F&& fn) {
-  LOG(VERBOSE) << "TreeTraversalPreOrderObservable: " << __PRETTY_FUNCTION__;
-
-  using T_simple = std::decay_t<T>;
-  return rx::observable<>::create<T_simple>(
-    // Copy node to avoid lifetime issues.
-    [node=node,fn=std::forward<F>(fn)](rx::subscriber<T_simple> dest) {
-      LOG(VERBOSE) << "TreeTraversalPreOrderObservable (lambda)";
-      TreeTraversalPreOrderObservableImpl<T_simple>(dest,
-                                                    std::move(node),
-                                                    std::move(fn));
-      dest.on_completed();
-    }
-  );
-}
-
-DirectoryEntry::ObservableT
-    DirectoryEntry::GetSubTreePreOrderEntries(borrowed<SystemCall*> system_call) const {
-  return TreeTraversalPreOrderObservable(
-      DirectoryEntryResult{*this},
-      [system_call=system_call](auto/*DirectoryEntryResult*/&& result)
-          -> std::vector<DirectoryEntryResult> {
-        if (!result) {
-          LOG(VERBOSE) << "GetSubTreePreOrderEntries (no value return)";
-          // Cannot have children when it was an error.
-          return {};
-        }
-        return
-            IORAP_FORWARD_LAMBDA(result)
-            .value()
-            .GetChildrenEntries(system_call);
-      });
-}
-
-struct StatError {
-  int err_no;
-  std::string path_name;
-};
-
-std::ostream& operator<<(std::ostream& os, const StatError& e) {
-  os << "StatError{" << e.err_no << "," << e.path_name
-     << ": " << strerror(e.err_no) << "}";
-  return os;
-}
-
-template <typename U = void>  // suppress unused warning.
-static iorap::expected<struct stat, StatError> Stat(const std::string& path_name,
-                                                    borrowed<SystemCall*> system_call) {
-  struct stat statbuf{};
-
-  // Call stat(2) in live code. Overridden in test code.
-  if (system_call->stat(path_name.c_str(), /*out*/&statbuf) == 0) {
-    return statbuf;
-  } else {
-    return iorap::unexpected(StatError{errno, path_name});
-  }
-}
-
-using StatResult = iorap::expected<struct stat, StatError>;
-
-// An inode's corresponding filename on the system.
-struct SearchMatch {
-  Inode inode;
-  // Relative path joined with a root directory.
-  //
-  // Use absolute path root dirs to get back absolute path filenames.
-  // If relative, this is relative to the current working directory.
-  std::string filename;
-};
-
-std::ostream& operator<<(std::ostream& os, const SearchMatch& s) {
-  os << "SearchMatch{" << s.inode << ", " << s.filename << "}";
-  return os;
-}
-
-struct SearchState {
-  // Emit 'match' Inodes corresponding to the ones here.
-  InodeSet inode_set;
-
-  // An inode matching one of the ones in inode_set was discovered in the most-recently
-  // emitted SearchState.
-  //
-  // The InodeSet removes any matching 'Inode'.
-  std::optional<SearchMatch> match;
-
-  SearchState() = default;
-  SearchState(SearchState&& other) = default;
-
-  // Do not copy this because copying InodeSet is excruciatingly slow.
-  SearchState(const SearchState& other) = delete;
-
-  // TODO: make sure this doesn't copy [inodes], as that would be unnecessarily expensive.
-};
-
-std::ostream& operator<<(std::ostream& os, const SearchState& s) {
-  os << "SearchState{match:";
-  // Print the 'match' first. The InodeSet could be very large so it could be truncated in logs.
-  if (s.match) {
-    os << s.match.value();
-  } else {
-    os << "(none)";
-  }
-  os << ", inode_set:" << s.inode_set << "}";
-  return os;
-}
-
-// TODO: write operator<< etc.
-
-// Return a lazy observable that will search for all filenames whose inodes
-// match the inodes in inode_search_list.
-//
-// Every unmatched inode will be emitted as an unexpected at the end of the stream.
-auto/*[observable<InodeResult>, connectable]*/ SearchDirectoriesForMatchingInodes(
-    std::vector<std::string> root_dirs,
-    std::vector<Inode> inode_search_list,
-    borrowed<SystemCall*> system_call) {
-
-  // Create a (lazy) observable that will emit each DirectoryEntry that is a recursive subchild
-  // of root_dirs. Emission will be stopped when its unsubscribed from.
-  //
-  // This is done by calling readdir(3) lazily.
-  auto/*obs<DirectoryEntry>*/ find_all_subdir_entries = ([&]() {
-    DirectoryEntry sentinel = DirectoryEntry::CreateSentinel(std::move(root_dirs));
-    auto/*obs<DirectoryEntryResult*/ results = sentinel.GetSubTreePreOrderEntries(system_call);
-
-    // Drop any errors by logging them to logcat. "Unwrap" the expected into the underlying data.
-    auto/*obs<DirectoryEntry*>*/ expected_drop_errors = MapExpectedOrLogError(std::move(results));
-    return expected_drop_errors;
-  })();
-
-  // DirectoryEntry is missing the dev_t portion, so we may need to call scan(2) again
-  // to confirm the dev_t. We skip calling scan(2) when the ino_t does not match.
-  // InodeSet lets us optimally avoid calling scan(2).
-  std::shared_ptr<SearchState> initial = std::make_shared<SearchState>();
-  initial->inode_set = InodeSet::OfList(inode_search_list);
-
-  auto/*[observable<SearchState>,Connectable]*/ search_state_results = find_all_subdir_entries.scan(
-      std::move(initial),
-      [system_call=system_call](std::shared_ptr<SearchState> search_state,
-                                const DirectoryEntry& dir_entry) {
-        LOG(VERBOSE) << "SearchDirectoriesForMatchingInodes#Scan "
-                     << dir_entry << ", state: " << *search_state;
-
-        search_state->match = std::nullopt;
-
-        InodeSet* inodes = &search_state->inode_set;
-
-        // Find all the possible inodes across different devices.
-        InodeSet::ValueRange inode_list = inodes->FindInodeList(dir_entry.d_ino);
-
-        // This directory doesn't correspond to any inodes we are searching for.
-        if (!inode_list) {
-          return search_state;
-        }
-
-        StatResult maybe_stat = Stat(dir_entry.filename, system_call);
-        VisitValueOrLogError(maybe_stat, [&](const struct stat& stat_buf) {
-          // Try to match the specific inode. Usually this will not result in a match (nullopt).
-          std::optional<Inode> inode = inodes->FindAndRemoveInodeInList(inode_list, stat_buf);
-
-          if (inode) {
-            search_state->match = SearchMatch{inode.value(), dir_entry.filename};
-          }
-        });
-
-        return search_state;
-      }
-  // Avoid exhausting a potentially 'infinite' stream of files by terminating as soon
-  // as we find every single inode we care about.
-  ).take_while([](std::shared_ptr<SearchState> state) {
-      // Also emit the last item that caused the search set to go empty.
-      bool cond = !state->inode_set.Empty() || state->match;
-
-      if (WOULD_LOG(VERBOSE)) {
-        static int kCounter = 0;
-        LOG(VERBOSE) << "SearchDirectoriesForMatchingInodes#take_while (" << kCounter++ <<
-                     ",is_empty:"
-                     << state->inode_set.Empty() << ", match:" << state->match.has_value();
-      }
-      // Minor O(1) implementation inefficiency:
-      // (Too minor to fix but it can be strange if looking at the logs or readdir traces).
-      //
-      // Note, because we return 'true' after the search set went empty,
-      // the overall stream graph still pulls from search_state_results exactly once more:
-      //
-      // This means that for cond to go to false, we would've read one extra item and then discarded
-      // it. If that item was the first child of a directory, that means we essentially did
-      // one redundant pass of doing a readdir.
-      // In other words if the search set goes to empty while the current item is a directory,
-      //
-      // it will definitely readdir on it at least once as we try to get the first child in
-      // OnTreeTraversal.
-      //
-      // This could be fixed with a 'take_until(Predicate)' operator which doesn't discard
-      // the last item when the condition becomes false. However rxcpp seems to lack this operator,
-      // whereas RxJava has it.
-
-      if (!cond) {
-        LOG(VERBOSE) << "SearchDirectoriesForMatchingInodes#take_while "
-                     << "should now terminate for " << *state;
-      }
-
-      return cond;
-  }).publish();
-  // The publish here is mandatory. The stream is consumed twice (once by matched and once by
-  // unmatched streams). Without the publish, once all items from 'matched' were consumed it would
-  // start another instance of 'search_state_results' (i.e. it appears as if the search
-  // is restarted).
-  //
-  // By using 'publish', the search_state_results is effectively shared by both downstream nodes.
-  // Note that this also requires the subscriber to additionally call #connect on the above stream,
-  // otherwise no work will happen.
-
-  // Lifetime notes:
-  //
-  // The the 'SearchState' is emitted into both below streams simultaneously.
-  //    The 'unmatched_inode_values' only touches the inode_set.
-  //    The 'matched_inode_values' only touches the match.
-  // Either stream can 'std::move' from those fields because they don't move each other's fields.
-  auto/*observable<InodeResult>*/ matched_inode_values = search_state_results
-      .filter([](std::shared_ptr<SearchState> search_state) {
-                  return search_state->match.has_value(); })
-      .map([](std::shared_ptr<SearchState> search_state) {
-                  return std::move(search_state->match.value()); })
-                     // observable<SearchMatch>
-      .map([](SearchMatch search_match) {
-          return InodeResult::makeSuccess(search_match.inode, std::move(search_match.filename));
-      });            // observable<InodeResult>
-
-  auto/*observable<?>*/ unmatched_inode_values = search_state_results
-      // The 'last' SearchState is the one that contains all the remaining inodes.
-      .take_last(1)  // observable<SearchState>
-      .flat_map([](std::shared_ptr<SearchState> search_state) {
-          LOG(VERBOSE) << "SearchDirectoriesForMatchingInodes#unmatched -- flat_map";
-          // Aside: Could've used a move here if the inodes weren't so lightweight already.
-          return search_state->inode_set.IterateValues(); })
-                     // observable<Inode>
-      .map([](const Inode& inode) {
-          LOG(VERBOSE) << "SearchDirectoriesForMatchingInodes#unmatched -- map";
-          return InodeResult::makeFailure(inode, InodeResult::kCouldNotFindFilename);
-      });
-                     // observable<InodeResult>
-
-  // The matched and unmatched InodeResults are emitted together.
-  //   Use merge, not concat, because we need both observables to be subscribed to simultaneously.
-
-  auto/*observable<InodeResult*/ all_inode_results =
-      matched_inode_values.merge(unmatched_inode_values);
-
-  // Now that all mid-stream observables have been connected, turn the Connectable observable
-  // into a regular observable.
-
-  // The caller has to call 'connect' on the search_state_results after subscribing
-  // and before any work can actually start.
-  return std::make_pair(all_inode_results, search_state_results);
-}
-
-rxcpp::observable<InodeResult> SearchDirectories::FindFilenamesFromInodes(
-    std::vector<std::string> root_directories,
-    std::vector<Inode> inode_list,
-    SearchMode mode) const {
-  DCHECK(mode == SearchMode::kInProcessDirect) << " other modes not implemented yet";
-
-  auto/*observable[2]*/ [inode_results, connectable] = SearchDirectoriesForMatchingInodes(
-      std::move(root_directories),
-      std::move(inode_list),
-      system_call_);
-
-  return inode_results.ref_count(connectable);
-}
-
-// I think we could avoid this with auto_connect, which rxcpp doesn't seem to have.
-//
-// I can't figure out any other way to avoid this, or at least to allow connecting
-// on the primary observable (instead of a secondary side-observable).
-//
-// If using the obvious publish+ref_count then the unmerged stream gets no items emitted into it.
-// If tried to ref_count later, everything turns into no-op.
-// If trying to call connect too early, the subscribe is missed.
-template <typename T>
-struct RxAnyConnectableFromObservable : public SearchDirectories::RxAnyConnectable {
-  virtual void connect() override {
-    observable.connect();
-  }
-
-  virtual ~RxAnyConnectableFromObservable() {}
-
-  RxAnyConnectableFromObservable(rxcpp::connectable_observable<T> observable)
-    : observable(observable) {
-  }
-
-  rxcpp::connectable_observable<T> observable;
-};
-
-// Type deduction helper.
-template <typename T>
-std::unique_ptr<SearchDirectories::RxAnyConnectable>
-    MakeRxAnyConnectableFromObservable(rxcpp::connectable_observable<T> observable) {
-  SearchDirectories::RxAnyConnectable* ptr = new RxAnyConnectableFromObservable<T>{observable};
-  return std::unique_ptr<SearchDirectories::RxAnyConnectable>{ptr};
-}
-
-std::pair<rxcpp::observable<InodeResult>, std::unique_ptr<SearchDirectories::RxAnyConnectable>>
-    SearchDirectories::FindFilenamesFromInodesPair(
-        std::vector<std::string> root_directories,
-        std::vector<Inode> inode_list,
-        SearchMode mode) const {
-  DCHECK(mode == SearchMode::kInProcessDirect) << " other modes not implemented yet";
-
-  auto/*observable[2]*/ [inode_results, connectable] = SearchDirectoriesForMatchingInodes(
-      std::move(root_directories),
-      std::move(inode_list),
-      system_call_);
-
-  std::unique_ptr<SearchDirectories::RxAnyConnectable> connectable_ptr =
-    MakeRxAnyConnectableFromObservable(connectable.as_dynamic());
-
-  return {inode_results, std::move(connectable_ptr)};
-}
-
-rxcpp::observable<InodeResult>
-    SearchDirectories::FindFilenamesFromInodes(std::vector<std::string> root_directories,
-                                               rxcpp::observable<Inode> inodes,
-                                               SearchMode mode) const {
-
-  // It's inefficient to search for inodes until the full search list is available,
-  // so first reduce to a vector so we can access all the inodes simultaneously.
-  return inodes.reduce(std::vector<Inode>{},
-                       [](std::vector<Inode> vec, Inode inode) {
-                         vec.push_back(inode);
-                         return vec;
-                       },
-                       [](std::vector<Inode> v){
-                         return v;  // TODO: use an identity function
-                       })
-    .flat_map([root_directories=std::move(root_directories), mode, self=*this]
-          (std::vector<Inode> vec) {
-      // All borrowed values (e.g. SystemCall) must outlive the observable.
-      return self.FindFilenamesFromInodes(root_directories, vec, mode);
-    }
-  );
-}
-
-auto/*[observable<InodeResult>]*/ EmitAllInodesFromDirectories(
-    std::vector<std::string> root_dirs,
-    borrowed<SystemCall*> system_call) {
-
-  // Create a (lazy) observable that will emit each DirectoryEntry that is a recursive subchild
-  // of root_dirs. Emission will be stopped when its unsubscribed from.
-  //
-  // This is done by calling readdir(3) lazily.
-  auto/*obs<DirectoryEntry>*/ find_all_subdir_entries = ([&]() {
-    DirectoryEntry sentinel = DirectoryEntry::CreateSentinel(std::move(root_dirs));
-    auto/*obs<DirectoryEntryResult*/ results = sentinel.GetSubTreePreOrderEntries(system_call);
-
-    // Drop any errors by logging them to logcat. "Unwrap" the expected into the underlying data.
-    auto/*obs<DirectoryEntry*>*/ expected_drop_errors = MapExpectedOrLogError(std::move(results));
-    return expected_drop_errors;
-  })();
-
-  // Fill in -1 for the dev_t since readdir only returns the ino_t.
-  // The caller of this function is expected to call stat(2) later on to fill in
-  // the full data.
-  return find_all_subdir_entries.map([](DirectoryEntry e) {
-    return InodeResult::makeSuccess(Inode::FromDeviceAndInode(-1, e.d_ino), std::move(e.filename));
-  });
-}
-
-rxcpp::observable<InodeResult>
-    SearchDirectories::ListAllFilenames(std::vector<std::string> root_directories) const {
-  // TODO: refactor implementation into DiskScanDataSource.
-  return EmitAllInodesFromDirectories(std::move(root_directories),
-                                      /*borrowed*/system_call_);
-}
-
-struct FilterState {
-  // Emit 'match' Inodes corresponding to the ones here.
-  InodeSet inode_set;
-
-  // An inode matching one of the ones in inode_set was discovered in the most-recently
-  // emitted SearchState.
-  //
-  // The InodeSet removes any matching 'Inode'.
-  std::optional<InodeResult> match;
-
-  FilterState() = default;
-  FilterState(FilterState&& other) = default;
-
-  // Copying the InodeSet is expensive, so forbid any copies.
-  FilterState(const FilterState& other) = delete;
-};
-
-std::ostream& operator<<(std::ostream& os, const FilterState& s) {
-  os << "FilterState{match:";
-  // Print the 'match' first. The InodeSet could be very large so it could be truncated in logs.
-  if (s.match) {
-    os << s.match.value();
-  } else {
-    os << "(none)";
-  }
-  os << ", inode_set:" << s.inode_set << "}";
-  return os;
-}
-
-rxcpp::observable<InodeResult> SearchDirectories::FilterFilenamesForSpecificInodes(
-    rxcpp::observable<InodeResult> all_inodes,
-    std::vector<Inode> inode_list,
-    bool missing_device_number,   // missing dev_t portion?
-    bool needs_verification) const {
-  // TODO: refactor into InodeResolver
-
-  borrowed<SystemCall*> system_call = system_call_;
-
-  // InodeResult may be missing the dev_t portion, so we may need to call scan(2) again
-  // to confirm the dev_t. We skip calling scan(2) when the ino_t does not match.
-  // InodeSet lets us optimally avoid calling scan(2).
-  std::shared_ptr<FilterState> initial = std::make_shared<FilterState>();
-  initial->inode_set = InodeSet::OfList(inode_list);
-
-  auto/*[observable<FilterState>,Connectable]*/ filter_state_results = all_inodes.scan(
-      std::move(initial),
-      [system_call, missing_device_number]
-          (std::shared_ptr<FilterState> filter_state, InodeResult inode_result) {
-        LOG(VERBOSE) << "FilterFilenamesForSpecificInodes#Scan "
-                     << inode_result << ", state: " << *filter_state;
-
-        filter_state->match = std::nullopt;
-
-        InodeSet* inodes = &filter_state->inode_set;
-
-        // Find all the possible (dev_t, ino_t) potential needles given an ino_t in the haystack.
-        InodeSet::ValueRange inode_list = inodes->FindInodeList(inode_result.inode.inode);
-
-        // This inode result doesn't correspond to any inodes we are searching for.
-        if (!inode_list) {
-          // Drop the result and keep going.
-          return filter_state;
-        }
-
-        if (missing_device_number) {
-          // Need to fill in dev_t by calling stat(2).
-          VisitValueOrLogError(std::move(inode_result.data), [&](std::string filename) {
-            StatResult maybe_stat = Stat(filename, system_call);
-            VisitValueOrLogError(maybe_stat, [&](const struct stat& stat_buf) {
-              // Try to match the specific inode. Usually this will not result in a match (nullopt).
-              std::optional<Inode> inode = inodes->FindAndRemoveInodeInList(inode_list, stat_buf);
-
-              if (inode) {
-                filter_state->match = InodeResult::makeSuccess(inode.value(), std::move(filename));
-              }
-            });
-
-            // Note: stat errors are logged here to make the error closer to the occurrence.
-            // In theory, we could just return it as an InodeResult but then the error would
-            // just get logged elsewhere.
-          });
-        } else {
-            // Trust the dev_t in InodeResult is valid. Later passes can verify it.
-
-            // Try to match the specific inode. Usually this will not result in a match (nullopt).
-            std::optional<Inode> inode =
-                inodes->FindAndRemoveInodeInList(inode_list, inode_result.inode);
-
-            if (inode) {
-              filter_state->match = inode_result;
-            }
-
-            // Note that the InodeResult doesn't necessarily need to have a valid filename here.
-            // If the earlier pass returned an error-ed result, this will forward the error code.
-        }
-
-        return filter_state;
-      }
-  // Avoid exhausting a potentially 'infinite' stream of files by terminating as soon
-  // as we find every single inode we care about.
-  ).take_while([](std::shared_ptr<FilterState> state) {
-      // Also emit the last item that caused the search set to go empty.
-      bool cond = !state->inode_set.Empty() || state->match;
-
-      if (WOULD_LOG(VERBOSE)) {
-        static int kCounter = 0;
-        LOG(VERBOSE) << "FilterFilenamesForSpecificInodes#take_while (" << kCounter++ <<
-                     ",is_empty:"
-                     << state->inode_set.Empty() << ", match:" << state->match.has_value();
-      }
-      // Minor O(1) implementation inefficiency:
-      // (Too minor to fix but it can be strange if looking at the logs or readdir traces).
-      //
-      // Note, because we return 'true' after the search set went empty,
-      // the overall stream graph still pulls from filter_state_results exactly once more:
-      //
-      // This means that for cond to go to false, we would've read one extra item and then discarded
-      // it. If that item was the first child of a directory, that means we essentially did
-      // one redundant pass of doing a readdir.
-      // In other words if the search set goes to empty while the current item is a directory,
-      //
-      // it will definitely readdir on it at least once as we try to get the first child in
-      // OnTreeTraversal.
-      //
-      // This could be fixed with a 'take_until(Predicate)' operator which doesn't discard
-      // the last item when the condition becomes false. However rxcpp seems to lack this operator,
-      // whereas RxJava has it.
-
-      if (!cond) {
-        LOG(VERBOSE) << "FilterFilenamesForSpecificInodes#take_while "
-                     << "should now terminate for " << *state;
-      }
-
-      return cond;
-  }).publish();
-  // The publish here is mandatory. The stream is consumed twice (once by matched and once by
-  // unmatched streams). Without the publish, once all items from 'matched' were consumed it would
-  // start another instance of 'filter_state_results' (i.e. it appears as if the search
-  // is restarted).
-  //
-  // By using 'publish', the filter_state_results is effectively shared by both downstream nodes.
-  // Note that this also requires the subscriber to additionally call #connect on the above stream,
-  // otherwise no work will happen.
-
-  // Lifetime notes:
-  //
-  // The the 'FilterState' is emitted into both below streams simultaneously.
-  //    The 'unmatched_inode_values' only touches the inode_set.
-  //    The 'matched_inode_values' only touches the match.
-  // Either stream can 'std::move' from those fields because they don't move each other's fields.
-  auto/*observable<InodeResult>*/ matched_inode_values = filter_state_results
-      .filter([](std::shared_ptr<FilterState> filter_state) {
-                  return filter_state->match.has_value(); })
-      .map([](std::shared_ptr<FilterState> filter_state) {
-                  return std::move(filter_state->match.value()); });
-                     // observable<InodeResult>
-
-  auto/*observable<?>*/ unmatched_inode_values = filter_state_results
-      // The 'last' FilterState is the one that contains all the remaining inodes.
-      .take_last(1)  // observable<FilterState>
-      .flat_map([](std::shared_ptr<FilterState> filter_state) {
-          LOG(VERBOSE) << "FilterFilenamesForSpecificInodes#unmatched -- flat_map";
-          // Aside: Could've used a move here if the inodes weren't so lightweight already.
-          return filter_state->inode_set.IterateValues(); })
-                     // observable<Inode>
-      .map([](const Inode& inode) {
-          LOG(VERBOSE) << "FilterFilenamesForSpecificInodes#unmatched -- map";
-          return InodeResult::makeFailure(inode, InodeResult::kCouldNotFindFilename);
-      });
-                     // observable<InodeResult>
-
-  // The matched and unmatched InodeResults are emitted together.
-  //   Use merge, not concat, because we need both observables to be subscribed to simultaneously.
-
-  auto/*observable<InodeResult*/ all_inode_results =
-      matched_inode_values.merge(unmatched_inode_values);
-
-  // Verify the inode results by calling stat(2).
-  // Unverified results are turned into an error.
-
-  auto/*observable<InodeResult>*/ verified_inode_results =
-    all_inode_results.map([needs_verification, system_call](InodeResult result) {
-      if (!needs_verification || !result) {
-        // Skip verification if requested, or if the result didn't have a filename.
-        return result;
-      }
-
-      const std::string& filename = result.data.value();
-      StatResult maybe_stat = Stat(filename, system_call);
-
-      if (maybe_stat)
-      {
-        if (result.inode == Inode::FromDeviceAndInode(maybe_stat->st_dev, maybe_stat->st_ino)) {
-          return result;
-        } else {
-          LOG(WARNING)
-              << "FilterFilenamesForSpecificInodes#verified fail out-of-date inode: " << result;
-          return InodeResult::makeFailure(result.inode, InodeResult::kVerificationFailed);
-        }
-      } else {
-        // Forward stat errors directly, as it could be a missing security rule,
-        // but turn -ENOENT into casual verification errors.
-        const StatError& err = maybe_stat.error();
-        int error_code = err.err_no;
-        if (err.err_no == ENOENT) {
-          error_code = InodeResult::kVerificationFailed;
-
-          // TODO: Don't LOG(WARNING) here because this could be very common if we
-          // access the data much much later after the initial results were read in.
-          LOG(WARNING)
-              << "FilterFilenamesForSpecificInodes#verified fail out-of-date filename: " << result;
-        } else {
-          LOG(ERROR)
-              << "FilterFilenamesForSpecificInodes#verified stat(2) failure: " << err;
-        }
-
-        return InodeResult::makeFailure(result.inode, error_code);
-      }
-    });
-
-  // Now that all mid-stream observables have been connected, turn the Connectable observable
-  // into a regular observable.
-  return verified_inode_results.ref_count(filter_state_results);
-}
-
-rxcpp::observable<InodeResult> SearchDirectories::EmitAllFilenames(
-    rxcpp::observable<InodeResult> all_inodes,
-    bool missing_device_number,   // missing dev_t portion?
-    bool needs_verification) const {
-  // TODO: refactor into InodeResolver
-
-  borrowed<SystemCall*> system_call = system_call_;
-
-  // InodeResult may be missing the dev_t portion, so we may need to call scan(2) again
-  // to confirm the dev_t.
-
-  using EmitAllState = std::optional<InodeResult>;
-
-  auto/*[observable<FilterState>,Connectable]*/ all_inode_results = all_inodes.map(
-      [system_call, missing_device_number](InodeResult inode_result) {
-        LOG(VERBOSE) << "EmitAllFilenames#map "
-                     << inode_result;
-
-        // Could fail if the device number is missing _and_ stat(2) fails.
-        EmitAllState match = std::nullopt;
-
-        if (missing_device_number) {
-          // Need to fill in dev_t by calling stat(2).
-          VisitValueOrLogError(std::move(inode_result.data), [&](std::string filename) {
-            StatResult maybe_stat = Stat(filename, system_call);
-            VisitValueOrLogError(maybe_stat, [&](const struct stat& stat_buf) {
-              Inode inode = Inode::FromDeviceAndInode(stat_buf.st_dev, stat_buf.st_ino);
-              match = InodeResult::makeSuccess(inode, std::move(filename));
-            });
-
-            // Note: stat errors are logged here to make the error closer to the occurrence.
-            // In theory, we could just return it as an InodeResult but then the error would
-            // just get logged elsewhere.
-          });
-        } else {
-            // Trust the dev_t in InodeResult is valid. Later passes can verify it.
-            match = std::move(inode_result);
-
-            // Note that the InodeResult doesn't necessarily need to have a valid filename here.
-            // If the earlier pass returned an error-ed result, this will forward the error code.
-        }
-
-        return match;  // implicit move.
-      }
-  );
-
-  auto/*observable<InodeResult>*/ matched_inode_values = all_inode_results
-      .filter([](const EmitAllState& filter_state) { return filter_state.has_value(); })
-      .map([](EmitAllState& filter_state) { return std::move(filter_state.value()); });
-                     // observable<InodeResult>
-
-  // Verify the inode results by calling stat(2).
-  // Unverified results are turned into an error.
-
-  auto/*observable<InodeResult>*/ verified_inode_results =
-    matched_inode_values.map([needs_verification, system_call](InodeResult result) {
-      if (!needs_verification || !result) {
-        // Skip verification if requested, or if the result didn't have a filename.
-        return result;
-      }
-
-      const std::string& filename = result.data.value();
-      StatResult maybe_stat = Stat(filename, system_call);
-
-      if (maybe_stat)
-      {
-        if (result.inode == Inode::FromDeviceAndInode(maybe_stat->st_dev, maybe_stat->st_ino)) {
-          return result;
-        } else {
-          LOG(WARNING)
-              << "EmitAllFilenames#verified fail out-of-date inode: " << result;
-          return InodeResult::makeFailure(result.inode, InodeResult::kVerificationFailed);
-        }
-      } else {
-        // Forward stat errors directly, as it could be a missing security rule,
-        // but turn -ENOENT into casual verification errors.
-        const StatError& err = maybe_stat.error();
-        int error_code = err.err_no;
-        if (err.err_no == ENOENT) {
-          error_code = InodeResult::kVerificationFailed;
-
-          // TODO: Don't LOG(WARNING) here because this could be very common if we
-          // access the data much much later after the initial results were read in.
-          LOG(WARNING)
-              << "EmitAllFilenames#verified fail out-of-date filename: " << result;
-        } else {
-          LOG(ERROR)
-              << "EmitAllFilenames#verified stat(2) failure: " << err;
-        }
-
-        return InodeResult::makeFailure(result.inode, error_code);
-      }
-    });
-
-  // TODO: refactor this function some more with the Find(inode_set) equivalent.
-
-  // Now that all mid-stream observables have been connected, turn the Connectable observable
-  // into a regular observable.
-  return verified_inode_results;
-}
-
-}  // namespace iorap::inode2filename
diff --git a/src/inode2filename/search_directories.h b/src/inode2filename/search_directories.h
deleted file mode 100644
index 0b4af78..0000000
--- a/src/inode2filename/search_directories.h
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_INODE2FILENAME_SEARCH_DIRECTORIES_H_
-#define IORAP_SRC_INODE2FILENAME_SEARCH_DIRECTORIES_H_
-
-#include "inode2filename/inode.h"
-#include "inode2filename/system_call.h"
-#include "inode2filename/inode_resolver.h"
-
-#include <fruit/fruit.h>
-
-#include <rxcpp/rx.hpp>
-namespace iorap::inode2filename {
-
-// TODO: rename.
-using SearchMode = ProcessMode;
-
-struct SearchDirectories {
-  // Type-erased subset of rxcpp::connectable_observable<?>
-  struct RxAnyConnectable {
-    // Connects to the underlying observable.
-    //
-    // This kicks off the graph, streams begin emitting items.
-    // This method will block until all items have been fully emitted
-    // and processed by any subscribers.
-    virtual void connect() = 0;
-
-    virtual ~RxAnyConnectable(){}
-  };
-
-
-  // Create a cold observable of inode results (a lazy stream) corresponding
-  // to the inode search list.
-  //
-  // A depth-first search is done on each of the root directories (in order),
-  // until all inodes have been found (or until all directories have been exhausted).
-  //
-  // Some internal errors may occur during emission that aren't part of an InodeResult;
-  // these will be sent to the error logcat and dropped.
-  //
-  // Calling this function does not begin the search.
-  // The returned observable will begin the search after subscribing to it.
-  //
-  // The emitted InodeResult stream has these guarantees:
-  // - All inodes in inode_list will eventually be emitted exactly once in an InodeResult
-  // - When all inodes are found, directory traversal is halted.
-  // - The order of emission can be considered arbitrary.
-  //
-  // Lifetime rules:
-  // - The observable must be fully consumed before deleting any of the SearchDirectory's
-  //   borrowed constructor parameters (e.g. the SystemCall).
-  // - SearchDirectory itself can be deleted at any time after creating an observable.
-  rxcpp::observable<InodeResult>
-      FindFilenamesFromInodes(std::vector<std::string> root_directories,
-                              std::vector<Inode> inode_list,
-                              SearchMode mode) const;
-
-  // Create a cold observable of inode results (a lazy stream) corresponding
-  // to the inode search list.
-  //
-  // A depth-first search is done on each of the root directories (in order),
-  // until all inodes have been found (or until all directories have been exhausted).
-  //
-  // Some internal errors may occur during emission that aren't part of an InodeResult;
-  // these will be sent to the error logcat and dropped.
-  //
-  // Calling this function does not begin the search.
-  // The returned observable will begin the search after subscribing to it.
-  //
-  // The emitted InodeResult stream has these guarantees:
-  // - All inodes in inode_list will eventually be emitted exactly once in an InodeResult
-  // - When all inodes are found, directory traversal is halted.
-  // - The order of emission can be considered arbitrary.
-  //
-  // Lifetime rules:
-  // - The observable must be fully consumed before deleting any of the SearchDirectory's
-  //   borrowed constructor parameters (e.g. the SystemCall).
-  // - SearchDirectory itself can be deleted at any time after creating an observable.
-  std::pair<rxcpp::observable<InodeResult>, std::unique_ptr<RxAnyConnectable>>
-      FindFilenamesFromInodesPair(std::vector<std::string> root_directories,
-                                  std::vector<Inode> inode_list,
-                                  SearchMode mode) const;
-
-  // No items on the output stream will be emitted until 'inodes' completes.
-  //
-  // The current algorithm is a naive DFS, so if it began too early it would either
-  // miss the search items or require traversal restarts.
-  //
-  // See above for more details.
-  rxcpp::observable<InodeResult>
-      FindFilenamesFromInodes(std::vector<std::string> root_directories,
-                              rxcpp::observable<Inode> inodes,
-                              SearchMode mode) const;
-
-  rxcpp::observable<InodeResult>
-      ListAllFilenames(std::vector<std::string> root_directories) const;
-
-  rxcpp::observable<InodeResult> FilterFilenamesForSpecificInodes(
-      // haystack that will be subscribed to until all in inode_list are found.
-      rxcpp::observable<InodeResult> all_inodes,
-      // key list: traverse all_inodes until we emit all results from inode_list.
-      std::vector<Inode> inode_list,
-      // all_inodes have a missing device number: use stat(2) to fill it in.
-      bool missing_device_number,
-      bool needs_verification) const;
-
-  rxcpp::observable<InodeResult> EmitAllFilenames(
-      // haystack that will be subscribed to until all in inode_list are found.
-      rxcpp::observable<InodeResult> all_inodes,
-      // all_inodes have a missing device number: use stat(2) to fill it in.
-      bool missing_device_number,
-      bool needs_verification) const;
-
-  // Any borrowed parameters here can also be borrowed by the observables returned by the above
-  // member functions.
-  //
-  // The observables must be fully consumed within the lifetime of the borrowed parameters.
-  INJECT(SearchDirectories(borrowed<SystemCall*> system_call))
-      : system_call_(system_call) {}
-
-  // TODO: is there a way to get rid of this second RxAnyConnectable parameter?
- private:
-  // This gets passed around to lazy lambdas, so we must finish consuming any observables
-  // before the injected system call is deleted.
-  borrowed<SystemCall*> system_call_;
-};
-
-}  // namespace iorap::inode2filename
-
-#endif  // IORAP_SRC_INODE2FILENAME_SEARCH_DIRECTORIES_H_
diff --git a/src/inode2filename/system_call.h b/src/inode2filename/system_call.h
deleted file mode 100644
index 43c371f..0000000
--- a/src/inode2filename/system_call.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_INODE2FILENAME_SYSTEM_CALL_H_
-#define IORAP_SRC_INODE2FILENAME_SYSTEM_CALL_H_
-
-#include <fruit/fruit.h>
-
-#include <dirent.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-// Abstract out the system calls behind a virtual interface:
-// This enables us to use dependency injection to provide mock implementations
-// during tests.
-struct SystemCall {
-  // stat(2)
-  virtual int stat(const char *pathname, struct stat *statbuf) = 0;
-
-  // opendir(3)
-  virtual DIR *opendir(const char *name) = 0;
-
-  // readdir(3)
-  virtual struct dirent *readdir(DIR *dirp) = 0;
-
-  // closedir(3)
-  virtual int closedir(DIR *dirp) = 0;
-
-  virtual ~SystemCall() {}
-};
-
-// "Live" implementation that calls down to libc.
-struct SystemCallImpl : public SystemCall {
-  // Marks this constructor as the one to use for injection.
-  INJECT(SystemCallImpl()) = default;
-
-  // stat(2)
-  virtual int stat(const char *pathname, struct stat *statbuf) override {
-    return ::stat(pathname, statbuf);
-  }
-
-  // opendir(3)
-  virtual DIR *opendir(const char *name) override {
-    return ::opendir(name);
-  }
-
-  // readdir(3)
-  virtual struct dirent *readdir(DIR *dirp) override {
-    return ::readdir(dirp);
-  }
-
-  // closedir(3)
-  virtual int closedir(DIR *dirp) override {
-    return ::closedir(dirp);
-  }
-
-  virtual ~SystemCallImpl() {}
-};
-
-#endif  // IORAP_SRC_INODE2FILENAME_SYSTEM_CALL_H_
-
diff --git a/src/iorapd/main.cc b/src/iorapd/main.cc
deleted file mode 100644
index a3a63f2..0000000
--- a/src/iorapd/main.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "binder/iiorap_impl.h"
-#include "common/debug.h"
-#include "common/loggers.h"
-#include "common/property.h"
-#include "db/models.h"
-#include "manager/event_manager.h"
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <binder/IPCThreadState.h>
-#include <server_configurable_flags/get_flags.h>
-#include <utils/Trace.h>
-
-#include <stdio.h>
-
-static constexpr const char* kServiceName = iorap::binder::IIorapImpl::getServiceName();
-
-int main(int /*argc*/, char** argv) {
-  bool tracing_allowed = iorap::common::IsTracingEnabled(/*default_value=*/"false");
-  bool readahead_allowed = iorap::common::IsReadAheadEnabled(/*default_value*/"false");
-  if (!tracing_allowed && !readahead_allowed) {
-    LOG(INFO) << "Turn off IORap because both tracing and prefetching are off.";
-    return 0;
-  }
-
-  if (android::base::GetBoolProperty("iorapd.log.verbose", iorap::kIsDebugBuild)) {
-    // Show verbose logs if the property is enabled or if we are a debug build.
-    setenv("ANDROID_LOG_TAGS", "*:v", /*overwrite*/ 1);
-  }
-
-  // Logs go to system logcat.
-  android::base::InitLogging(argv, iorap::common::StderrAndLogdLogger{android::base::SYSTEM});
-
-  LOG(INFO) << kServiceName << " (the prefetchening) firing up";
-  {
-    android::ScopedTrace trace_db_init{ATRACE_TAG_ACTIVITY_MANAGER, "IorapNativeService::db_init"};
-    iorap::db::SchemaModel db_schema =
-        iorap::db::SchemaModel::GetOrCreate(
-            android::base::GetProperty("iorapd.db.location",
-                                       "/data/misc/iorapd/sqlite.db"));
-    db_schema.MarkSingleton();
-  }
-
-  std::shared_ptr<iorap::manager::EventManager> event_manager;
-  {
-    android::ScopedTrace trace_start{ATRACE_TAG_ACTIVITY_MANAGER, "IorapNativeService::start"};
-
-    // TODO: use fruit for this DI.
-    event_manager =
-        iorap::manager::EventManager::Create();
-    if (!iorap::binder::IIorapImpl::Start(event_manager)) {
-      LOG(ERROR) << "Unable to start IorapNativeService";
-      exit(1);
-    }
-  }
-
-  // This must be logged after all other initialization has finished.
-  LOG(INFO) << kServiceName << " (the prefetchening) readied up";
-
-  event_manager->Join();  // TODO: shutdown somewhere?
-  // Block until something else shuts down the binder service.
-  android::IPCThreadState::self()->joinThreadPool();
-  LOG(INFO) << kServiceName << " shutting down";
-
-  return 0;
-}
diff --git a/src/maintenance/controller.cc b/src/maintenance/controller.cc
deleted file mode 100644
index 8929057..0000000
--- a/src/maintenance/controller.cc
+++ /dev/null
@@ -1,633 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "compiler/compiler.h"
-#include "maintenance/controller.h"
-
-#include "common/cmd_utils.h"
-#include "common/debug.h"
-#include "common/expected.h"
-#include "common/trace.h"
-
-#include "db/models.h"
-#include "inode2filename/inode.h"
-#include "inode2filename/search_directories.h"
-#include "prefetcher/read_ahead.h"
-
-#include <android-base/file.h>
-#include <utils/Printer.h>
-
-#include <chrono>
-#include <ctime>
-#include <iostream>
-#include <filesystem>
-#include <fstream>
-#include <limits>
-#include <mutex>
-#include <optional>
-#include <vector>
-#include <string>
-#include <sys/wait.h>
-
-namespace iorap::maintenance {
-
-const constexpr int64_t kCompilerCheckIntervalMs = 10;
-static constexpr size_t kMinTracesForCompilation = 1;
-const constexpr char* kDenyListFilterDexFiles = "[.](art|oat|odex|vdex|dex)$";
-
-struct LastJobInfo {
-  time_t last_run_ns_{0};
-  size_t activities_last_compiled_{0};
-};
-
-LastJobInfo last_job_info_;
-std::mutex last_job_info_mutex_;
-
-// Gets the path of output compiled trace.
-db::CompiledTraceFileModel CalculateNewestFilePath(
-    const std::string& package_name,
-    const std::string& activity_name,
-    int version) {
-   db::VersionedComponentName versioned_component_name{
-     package_name, activity_name, version};
-
-   db::CompiledTraceFileModel output_file =
-       db::CompiledTraceFileModel::CalculateNewestFilePath(versioned_component_name);
-
-   return output_file;
-}
-
-using ArgString = const char*;
-
-static constexpr const char kCommandFileName[] = "/system/bin/iorap.cmd.compiler";
-
-int Exec::Execve(const std::string& pathname,
-                 std::vector<std::string>& argv_vec,
-                 char *const envp[]) {
-  std::unique_ptr<ArgString[]> argv_ptr =
-      common::VecToArgv(kCommandFileName, argv_vec);
-
-  return execve(pathname.c_str(), (char**)argv_ptr.get(), envp);
-}
-
-pid_t Exec::Fork() {
-  return fork();
-}
-
-// Represents the parameters used when fork+exec compiler.
-struct CompilerForkParameters {
-  std::vector<std::string> input_pbs;
-  std::vector<uint64_t> timestamp_limit_ns;
-  std::string output_proto;
-  std::vector<int32_t> pids;
-  ControllerParameters controller_params;
-
-  CompilerForkParameters(const std::vector<compiler::CompilationInput>& perfetto_traces,
-                         const std::string& output_proto,
-                         ControllerParameters controller_params) :
-    output_proto(output_proto), controller_params(controller_params) {
-        for (compiler::CompilationInput perfetto_trace : perfetto_traces) {
-          input_pbs.push_back(perfetto_trace.filename);
-          timestamp_limit_ns.push_back(perfetto_trace.timestamp_limit_ns);
-          pids.push_back(perfetto_trace.pid);
-        }
-  }
-};
-
-std::vector<std::string> MakeCompilerParams(const CompilerForkParameters& params) {
-    std::vector<std::string> argv;
-    ControllerParameters controller_params = params.controller_params;
-
-    common::AppendArgsRepeatedly(argv, params.input_pbs);
-    common::AppendArgsRepeatedly(argv, "--timestamp_limit_ns", params.timestamp_limit_ns);
-    common::AppendArgsRepeatedly(argv, "--pid", params.pids);
-
-    if (controller_params.output_text) {
-      argv.push_back("--output-text");
-    }
-
-    common::AppendArgs(argv, "--output-proto", params.output_proto);
-
-    if (controller_params.inode_textcache) {
-      common::AppendArgs(argv, "--inode-textcache", *controller_params.inode_textcache);
-    }
-
-    if (controller_params.verbose) {
-      argv.push_back("--verbose");
-    }
-
-    if (controller_params.exclude_dex_files) {
-      common::AppendArgs(argv, "--denylist-filter", kDenyListFilterDexFiles);
-    }
-
-    return argv;
-}
-
-// Sets a watch dog for the given pid and kill it if timeout.
-std::thread SetTimeoutWatchDog(pid_t pid, int64_t timeout_ms, std::atomic<bool>& cancel_watchdog) {
-  std::thread watchdog_thread{[pid, timeout_ms, &cancel_watchdog]() {
-    std::chrono::time_point start = std::chrono::system_clock::now();
-    std::chrono::milliseconds timeout(timeout_ms);
-    while (!cancel_watchdog) {
-      int status = kill(pid, 0);
-      if (status != 0) {
-        LOG(DEBUG) << "Process (" << pid << ") doesn't exist now.";
-        break;
-      }
-      std::chrono::time_point cur = std::chrono::system_clock::now();
-      if (cur - start > timeout) {
-        LOG(INFO) << "Process (" << pid << ") is timeout!";
-        LOG(INFO) << "start time: "
-                   << std::chrono::system_clock::to_time_t(start)
-                   << " end time: "
-                   << std::chrono::system_clock::to_time_t(cur)
-                   << " timeout: "
-                   << timeout_ms;
-        kill(pid, SIGKILL);
-        break;
-      }
-      usleep(kCompilerCheckIntervalMs * 1000);
-    }
-  }};
-
-  return watchdog_thread;
-}
-
-bool StartViaFork(const CompilerForkParameters& params) {
-  const ControllerParameters& controller_params = params.controller_params;
-  pid_t child = controller_params.exec->Fork();
-
-  if (child == -1) {
-    LOG(FATAL) << "Failed to fork a process for compilation";
-  } else if (child > 0) {  // we are the caller of this function
-    LOG(DEBUG) << "forked into a process for compilation , pid = " << child;
-
-    int64_t compiler_timeout_ms =
-        android::base::GetIntProperty("iorapd.maintenance.compiler_timeout_ms",
-                                       /*default*/ 10 * 60 * 1000); // 10 min
-    std::atomic<bool> cancel_watchdog(false);
-    std::thread watchdog_thread = SetTimeoutWatchDog(child, compiler_timeout_ms, cancel_watchdog);
-    int wstatus;
-    waitpid(child, /*out*/&wstatus, /*options*/0);
-
-    // Terminate the thread after the compiler process is killed or done.
-    LOG(DEBUG) << "Terminate the watch dog thread.";
-    cancel_watchdog = true;
-    watchdog_thread.join();
-
-    if (!WIFEXITED(wstatus)) {
-      LOG(ERROR) << "Child terminated abnormally, status: " << WEXITSTATUS(wstatus);
-      return false;
-    }
-
-    int status = WEXITSTATUS(wstatus);
-    LOG(DEBUG) << "Child terminated, status: " << status;
-    if (status == 0) {
-      LOG(DEBUG) << "Iorap compilation succeeded";
-      return true;
-    } else {
-      LOG(ERROR) << "Iorap compilation failed";
-      return false;
-    }
-  } else {
-    // we are the child that was forked.
-    std::vector<std::string> argv_vec = MakeCompilerParams(params);
-    std::unique_ptr<ArgString[]> argv_ptr =
-        common::VecToArgv(kCommandFileName, argv_vec);
-
-    std::stringstream argv; // for debugging.
-    for (std::string arg : argv_vec) {
-      argv  << arg << ' ';
-    }
-    LOG(DEBUG) << "fork+exec: " << kCommandFileName << " " << argv.str();
-
-    controller_params.exec->Execve(kCommandFileName,
-                                          argv_vec,
-                                         /*envp*/nullptr);
-    // This should never return.
-  }
-  return false;
-}
-
-// Gets the perfetto trace infos in the histories.
-std::vector<compiler::CompilationInput> GetPerfettoTraceInfo(
-    const db::DbHandle& db,
-    const std::vector<db::AppLaunchHistoryModel>& histories) {
-  std::vector<compiler::CompilationInput> perfetto_traces;
-
-  for(db::AppLaunchHistoryModel history : histories) {
-    // Get perfetto trace.
-    std::optional<db::RawTraceModel> raw_trace =
-        db::RawTraceModel::SelectByHistoryId(db, history.id);
-    if (!raw_trace) {
-      // This is normal: non-cold launches do not have traces.
-      continue;
-    }
-
-    if (!history.pid) {
-      LOG(DEBUG) << "Missing pid for history " << history.id;
-      continue;
-    }
-
-    uint64_t timestamp_limit = std::numeric_limits<uint64_t>::max();
-    // Get corresponding timestamp limit.
-    if (history.report_fully_drawn_ns) {
-      timestamp_limit = *history.report_fully_drawn_ns;
-    } else if (history.total_time_ns) {
-      timestamp_limit = *history.total_time_ns;
-    } else {
-      LOG(DEBUG) << " No timestamp exists. Using the max value.";
-    }
-    perfetto_traces.push_back({raw_trace->file_path, timestamp_limit, history.pid});
-  }
-  return perfetto_traces;
-}
-
-// Helper struct for printing vector.
-template <class T>
-struct VectorPrinter {
-  std::vector<T>& values;
-};
-
-std::ostream& operator<<(std::ostream& os,
-                      const struct compiler::CompilationInput& perfetto_trace) {
-  os << "file_path: " << perfetto_trace.filename << " "
-     << "timestamp_limit: " << perfetto_trace.timestamp_limit_ns;
-  return os;
-}
-
-template <class T>
-std::ostream& operator<<(std::ostream& os, const struct VectorPrinter<T>& printer) {
-  os << "[\n";
-  for (T i : printer.values) {
-    os << i << ",\n";
-  }
-  os << "]\n";
-  return os;
-}
-
-// Compiled the perfetto traces for an activity.
-bool CompileActivity(const db::DbHandle& db,
-                     int package_id,
-                     const std::string& package_name,
-                     const std::string& activity_name,
-                     int version,
-                     const ControllerParameters& params) {
-  ScopedFormatTrace atrace_compile_package(ATRACE_TAG_PACKAGE_MANAGER,
-                                           "Compile activity %s",
-                                           activity_name.c_str());
-
-  LOG(DEBUG) << "CompileActivity: " << package_name << "/" << activity_name << "@" << version;
-
-  db::CompiledTraceFileModel output_file =
-      CalculateNewestFilePath(package_name, activity_name, version);
-
-  std::string file_path = output_file.FilePath();
-
-  if (!params.recompile) {
-    if (std::filesystem::exists(file_path)) {
-      LOG(DEBUG) << "compiled trace exists in " << file_path;
-
-      db::VersionedComponentName vcn{package_name, activity_name, version};
-      std::optional<db::PrefetchFileModel> prefetch_file =
-          db::PrefetchFileModel::SelectByVersionedComponentName(db, vcn);
-      if (prefetch_file) {
-        return true;
-      } else {
-        LOG(WARNING) << "Missing corresponding prefetch_file db row for " << vcn;
-        // let it go and compile again. we'll insert the prefetch_file at the bottom.
-      }
-    }
-  }
-
-  std::optional<db::ActivityModel> activity =
-      db::ActivityModel::SelectByNameAndPackageId(db, activity_name.c_str(), package_id);
-  if (!activity) {
-    LOG(ERROR) << "Cannot find activity for package_id: " << package_id
-               <<" activity_name: " <<activity_name;
-    return false;
-  }
-
-  int activity_id = activity->id;
-
-  std::vector<db::AppLaunchHistoryModel> histories =
-      db::AppLaunchHistoryModel::SelectActivityHistoryForCompile(db, activity_id);
-
-  {
-    std::vector<compiler::CompilationInput> perfetto_traces =
-        GetPerfettoTraceInfo(db, histories);
-
-    if (perfetto_traces.size() < params.min_traces) {
-      LOG(DEBUG) << "The number of perfetto traces is " << perfetto_traces.size()
-                 <<", which is less than " << params.min_traces;
-      return false;
-    }
-
-    {
-      std::lock_guard<std::mutex> last_job_info_guard{last_job_info_mutex_};
-      last_job_info_.activities_last_compiled_++;
-    }
-
-    // Show the compilation config.
-    LOG(DEBUG) << "Try to compiled package_id: " << package_id
-               << " package_name: " << package_name
-               << " activity_name: " << activity_name
-               << " version: " << version
-               << " file_path: " << file_path
-               << " verbose: " << params.verbose
-               << " perfetto_traces: "
-               << VectorPrinter<compiler::CompilationInput>{perfetto_traces};
-    if (params.inode_textcache) {
-      LOG(DEBUG) << "inode_textcache: " << *params.inode_textcache;
-    }
-
-    CompilerForkParameters compiler_params{perfetto_traces, file_path, params};
-
-    if (!output_file.MkdirWithParents()) {
-      LOG(ERROR) << "Compile activity failed. Failed to mkdirs " << file_path;
-      return false;
-    }
-
-    ScopedFormatTrace atrace_compile_fork(ATRACE_TAG_PACKAGE_MANAGER,
-                                          "Fork+exec iorap.cmd.compiler",
-                                          activity_name.c_str());
-    if (!StartViaFork(compiler_params)) {
-      LOG(ERROR) << "Compilation failed for package_id:" << package_id
-                 << " activity_name: " << activity_name;
-      return false;
-    }
-  }
-
-  std::optional<db::PrefetchFileModel> compiled_trace =
-      db::PrefetchFileModel::Insert(db, activity_id, file_path);
-  if (!compiled_trace) {
-    LOG(ERROR) << "Cannot insert compiled trace activity_id: " << activity_id
-               << " file_path: " << file_path;
-    return false;
-  }
-  return true;
-}
-
-// Compiled the perfetto traces for activities in an package.
-bool CompilePackage(const db::DbHandle& db,
-                    const std::string& package_name,
-                    int version,
-                    const ControllerParameters& params) {
-  ScopedFormatTrace atrace_compile_package(ATRACE_TAG_PACKAGE_MANAGER,
-                                           "Compile package %s",
-                                           package_name.c_str());
-
-  std::optional<db::PackageModel> package =
-        db::PackageModel::SelectByNameAndVersion(db, package_name.c_str(), version);
-
-  if (!package) {
-    LOG(ERROR) << "Cannot find package for package_name: "
-               << package_name
-               << " and version "
-               << version;
-    return false;
-  }
-
-  std::vector<db::ActivityModel> activities =
-      db::ActivityModel::SelectByPackageId(db, package->id);
-
-  bool ret = true;
-  for (db::ActivityModel activity : activities) {
-    if (!CompileActivity(db, package->id, package->name, activity.name, version, params)) {
-      ret = false;
-    }
-  }
-  return ret;
-}
-
-// Compiled the perfetto traces for packages in a device.
-bool CompileAppsOnDevice(const db::DbHandle& db, const ControllerParameters& params) {
-  {
-    std::lock_guard<std::mutex> last_job_info_guard{last_job_info_mutex_};
-    last_job_info_.activities_last_compiled_ = 0;
-  }
-
-  std::vector<db::PackageModel> packages = db::PackageModel::SelectAll(db);
-  bool ret = true;
-  for (db::PackageModel package : packages) {
-    if (!CompilePackage(db, package.name, package.version, params)) {
-      ret = false;
-    }
-  }
-
-  {
-    std::lock_guard<std::mutex> last_job_info_guard{last_job_info_mutex_};
-    last_job_info_.last_run_ns_ = time(nullptr);
-  }
-
-  return ret;
-}
-
-// Compiled the perfetto traces for a single package in a device.
-bool CompileSingleAppOnDevice(const db::DbHandle& db,
-                              const ControllerParameters& params,
-                              const std::string& package_name) {
-  std::vector<db::PackageModel> packages = db::PackageModel::SelectByName(db, package_name.c_str());
-  bool ret = true;
-  for (db::PackageModel package : packages) {
-    if (!CompilePackage(db, package.name, package.version, params)) {
-      ret = false;
-    }
-  }
-
-  return ret;
-}
-
-bool Compile(const std::string& db_path, const ControllerParameters& params) {
-  iorap::db::SchemaModel db_schema = db::SchemaModel::GetOrCreate(db_path);
-  db::DbHandle db{db_schema.db()};
-  return CompileAppsOnDevice(db, params);
-}
-
-bool Compile(const std::string& db_path,
-             const std::string& package_name,
-             int version,
-             const ControllerParameters& params) {
-  iorap::db::SchemaModel db_schema = db::SchemaModel::GetOrCreate(db_path);
-  db::DbHandle db{db_schema.db()};
-  return CompilePackage(db, package_name, version, params);
-}
-
-bool Compile(const std::string& db_path,
-             const std::string& package_name,
-             const std::string& activity_name,
-             int version,
-             const ControllerParameters& params) {
-  iorap::db::SchemaModel db_schema = db::SchemaModel::GetOrCreate(db_path);
-  db::DbHandle db{db_schema.db()};
-
-  std::optional<db::PackageModel> package =
-      db::PackageModel::SelectByNameAndVersion(db, package_name.c_str(), version);
-
-  if (!package) {
-    LOG(ERROR) << "Cannot find package with name "
-               << package_name
-               << " and version "
-               << version;
-    return false;
-  }
-  return CompileActivity(db, package->id, package_name, activity_name, version, params);
-}
-
-static std::string TimeToString(time_t the_time) {
-  tm tm_buf{};
-  tm* tm_ptr = localtime_r(&the_time, &tm_buf);
-
-  if (tm_ptr != nullptr) {
-    char time_buffer[256];
-    strftime(time_buffer, sizeof(time_buffer), "%a %b %d %H:%M:%S %Y", tm_ptr);
-    return std::string{time_buffer};
-  } else {
-    return std::string{"(nullptr)"};
-  }
-}
-
-static std::string GetTimestampForPrefetchFile(const db::PrefetchFileModel& prefetch_file) {
-  std::filesystem::path path{prefetch_file.file_path};
-
-  std::error_code ec{};
-  auto last_write_time = std::filesystem::last_write_time(path, /*out*/ec);
-  if (ec) {
-    return std::string("Failed to get last write time: ") + ec.message();
-  }
-
-  time_t time = decltype(last_write_time)::clock::to_time_t(last_write_time);
-
-  std::string time_str = TimeToString(time);
-  return time_str;
-}
-
-void DumpPackageActivity(const db::DbHandle& db,
-                         ::android::Printer& printer,
-                         const db::PackageModel& package,
-                         const db::ActivityModel& activity) {
-  int package_id = package.id;
-  const std::string& package_name = package.name;
-  int package_version = package.version;
-  const std::string& activity_name = activity.name;
-  db::VersionedComponentName vcn{package_name, activity_name, package_version};
-
-  // com.google.Settings/com.google.Settings.ActivityMain@1234567890
-  printer.printFormatLine("  %s/%s@%d",
-                          package_name.c_str(),
-                          activity_name.c_str(),
-                          package_version);
-
-  std::optional<db::PrefetchFileModel> prefetch_file =
-      db::PrefetchFileModel::SelectByVersionedComponentName(db, vcn);
-
-  std::vector<db::AppLaunchHistoryModel> histories =
-      db::AppLaunchHistoryModel::SelectActivityHistoryForCompile(db, activity.id);
-  std::vector<compiler::CompilationInput> perfetto_traces =
-        GetPerfettoTraceInfo(db, histories);
-
-  if (prefetch_file) {
-    bool exists_on_disk = std::filesystem::exists(prefetch_file->file_path);
-
-    std::optional<size_t> prefetch_byte_sum =
-        prefetcher::ReadAhead::PrefetchSizeInBytes(prefetch_file->file_path);
-
-    if (exists_on_disk) {
-      printer.printFormatLine("    Compiled Status: Usable compiled trace");
-    } else {
-      printer.printFormatLine("    Compiled Status: Prefetch file deleted from disk.");
-    }
-
-    if (prefetch_byte_sum) {
-      printer.printFormatLine("      Bytes to be prefetched: %zu", *prefetch_byte_sum);
-    } else {
-      printer.printFormatLine("      Bytes to be prefetched: (bad file path)" );
-    }
-
-    printer.printFormatLine("      Time compiled: %s",
-                            GetTimestampForPrefetchFile(*prefetch_file).c_str());
-    printer.printFormatLine("      %s", prefetch_file->file_path.c_str());
-  } else {
-    size_t size = perfetto_traces.size();
-
-    if (size >= kMinTracesForCompilation) {
-      printer.printFormatLine("    Compiled Status: Raw traces pending compilation (%zu)",
-                              perfetto_traces.size());
-    } else {
-      size_t remaining = kMinTracesForCompilation - size;
-      printer.printFormatLine("    Compiled Status: Need %zu more traces for compilation",
-                              remaining);
-    }
-  }
-
-  printer.printFormatLine("    Raw traces:");
-  printer.printFormatLine("      Trace count: %zu", perfetto_traces.size());
-
-  for (compiler::CompilationInput& compilation_input : perfetto_traces) {
-    std::string& raw_trace_file_name = compilation_input.filename;
-
-    printer.printFormatLine("      %s", raw_trace_file_name.c_str());
-  }
-}
-
-void DumpPackage(const db::DbHandle& db,
-                 ::android::Printer& printer,
-                 db::PackageModel package) {
-  std::vector<db::ActivityModel> activities =
-      db::ActivityModel::SelectByPackageId(db, package.id);
-
-  for (db::ActivityModel& activity : activities) {
-    DumpPackageActivity(db, printer, package, activity);
-  }
-}
-
-void DumpAllPackages(const db::DbHandle& db, ::android::Printer& printer) {
-  printer.printLine("Package history in database:");
-
-  std::vector<db::PackageModel> packages = db::PackageModel::SelectAll(db);
-  for (db::PackageModel package : packages) {
-    DumpPackage(db, printer, package);
-  }
-
-  printer.printLine("");
-}
-
-void Dump(const db::DbHandle& db, ::android::Printer& printer) {
-  bool locked = last_job_info_mutex_.try_lock();
-
-  LastJobInfo info = last_job_info_;
-
-  printer.printFormatLine("Background job:");
-  if (!locked) {
-    printer.printLine("""""  (possible deadlock)");
-  }
-  if (info.last_run_ns_ != time_t{0}) {
-    std::string time_str = TimeToString(info.last_run_ns_);
-
-    printer.printFormatLine("  Last run at: %s", time_str.c_str());
-  } else {
-    printer.printFormatLine("  Last run at: (None)");
-  }
-  printer.printFormatLine("  Activities last compiled: %zu", info.activities_last_compiled_);
-
-  printer.printLine("");
-
-  if (locked) {
-    last_job_info_mutex_.unlock();
-  }
-
-  DumpAllPackages(db, printer);
-}
-
-}  // namespace iorap::maintenance
diff --git a/src/maintenance/controller.h b/src/maintenance/controller.h
deleted file mode 100644
index 750d0b4..0000000
--- a/src/maintenance/controller.h
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_MAINTENANCE_COMPILER_CONTROLLER_H_
-#define IORAP_SRC_MAINTENANCE_COMPILER_CONTROLLER_H_
-
-#include "db/file_models.h"
-#include "inode2filename/inode_resolver.h"
-
-#include <string>
-#include <vector>
-
-namespace android {
-class Printer;
-}  // namespace android
-
-namespace iorap::maintenance {
-
-// Enabling mock for testing purpose.
-class IExec {
- public:
-  virtual int Execve(const std::string& pathname,
-                     std::vector<std::string>& argv_vec,
-                     char *const envp[]) = 0;
-  virtual int Fork() = 0;
-  virtual ~IExec() = default;
-};
-
-class Exec : public IExec {
- public:
-   virtual int Execve(const std::string& pathname,
-                      std::vector<std::string>& argv_vec,
-                      char *const envp[]);
-   virtual int Fork();
-};
-
-// Represents the parameters used for compilation controller.
-struct ControllerParameters {
-  bool output_text;
-  // The path of inode2filepath file.
-  std::optional<std::string> inode_textcache;
-  bool verbose;
-  bool recompile;
-  uint64_t min_traces;
-  std::shared_ptr<IExec> exec;
-  bool exclude_dex_files;
-
-  ControllerParameters(bool output_text,
-                       std::optional<std::string> inode_textcache,
-                       bool verbose,
-                       bool recompile,
-                       uint64_t min_traces,
-                       std::shared_ptr<IExec> exec,
-                       bool exclude_dex_files) :
-    output_text(output_text),
-    inode_textcache(inode_textcache),
-    verbose(verbose),
-    recompile(recompile),
-    min_traces(min_traces),
-    exec(exec),
-    exclude_dex_files(exclude_dex_files) {
-  }
-};
-
-// Control the compilation of perfetto traces in the sqlite db.
-//
-// The strategy now is to compile all the existing perfetto traces for an activity
-// and skip ones if the number of perfetto traces is less than the min_traces.
-//
-// By default, the program doesn't replace the existing compiled trace, it just
-// return true. To force replace the existing compiled trace, set `force` to true.
-//
-// The timestamp limit of the each perfetto trace is determined by `report_fully_drawn_ns`
-// timestamp. If it doesn't exists, use `total_time_ns`. If neither of them exists,
-// use the max.
-
-// Compile all activities of all packages in the database.
-bool Compile(const std::string& db_path, const ControllerParameters& params);
-
-// Compile all activities in the package.
-// If the version is not given, an arbitrary package that has the same name is used.
-bool Compile(const std::string& db_path,
-             const std::string& package_name,
-             int version,
-             const ControllerParameters& params);
-
-// Compile trace for the activity.
-// If the version is not given, an arbitrary package has the same name is used.
-bool Compile(const std::string& db_path,
-             const std::string& package_name,
-             const std::string& activity_name,
-             int version,
-             const ControllerParameters& params);
-// Visible for testing.
-bool CompileAppsOnDevice(const db::DbHandle& db, const ControllerParameters& params);
-
-bool CompileSingleAppOnDevice(const db::DbHandle& db,
-                              const ControllerParameters& params,
-                              const std::string& package_name);
-
-void Dump(const db::DbHandle& db, ::android::Printer& printer);
-
-} // iorap::maintenance
-
-#endif  // IORAP_SRC_MAINTENANCE_COMPILER_CONTROLLER_H_
diff --git a/src/maintenance/db_cleaner.cc b/src/maintenance/db_cleaner.cc
deleted file mode 100644
index 56eff70..0000000
--- a/src/maintenance/db_cleaner.cc
+++ /dev/null
@@ -1,66 +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 "maintenance/db_cleaner.h"
-
-#include <android-base/file.h>
-
-#include <cstdio>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <limits>
-#include <optional>
-#include <string>
-#include <vector>
-
-#include "db/clean_up.h"
-#include "db/file_models.h"
-#include "db/models.h"
-
-namespace iorap::maintenance {
-
-// Enable foreign key restriction.
-const constexpr char* kForeignKeyOnSql = "PRAGMA foreign_keys = ON;";
-
-void CleanUpDatabase(const db::DbHandle& db,
-                     std::shared_ptr<binder::PackageVersionMap> version_map) {
-  std::vector<db::PackageModel> packages = db::PackageModel::SelectAll(db);
-  // Enable cascade deletion.
-  if (!db::DbQueryBuilder::ExecuteOnce(db, kForeignKeyOnSql)) {
-    LOG(ERROR) << "Fail to turn on foreign key restraint!";
-  }
-
-  for (db::PackageModel package : packages) {
-    std::optional<int64_t> version = version_map->Find(package.name);
-    if (!version) {
-      LOG(DEBUG) << "Fail to find version for package " << package.name
-                 << " with version " << package.version
-                 << ". The package manager may be down.";
-      continue;
-    }
-    // Package is cleanup if it
-    // * is not in the version map, it may be uninstalled
-    // * has an different version with the latest one
-    if (*version != package.version) {
-      db::CleanUpFilesForPackage(db, package.id, package.name, package.version);
-      if (!package.Delete()) {
-        LOG(ERROR) << "Fail to delete package " << package.name
-                   << " with version " << package.version;
-      }
-    }
-  }
-}
-
-}  // namespace iorap::maintenance
diff --git a/src/maintenance/db_cleaner.h b/src/maintenance/db_cleaner.h
deleted file mode 100644
index 1168bd5..0000000
--- a/src/maintenance/db_cleaner.h
+++ /dev/null
@@ -1,34 +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.
-
-#ifndef IORAP_SRC_MAINTENANCE_VERSION_UPDATE_H_
-#define IORAP_SRC_MAINTENANCE_VERSION_UPDATE_H_
-
-#include <android/content/pm/IPackageManagerNative.h>
-
-#include <string>
-#include <vector>
-
-#include "binder/package_version_map.h"
-#include "db/file_models.h"
-
-namespace iorap::maintenance {
-
-// Clean up the database.
-// Remove all relevant data for old-version packages.
-void CleanUpDatabase(const db::DbHandle& db,
-                     std::shared_ptr<binder::PackageVersionMap> version_map);
-}  // namespace iorap::maintenance
-
-#endif  // IORAP_SRC_MAINTENANCE_VERSION_UPDATE_H_
diff --git a/src/maintenance/main.cc b/src/maintenance/main.cc
deleted file mode 100644
index 8b66069..0000000
--- a/src/maintenance/main.cc
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "common/debug.h"
-#include "compiler/compiler.h"
-#include "maintenance/controller.h"
-#include "db/clean_up.h"
-
-#include <android-base/parseint.h>
-#include <android-base/properties.h>
-#include <android-base/logging.h>
-
-#include <iostream>
-#include <optional>
-
-#if defined(IORAP_MAINTENANCE_MAIN)
-
-namespace iorap::maintenance {
-
-void Usage(char** argv) {
-  std::cerr << "Usage: " << argv[0] << " <path of sqlite db>" << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "  Compile the perfetto trace for an package and activity." << std::endl;
-  std::cerr << "  The info of perfetto trace is stored in the sqlite db." << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "  Optional flags:" << std::endl;
-  std::cerr << "    --package $,-p $           Package name." << std::endl;
-  std::cerr << "    --version $,-ve $          Package version." << std::endl;
-  std::cerr << "    --activity $,-a $          Activity name." << std::endl;
-  std::cerr << "    --inode-textcache $,-it $  Resolve inode->filename from textcache." << std::endl;
-  std::cerr << "    --help,-h                  Print this Usage." << std::endl;
-  std::cerr << "    --recompile,-r             Force re-compilation, which replace the existing compiled trace ." << std::endl;
-  std::cerr << "    --purge-package,-pp        Purge all files associated with a package." << std::endl;
-  std::cerr << "    --verbose,-v               Set verbosity (default off)." << std::endl;
-  std::cerr << "    --output-text,-ot          Output ascii text instead of protobuf (default off)." << std::endl;
-  std::cerr << "    --min_traces,-mt           The min number of perfetto traces needed "
-            << "for compilation (default 1)." << std::endl;
-  std::cerr << "    --exclude-dex-files,-edf   Set of exclude dex files" << std::endl;
-  exit(1);
-}
-
-
-int Main(int argc, char** argv){
-  android::base::InitLogging(argv);
-  android::base::SetLogger(android::base::StderrLogger);
-
-  if (argc == 1) {
-    // Need at least 1 input file to do anything.
-    Usage(argv);
-  }
-
-  std::vector<std::string> arg_input_filenames;
-  std::optional<std::string> arg_package;
-  std::optional<std::string> arg_purge_package;
-  int arg_version = -1;
-  std::optional<std::string> arg_activity;
-  std::optional<std::string> arg_inode_textcache;
-  bool recompile = false;
-  bool enable_verbose = false;
-  bool arg_output_text = false;
-  uint64_t arg_min_traces = 1;
-  bool exclude_dex_files = false;
-
-  for (int arg = 1; arg < argc; ++arg) {
-    std::string argstr = argv[arg];
-    bool has_arg_next = (arg+1)<argc;
-    std::string arg_next = has_arg_next ? argv[arg+1] : "";
-
-    if (argstr == "--help" || argstr == "-h") {
-      Usage(argv);
-    } else if (argstr == "--package" || argstr == "-p") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --package <value>" << std::endl;
-        return 1;
-      }
-      arg_package = arg_next;
-      ++arg;
-    } else if (argstr == "--version" || argstr == "-ve") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --version <value>" << std::endl;
-        return 1;
-      }
-      int version;
-      if (!android::base::ParseInt<int>(arg_next, &version)) {
-        std::cerr << "Invalid --version " << arg_next << std::endl;
-        return 1;
-      }
-      arg_version = version;
-      ++arg;
-    } else if (argstr == "--activity" || argstr == "-a") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --activity <value>" << std::endl;
-        return 1;
-      }
-      arg_activity = arg_next;
-      ++arg;
-    } else if (argstr == "--inode-textcache" || argstr == "-it") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --inode-textcache <value>" << std::endl;
-        return 1;
-      }
-      arg_inode_textcache = arg_next;
-      ++arg;
-    } else if (argstr == "--purge-package" || argstr == "-pp") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --purge-package <value>" << std::endl;
-        return 1;
-      }
-      arg_purge_package = arg_next;
-      ++arg;
-    } else if (argstr == "--verbose" || argstr == "-v") {
-      enable_verbose = true;
-    } else if (argstr == "--recompile" || argstr == "-r") {
-      recompile = true;
-    } else if (argstr == "--output-text" || argstr == "-ot") {
-      arg_output_text = true;
-    } else if (argstr == "--min_traces" || argstr == "-mt") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --min_traces <value>" << std::endl;
-        return 1;
-      }
-      arg_min_traces = std::stoul(arg_next);
-      ++arg;
-    } else if (argstr == "--exclude-dex-files" || argstr == "-edf") {
-      exclude_dex_files = true;
-    } else {
-      arg_input_filenames.push_back(argstr);
-    }
-  }
-
-  if (arg_input_filenames.empty()) {
-    LOG(ERROR) << "Missing filename to a sqlite database.";
-    Usage(argv);
-  } else if (arg_input_filenames.size() > 1) {
-    LOG(ERROR) << "More than one filename to a sqlite database.";
-    Usage(argv);
-  }
-
-  std::string db_path = arg_input_filenames[0];
-
-  if (enable_verbose) {
-    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
-
-    LOG(VERBOSE) << "Verbose check";
-    LOG(VERBOSE) << "Debug check: " << ::iorap::kIsDebugBuild;
-  } else {
-    android::base::SetMinimumLogSeverity(android::base::DEBUG);
-  }
-
-  if (arg_purge_package) {
-    db::CleanUpFilesForPackage(db_path, *arg_purge_package);
-    return 0;
-    // Don't do any more work because SchemaModel can only be created once.
-  }
-
-  maintenance::ControllerParameters params{
-    arg_output_text,
-    arg_inode_textcache,
-    enable_verbose,
-    recompile,
-    arg_min_traces,
-    std::make_shared<Exec>(),
-    exclude_dex_files};
-
-  int ret_code = 0;
-  if (arg_package && arg_activity) {
-    ret_code = !Compile(std::move(db_path),
-                        std::move(*arg_package),
-                        std::move(*arg_activity),
-                        arg_version,
-                        params);
-  } else if (arg_package) {
-    ret_code = !Compile(std::move(db_path), std::move(*arg_package), arg_version, params);
-  } else {
-    ret_code = !Compile(std::move(db_path), params);
-  }
-  return ret_code;
-}
-
-} // iorap::maintenance
-
-int main(int argc, char** argv) {
-  return ::iorap::maintenance::Main(argc, argv);
-}
-
-
-#endif  // IORAP_MAINTENANCE_MAIN
diff --git a/src/manager/event_manager.cc b/src/manager/event_manager.cc
deleted file mode 100644
index 0242c10..0000000
--- a/src/manager/event_manager.cc
+++ /dev/null
@@ -1,1401 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "binder/package_version_map.h"
-#include "common/debug.h"
-#include "common/expected.h"
-#include "common/printer.h"
-#include "common/rx_async.h"
-#include "common/property.h"
-#include "common/trace.h"
-#include "db/app_component_name.h"
-#include "db/file_models.h"
-#include "db/models.h"
-#include "maintenance/controller.h"
-#include "maintenance/db_cleaner.h"
-#include "manager/event_manager.h"
-#include "perfetto/rx_producer.h"
-#include "prefetcher/read_ahead.h"
-#include "prefetcher/task_id.h"
-
-#include <android-base/chrono_utils.h>
-#include <android-base/strings.h>
-#include <android-base/properties.h>
-#include <rxcpp/rx.hpp>
-#include <server_configurable_flags/get_flags.h>
-#include <utils/misc.h>
-#include <utils/Trace.h>
-
-#include <atomic>
-#include <filesystem>
-#include <functional>
-#include <type_traits>
-#include <unordered_map>
-
-using rxcpp::observe_on_one_worker;
-
-namespace iorap::manager {
-
-using binder::AppLaunchEvent;
-using binder::DexOptEvent;
-using binder::JobScheduledEvent;
-using binder::RequestId;
-using binder::TaskResult;
-
-using common::AsyncPool;
-using common::RxAsync;
-
-using perfetto::PerfettoStreamCommand;
-using perfetto::PerfettoTraceProto;
-
-using db::AppComponentName;
-
-const constexpr bool kExcludeDexFilesDefault = true;
-
-static std::atomic<bool> s_tracing_allowed{false};
-static std::atomic<bool> s_readahead_allowed{false};
-static std::atomic<uint64_t> s_min_traces{3};
-
-struct PackageBlacklister {
-  // "x.y.z;foo.bar.baz" colon-separated list of substrings
-  PackageBlacklister(std::string blacklist_string) {
-    LOG(VERBOSE) << "Configuring package blacklister with string: " << blacklist_string;
-
-    std::vector<std::string> split = ::android::base::Split(blacklist_string, ";");
-
-    // Ignore any l/r whitespace or empty strings.
-    for (const std::string& s : split) {
-      std::string t = ::android::base::Trim(s);
-      if (!t.empty()) {
-        LOG(INFO) << "Blacklisted package: " << t << "; will not optimize.";
-        packages_.push_back(t);
-      }
-    }
-  }
-
-  PackageBlacklister() = default;
-
-  bool IsBlacklisted(const std::string& package_name) const {
-    return std::find(packages_.begin(), packages_.end(), package_name) != packages_.end();
-  }
-
-  bool IsBlacklisted(const AppComponentName& component_name) const {
-    return IsBlacklisted(component_name.package);
-  }
-
-  bool IsBlacklisted(const std::optional<AppComponentName>& component_name) const {
-    return component_name.has_value() && IsBlacklisted(component_name->package);
-  }
-
- private:
-  std::vector<std::string> packages_;
-};
-
-using PackageVersionMap = std::unordered_map<std::string, int64_t>;
-
-// Main logic of the #OnAppLaunchEvent scan method.
-//
-// All functions are called from the same thread as the event manager
-// functions.
-//
-// This is a data type, it's moved (std::move) around from one iteration
-// of #scan to another.
-struct AppLaunchEventState {
-  std::optional<AppComponentName> component_name_;
-  // Sequence ID is shared amongst the same app launch sequence,
-  // but changes whenever a new app launch sequence begins.
-  size_t sequence_id_ = static_cast<size_t>(-1);
-  std::optional<AppLaunchEvent::Temperature> temperature_;
-
-  // Push data to perfetto rx chain for associating
-  // the raw_trace with the history_id.
-  std::optional<rxcpp::subscriber<int>> history_id_subscriber_;
-  rxcpp::observable<int> history_id_observable_;
-
-  std::optional<uint64_t> intent_started_ns_;
-  std::optional<uint64_t> total_time_ns_;
-
-  // Used by kReportFullyDrawn to find the right history_id.
-  // We assume no interleaving between different sequences.
-  // This assumption is checked in the Java service code.
-  std::optional<uint64_t> recent_history_id_;
-
-  // labeled as 'shared' due to rx not being able to handle move-only objects.
-  // lifetime: in practice equivalent to unique_ptr.
-  std::shared_ptr<prefetcher::ReadAhead> read_ahead_;
-  bool allowed_readahead_{true};
-  bool is_read_ahead_{false};
-  std::optional<prefetcher::TaskId> read_ahead_task_;
-
-  bool allowed_tracing_{true};
-  bool is_tracing_{false};
-  std::optional<rxcpp::composite_subscription> rx_lifetime_;
-  std::vector<rxcpp::composite_subscription> rx_in_flight_;
-
-  PackageBlacklister package_blacklister_{};
-
-  borrowed<perfetto::RxProducerFactory*> perfetto_factory_;  // not null
-  borrowed<observe_on_one_worker*> thread_;  // not null
-  borrowed<observe_on_one_worker*> io_thread_;  // not null
-  borrowed<AsyncPool*> async_pool_;  // not null
-
-  std::shared_ptr<binder::PackageVersionMap> version_map_;
-
-  explicit AppLaunchEventState(borrowed<perfetto::RxProducerFactory*> perfetto_factory,
-                               bool allowed_readahead,
-                               bool allowed_tracing,
-                               PackageBlacklister package_blacklister,
-                               borrowed<observe_on_one_worker*> thread,
-                               borrowed<observe_on_one_worker*> io_thread,
-                               borrowed<AsyncPool*> async_pool,
-                               std::shared_ptr<binder::PackageVersionMap> version_map)
-    : read_ahead_{std::make_shared<prefetcher::ReadAhead>()}
-  {
-    perfetto_factory_ = perfetto_factory;
-    DCHECK(perfetto_factory_ != nullptr);
-
-    allowed_readahead_ = allowed_readahead;
-    allowed_tracing_ = allowed_tracing;
-
-    package_blacklister_ = package_blacklister;
-
-    thread_ = thread;
-    DCHECK(thread_ != nullptr);
-
-    io_thread_ = io_thread;
-    DCHECK(io_thread_ != nullptr);
-
-    async_pool_ = async_pool;
-    DCHECK(async_pool_ != nullptr);
-
-    version_map_ = version_map;
-    DCHECK(version_map_ != nullptr);
-  }
-
-  // Updates the values in this struct only as a side effect.
-  //
-  // May create and fire a new rx chain on the same threads as passed
-  // in by the constructors.
-  void OnNewEvent(const AppLaunchEvent& event) {
-    LOG(VERBOSE) << "AppLaunchEventState#OnNewEvent: " << event;
-
-    android::ScopedTrace trace_db_init{ATRACE_TAG_ACTIVITY_MANAGER,
-                                       "IorapNativeService::OnAppLaunchEvent"};
-
-    using Type = AppLaunchEvent::Type;
-
-    DCHECK_GE(event.sequence_id, 0);
-    sequence_id_ = static_cast<size_t>(event.sequence_id);
-    allowed_readahead_ = s_readahead_allowed;
-    allowed_tracing_ = s_tracing_allowed;
-
-    switch (event.type) {
-      case Type::kIntentStarted: {
-        const std::string& package_name = event.intent_proto->component().package_name();
-        const std::string& class_name = event.intent_proto->component().class_name();
-        AppComponentName component_name{package_name, class_name};
-        component_name = component_name.Canonicalize();
-        component_name_ = component_name;
-
-        if (package_blacklister_.IsBlacklisted(component_name)) {
-          LOG(DEBUG) << "kIntentStarted: package " << component_name.package
-                     << " ignored due to blacklisting.";
-          break;
-        }
-
-        // Create a new history ID chain for each new app start-up sequence.
-        auto history_id_observable = rxcpp::observable<>::create<int>(
-          [&](rxcpp::subscriber<int> subscriber) {
-            history_id_subscriber_ = std::move(subscriber);
-            LOG(VERBOSE) << " set up the history id subscriber ";
-          })
-          .tap([](int history_id) { LOG(VERBOSE) << " tap rx history id = " << history_id; })
-          .replay(1);  // Remember the history id in case we subscribe too late.
-
-        history_id_observable_ = history_id_observable;
-
-        // Immediately turn observable hot, creating the subscriber.
-        history_id_observable.connect();
-
-        DCHECK(!IsTracing());
-
-        // The time should be set before perfetto tracing.
-        // Record the timestamp even no perfetto tracing is triggered,
-        // because the tracing may start in the following ActivityLaunched
-        // event. Otherwise, there will be no starting timestamp and
-        // trace without starting timestamp is not considered for compilation.
-        if (event.timestamp_nanos >= 0) {
-          intent_started_ns_ = event.timestamp_nanos;
-        } else {
-          LOG(WARNING) << "Negative event timestamp: " << event.timestamp_nanos;
-        }
-        break;
-      }
-      case Type::kIntentFailed:
-        if (package_blacklister_.IsBlacklisted(component_name_)) {
-          LOG(VERBOSE) << "kIntentFailed: package " << component_name_->package
-                       << " ignored due to blacklisting.";
-          break;
-        }
-
-        if (history_id_subscriber_) {
-          history_id_subscriber_->on_error(rxcpp::util::make_error_ptr(
-            std::ios_base::failure("Aborting due to intent failed")));
-          history_id_subscriber_ = std::nullopt;
-        }
-
-        break;
-      case Type::kActivityLaunched: {
-        // TODO add test in Android framework to verify this.
-        const std::string& title =
-            event.activity_record_proto->window_token().window_container().identifier().title();
-        if (!AppComponentName::HasAppComponentName(title)) {
-          // Proto comment claim this is sometimes a window title.
-          // We need the actual 'package/component' here, so just ignore it if it's a title.
-          LOG(WARNING) << "App launched without a component name: " << event;
-          break;
-        }
-
-        AppComponentName component_name = AppComponentName::FromString(title);
-        component_name = component_name.Canonicalize();
-        component_name_ = component_name;
-
-        if (package_blacklister_.IsBlacklisted(component_name_)) {
-          LOG(VERBOSE) << "kActivityLaunched: package " << component_name_->package
-                       << " ignored due to blacklisting.";
-          break;
-        }
-
-        // Cancel tracing for warm/hot.
-        // Restart tracing if the activity was unexpected.
-
-        AppLaunchEvent::Temperature temperature = event.temperature;
-        temperature_ = temperature;
-        if (temperature != AppLaunchEvent::Temperature::kCold) {
-          LOG(DEBUG) << "AppLaunchEventState#OnNewEvent don't trace due to non-cold temperature";
-        } else if (!IsTracing() && !IsReadAhead()) {  // and the temperature is Cold.
-          // Start late trace when intent didn't have a component name
-          LOG(VERBOSE) << "AppLaunchEventState#OnNewEvent need to start new trace";
-
-          if (allowed_readahead_ && !IsReadAhead()) {
-            StartReadAhead(sequence_id_, component_name);
-          }
-          if (allowed_tracing_ && !IsTracing() && !IsReadAhead()) {
-            rx_lifetime_ = StartTracing(std::move(component_name));
-          }
-        } else {
-          // FIXME: match actual component name against intent component name.
-          // abort traces if they don't match.
-
-          if (allowed_tracing_) {
-            LOG(VERBOSE) << "AppLaunchEventState#OnNewEvent already tracing";
-          }
-          LOG(VERBOSE) << "AppLaunchEventState#OnNewEvent already doing readahead";
-        }
-        break;
-      }
-      case Type::kActivityLaunchFinished:
-        if (package_blacklister_.IsBlacklisted(component_name_)) {
-          LOG(VERBOSE) << "kActivityLaunchFinished: package " << component_name_->package
-                       << " ignored due to blacklisting.";
-          break;
-        }
-
-        if (event.timestamp_nanos >= 0) {
-           total_time_ns_ = event.timestamp_nanos;
-        }
-        RecordDbLaunchHistory(event.activity_record_proto->proc_id());
-        // Finish tracing and collect trace buffer.
-        //
-        // TODO: this happens automatically when perfetto finishes its
-        // trace duration.
-        if (IsTracing()) {
-          MarkPendingTrace();
-        }
-        FinishReadAhead();
-        break;
-      case Type::kActivityLaunchCancelled:
-        if (package_blacklister_.IsBlacklisted(component_name_)) {
-          LOG(VERBOSE) << "kActivityLaunchCancelled: package " << component_name_->package
-                       << " ignored due to blacklisting.";
-          break;
-        }
-
-        // Abort tracing.
-        AbortTrace();
-        AbortReadAhead();
-        break;
-      case Type::kReportFullyDrawn: {
-        if (package_blacklister_.IsBlacklisted(component_name_)) {
-          LOG(VERBOSE) << "kReportFullyDrawn: package " << component_name_->package
-                       << " ignored due to blacklisting.";
-          break;
-        }
-
-        if (!recent_history_id_) {
-          LOG(WARNING) << "Dangling kReportFullyDrawn event";
-          return;
-        }
-        UpdateReportFullyDrawn(*recent_history_id_, event.timestamp_nanos);
-        recent_history_id_ = std::nullopt;
-        break;
-      }
-      default:
-        DCHECK(false) << "invalid type: " << event;  // binder layer should've rejected this.
-        LOG(ERROR) << "invalid type: " << event;  // binder layer should've rejected this.
-    }
-  }
-
-  // Is there an in-flight readahead task currently?
-  bool IsReadAhead() const {
-    return read_ahead_task_.has_value();
-  }
-
-  // Gets the compiled trace.
-  // If a compiled trace exists in sqlite, use that one. Otherwise, try
-  // to find a prebuilt one.
-  std::optional<std::string> GetCompiledTrace(const AppComponentName& component_name) {
-    ScopedFormatTrace atrace_get_compiled_trace(ATRACE_TAG_ACTIVITY_MANAGER, "GetCompiledTrace");
-    // Firstly, try to find the compiled trace from sqlite.
-    android::base::Timer timer{};
-    db::DbHandle db{db::SchemaModel::GetSingleton()};
-    std::optional<int> version =
-        version_map_->GetOrQueryPackageVersion(component_name.package);
-    if (!version) {
-      LOG(DEBUG) << "The version is NULL, maybe package manager is down.";
-      return std::nullopt;
-    }
-    db::VersionedComponentName vcn{component_name.package,
-                                   component_name.activity_name,
-                                   *version};
-
-    std::optional<db::PrefetchFileModel> compiled_trace =
-          db::PrefetchFileModel::SelectByVersionedComponentName(db, vcn);
-
-    std::chrono::milliseconds duration_ms = timer.duration();
-    LOG(DEBUG) << "EventManager: Looking up compiled trace done in "
-               << duration_ms.count() // the count of ticks.
-               << "ms.";
-
-    if (compiled_trace) {
-      if (std::filesystem::exists(compiled_trace->file_path)) {
-        return compiled_trace->file_path;
-      } else {
-        LOG(DEBUG) << "Compiled trace in sqlite doesn't exists. file_path: "
-                   << compiled_trace->file_path;
-      }
-    }
-
-    LOG(DEBUG) << "Cannot find compiled trace in sqlite for package_name: "
-               << component_name.package
-               << " activity_name: "
-               << component_name.activity_name;
-
-    // If sqlite doesn't have the compiled trace, try the prebuilt path.
-    std::string file_path = "/product/iorap-trace/";
-    file_path += component_name.ToMakeFileSafeEncodedPkgString();
-    file_path += ".compiled_trace.pb";
-
-    if (std::filesystem::exists(file_path)) {
-      return file_path;
-    }
-
-    LOG(DEBUG) << "Prebuilt compiled trace doesn't exists. file_path: "
-               << file_path;
-
-    return std::nullopt;
-  }
-
-  void StartReadAhead(size_t id, const AppComponentName& component_name) {
-    DCHECK(allowed_readahead_);
-    DCHECK(!IsReadAhead());
-
-    std::optional<std::string> file_path = GetCompiledTrace(component_name);
-    if (!file_path) {
-      LOG(VERBOSE) << "Cannot find a compiled trace.";
-      return;
-    }
-
-    prefetcher::TaskId task{id, *file_path};
-    read_ahead_->BeginTask(task);
-    // TODO: non-void return signature?
-
-    read_ahead_task_ = std::move(task);
-  }
-
-  void FinishReadAhead() {
-    // if no readahead task exist, do nothing.
-    if (!IsReadAhead()){
-      return;
-    }
-
-    read_ahead_->FinishTask(*read_ahead_task_);
-    read_ahead_task_ = std::nullopt;
-  }
-
-  void AbortReadAhead() {
-    FinishReadAhead();
-  }
-
-  bool IsTracing() const {
-    return is_tracing_;
-  }
-
-  std::optional<rxcpp::composite_subscription> StartTracing(
-      AppComponentName component_name) {
-    DCHECK(allowed_tracing_);
-    DCHECK(!IsTracing());
-
-    std::optional<int> version =
-        version_map_->GetOrQueryPackageVersion(component_name_->package);
-    if (!version) {
-      LOG(DEBUG) << "The version is NULL, maybe package manager is down.";
-      return std::nullopt;
-    }
-    db::VersionedComponentName versioned_component_name{component_name.package,
-                                                        component_name.activity_name,
-                                                        *version};
-    db::DbHandle db{db::SchemaModel::GetSingleton()};
-    {
-      ScopedFormatTrace atrace_traces_number_check(
-          ATRACE_TAG_ACTIVITY_MANAGER, "IorapNativeService::CheckPerfettoTracesNnumber");
-      // Just return if we have enough perfetto traces.
-      if (!db::PerfettoTraceFileModel::NeedMorePerfettoTraces(
-          db, versioned_component_name)) {
-        return std::nullopt;
-      }
-    }
-
-    auto /*observable<PerfettoStreamCommand>*/ perfetto_commands =
-      rxcpp::observable<>::just(PerfettoStreamCommand::kStartTracing)
-          // wait 1x
-          .concat(
-              // Pick a value longer than the perfetto config delay_ms, so that we send
-              // 'kShutdown' after tracing has already finished.
-              rxcpp::observable<>::interval(std::chrono::milliseconds(10000))
-                  .take(2)  // kStopTracing, kShutdown.
-                  .map([](int value) {
-                         // value is 1,2,3,...
-                         return static_cast<PerfettoStreamCommand>(value);  // 1,2, ...
-                       })
-          );
-
-    auto /*observable<PerfettoTraceProto>*/ trace_proto_stream =
-        perfetto_factory_->CreateTraceStream(perfetto_commands);
-    // This immediately connects to perfetto asynchronously.
-    //
-    // TODO: create a perfetto handle earlier, to minimize perfetto startup latency.
-
-    rxcpp::composite_subscription lifetime;
-
-    auto stream_via_threads = trace_proto_stream
-      .tap([](const PerfettoTraceProto& trace_proto) {
-             LOG(VERBOSE) << "StartTracing -- PerfettoTraceProto received (1)";
-           })
-      .combine_latest(history_id_observable_)
-      .observe_on(*thread_)   // All work prior to 'observe_on' is handled on thread_.
-      .subscribe_on(*thread_)   // All work prior to 'observe_on' is handled on thread_.
-      .observe_on(*io_thread_)  // Write data on an idle-class-priority thread.
-      .tap([](std::tuple<PerfettoTraceProto, int> trace_tuple) {
-             LOG(VERBOSE) << "StartTracing -- PerfettoTraceProto received (2)";
-           });
-
-   lifetime = RxAsync::SubscribeAsync(*async_pool_,
-        std::move(stream_via_threads),
-        /*on_next*/[versioned_component_name]
-        (std::tuple<PerfettoTraceProto, int> trace_tuple) {
-          PerfettoTraceProto& trace_proto = std::get<0>(trace_tuple);
-          int history_id = std::get<1>(trace_tuple);
-
-          db::PerfettoTraceFileModel file_model =
-            db::PerfettoTraceFileModel::CalculateNewestFilePath(versioned_component_name);
-
-          std::string file_path = file_model.FilePath();
-
-          ScopedFormatTrace atrace_write_to_file(ATRACE_TAG_ACTIVITY_MANAGER,
-                                                 "Perfetto Write Trace To File %s",
-                                                 file_path.c_str());
-
-          if (!file_model.MkdirWithParents()) {
-            LOG(ERROR) << "Cannot save TraceBuffer; failed to mkdirs " << file_path;
-            return;
-          }
-
-          if (!trace_proto.WriteFullyToFile(file_path)) {
-            LOG(ERROR) << "Failed to save TraceBuffer to " << file_path;
-          } else {
-            LOG(INFO) << "Perfetto TraceBuffer saved to file: " << file_path;
-
-            ScopedFormatTrace atrace_update_raw_traces_table(
-                ATRACE_TAG_ACTIVITY_MANAGER,
-                "update raw_traces table history_id = %d",
-                history_id);
-            db::DbHandle db{db::SchemaModel::GetSingleton()};
-            std::optional<db::RawTraceModel> raw_trace =
-                db::RawTraceModel::Insert(db, history_id, file_path);
-
-            if (!raw_trace) {
-              LOG(ERROR) << "Failed to insert raw_traces for " << file_path;
-            } else {
-              LOG(VERBOSE) << "Inserted into db: " << *raw_trace;
-            }
-          }
-        },
-        /*on_error*/[](rxcpp::util::error_ptr err) {
-          LOG(ERROR) << "Perfetto trace proto collection error: " << rxcpp::util::what(err);
-        });
-
-    is_tracing_ = true;
-
-    return lifetime;
-  }
-
-  void AbortTrace() {
-    LOG(VERBOSE) << "AppLaunchEventState - AbortTrace";
-
-    // if the tracing is not running, do nothing.
-    if (!IsTracing()){
-      return;
-    }
-
-    is_tracing_ = false;
-    if (rx_lifetime_) {
-      // TODO: it would be good to call perfetto Destroy.
-
-      rx_in_flight_.erase(std::remove(rx_in_flight_.begin(),
-                                      rx_in_flight_.end(), *rx_lifetime_),
-                          rx_in_flight_.end());
-
-      LOG(VERBOSE) << "AppLaunchEventState - AbortTrace - Unsubscribe";
-      rx_lifetime_->unsubscribe();
-
-      rx_lifetime_.reset();
-    }
-  }
-
-  void MarkPendingTrace() {
-    LOG(VERBOSE) << "AppLaunchEventState - MarkPendingTrace";
-    DCHECK(is_tracing_);
-    DCHECK(rx_lifetime_.has_value());
-
-    if (rx_lifetime_) {
-      LOG(VERBOSE) << "AppLaunchEventState - MarkPendingTrace - lifetime moved";
-      // Don't unsubscribe because that would cause the perfetto TraceBuffer
-      // to get dropped on the floor.
-      //
-      // Instead, we want to let it finish and write it out to a file.
-      rx_in_flight_.push_back(*std::move(rx_lifetime_));
-      rx_lifetime_.reset();
-    } else {
-      LOG(VERBOSE) << "AppLaunchEventState - MarkPendingTrace - lifetime was empty";
-    }
-
-    is_tracing_ = false;
-    // FIXME: how do we clear this vector?
-  }
-
-  void RecordDbLaunchHistory(int32_t pid) {
-    std::optional<db::AppLaunchHistoryModel> history = InsertDbLaunchHistory(pid);
-
-    // RecordDbLaunchHistory happens-after kIntentStarted
-    if (!history_id_subscriber_.has_value()) {
-      LOG(WARNING) << "Logic error? Should always have a subscriber here.";
-      return;
-    }
-
-    // Ensure that the history id rx chain is terminated either with an error or with
-    // the newly inserted app_launch_histories.id
-    if (!history) {
-      history_id_subscriber_->on_error(rxcpp::util::make_error_ptr(
-          std::ios_base::failure("Failed to insert history id")));
-      recent_history_id_ = std::nullopt;
-    } else {
-      // Note: we must have already subscribed, or this value will disappear.
-      LOG(VERBOSE) << "history_id_subscriber on_next history_id=" << history->id;
-      history_id_subscriber_->on_next(history->id);
-      history_id_subscriber_->on_completed();
-
-      recent_history_id_ = history->id;
-    }
-    history_id_subscriber_ = std::nullopt;
-  }
-
-  std::optional<db::AppLaunchHistoryModel> InsertDbLaunchHistory(int32_t pid) {
-    // TODO: deferred queue into a different lower priority thread.
-    if (!component_name_ || !temperature_) {
-      LOG(VERBOSE) << "Skip RecordDbLaunchHistory, no component name available.";
-
-      return std::nullopt;
-    }
-
-    android::ScopedTrace trace{ATRACE_TAG_ACTIVITY_MANAGER,
-                               "IorapNativeService::RecordDbLaunchHistory"};
-    db::DbHandle db{db::SchemaModel::GetSingleton()};
-
-    using namespace iorap::db;
-
-    std::optional<int> version =
-        version_map_->GetOrQueryPackageVersion(component_name_->package);
-    if (!version) {
-      LOG(DEBUG) << "The version is NULL, maybe package manager is down.";
-      return std::nullopt;
-    }
-    std::optional<ActivityModel> activity =
-        ActivityModel::SelectOrInsert(db,
-                                      component_name_->package,
-                                      *version,
-                                      component_name_->activity_name);
-
-    if (!activity) {
-      LOG(WARNING) << "Failed to query activity row for : " << *component_name_;
-      return std::nullopt;
-    }
-
-    auto temp = static_cast<db::AppLaunchHistoryModel::Temperature>(*temperature_);
-
-    std::optional<AppLaunchHistoryModel> alh =
-        AppLaunchHistoryModel::Insert(db,
-                                      activity->id,
-                                      temp,
-                                      IsTracing(),
-                                      IsReadAhead(),
-                                      intent_started_ns_,
-                                      total_time_ns_,
-                                      // ReportFullyDrawn event normally occurs after this. Need update later.
-                                      /* report_fully_drawn_ns= */ std::nullopt,
-                                      pid);
-    //Repo
-    if (!alh) {
-      LOG(WARNING) << "Failed to insert app_launch_histories row";
-      return std::nullopt;
-    }
-
-    LOG(VERBOSE) << "RecordDbLaunchHistory: " << *alh;
-    return alh;
-  }
-
-  void UpdateReportFullyDrawn(int history_id, uint64_t timestamp_ns) {
-    LOG(DEBUG) << "Update kReportFullyDrawn for history_id:"
-               << history_id
-               << " timestamp_ns: "
-               << timestamp_ns;
-
-    android::ScopedTrace trace{ATRACE_TAG_ACTIVITY_MANAGER,
-                               "IorapNativeService::UpdateReportFullyDrawn"};
-    db::DbHandle db{db::SchemaModel::GetSingleton()};
-
-    bool result =
-        db::AppLaunchHistoryModel::UpdateReportFullyDrawn(db,
-                                                          history_id,
-                                                          timestamp_ns);
-
-    if (!result) {
-      LOG(WARNING) << "Failed to update app_launch_histories row";
-    }
-  }
-};
-
-struct AppLaunchEventDefender {
-  binder::AppLaunchEvent::Type last_event_type_{binder::AppLaunchEvent::Type::kUninitialized};
-
-  enum class Result {
-    kAccept,      // Pass-through the new event.
-    kOverwrite,   // Overwrite the new event with a different event.
-    kReject       // Completely reject the new event, it will not be delivered.
-  };
-
-  Result OnAppLaunchEvent(binder::RequestId request_id,
-                          const binder::AppLaunchEvent& event,
-                          binder::AppLaunchEvent* overwrite) {
-    using Type = binder::AppLaunchEvent::Type;
-    CHECK(overwrite != nullptr);
-
-    // Ensure only legal transitions are allowed.
-    switch (last_event_type_) {
-      case Type::kUninitialized:
-      case Type::kIntentFailed:
-      case Type::kActivityLaunchCancelled:
-      case Type::kReportFullyDrawn: {  // From a terminal state, only go to kIntentStarted
-        if (event.type != Type::kIntentStarted) {
-          LOG(DEBUG) << "Rejecting transition from " << last_event_type_ << " to " << event.type;
-          last_event_type_ = Type::kUninitialized;
-          return Result::kReject;
-        } else {
-          LOG(VERBOSE) << "Accept transition from " << last_event_type_ << " to " << event.type;
-          last_event_type_ = event.type;
-          return Result::kAccept;
-        }
-      }
-      case Type::kIntentStarted: {
-        if (event.type == Type::kIntentFailed ||
-            event.type == Type::kActivityLaunched) {
-          LOG(VERBOSE) << "Accept transition from " << last_event_type_ << " to " << event.type;
-          last_event_type_ = event.type;
-          return Result::kAccept;
-        } else {
-          LOG(DEBUG) << "Overwriting transition from kIntentStarted to "
-                       << event.type << " into kIntentFailed";
-          last_event_type_ = Type::kIntentFailed;
-
-          *overwrite = event;
-          overwrite->type = Type::kIntentFailed;
-          return Result::kOverwrite;
-        }
-      }
-      case Type::kActivityLaunched: {
-        if (event.type == Type::kActivityLaunchFinished ||
-            event.type == Type::kActivityLaunchCancelled) {
-          LOG(VERBOSE) << "Accept transition from " << last_event_type_ << " to " << event.type;
-          last_event_type_ = event.type;
-          return Result::kAccept;
-        } else {
-          LOG(DEBUG) << "Overwriting transition from kActivityLaunched to "
-                       << event.type << " into kActivityLaunchCancelled";
-          last_event_type_ = Type::kActivityLaunchCancelled;
-
-          *overwrite = event;
-          overwrite->type = Type::kActivityLaunchCancelled;
-          return Result::kOverwrite;
-        }
-      }
-      case Type::kActivityLaunchFinished: {
-        if (event.type == Type::kIntentStarted ||
-            event.type == Type::kReportFullyDrawn) {
-          LOG(VERBOSE) << "Accept transition from " << last_event_type_ << " to " << event.type;
-          last_event_type_ = event.type;
-          return Result::kAccept;
-        } else {
-          LOG(DEBUG) << "Rejecting transition from " << last_event_type_ << " to " << event.type;
-          last_event_type_ = Type::kUninitialized;
-          return Result::kReject;
-        }
-      }
-    }
-  }
-};
-
-// Convert callback pattern into reactive pattern.
-struct AppLaunchEventSubject {
-  using RefWrapper =
-    std::reference_wrapper<const AppLaunchEvent>;
-
-  AppLaunchEventSubject() {}
-
-  void Subscribe(rxcpp::subscriber<RefWrapper> subscriber) {
-    DCHECK(ready_ != true) << "Cannot Subscribe twice";
-
-    subscriber_ = std::move(subscriber);
-
-    // Release edge of synchronizes-with AcquireIsReady.
-    ready_.store(true);
-  }
-
-  void OnNext(const AppLaunchEvent& e) {
-    if (!AcquireIsReady()) {
-      return;
-    }
-
-    if (!subscriber_->is_subscribed()) {
-      return;
-    }
-
-    /*
-     * TODO: fix upstream.
-     *
-     * Rx workaround: this fails to compile when
-     * the observable is a reference type:
-     *
-     * external/Reactive-Extensions/RxCpp/Rx/v2/src/rxcpp/rx-observer.hpp:354:18: error: multiple overloads of 'on_next' instantiate to the same signature 'void (const iorap::binder::AppLaunchEvent &) const'
-     *   virtual void on_next(T&&) const {};
-     *
-     * external/Reactive-Extensions/RxCpp/Rx/v2/src/rxcpp/rx-observer.hpp:353:18: note: previous declaration is here
-     *   virtual void on_next(T&) const {};
-     *
-     * (The workaround is to use reference_wrapper instead
-     *  of const AppLaunchEvent&)
-     */
-    subscriber_->on_next(std::cref(e));
-
-  }
-
-  void OnCompleted() {
-    if (!AcquireIsReady()) {
-      return;
-    }
-
-    subscriber_->on_completed();
-  }
-
- private:
-  bool AcquireIsReady() {
-    // Synchronizes-with the release-edge in Subscribe.
-    // This can happen much later, only once the subscription actually happens.
-
-    // However, as far as I know, 'rxcpp::subscriber' is not thread safe,
-    // (but the observable chain itself can be made thread-safe via #observe_on, etc).
-    // so we must avoid reading it until it has been fully synchronized.
-    //
-    // TODO: investigate rxcpp subscribers and see if we can get rid of this atomics,
-    // to make it simpler.
-    return ready_.load();
-  }
-
-  // TODO: also track the RequestId ?
-
-  std::atomic<bool> ready_{false};
-
-
-  std::optional<rxcpp::subscriber<RefWrapper>> subscriber_;
-};
-
-// Convert callback pattern into reactive pattern.
-struct JobScheduledEventSubject {
-  JobScheduledEventSubject() {}
-
-  void Subscribe(rxcpp::subscriber<std::pair<RequestId, JobScheduledEvent>> subscriber) {
-    DCHECK(ready_ != true) << "Cannot Subscribe twice";
-
-    subscriber_ = std::move(subscriber);
-
-    // Release edge of synchronizes-with AcquireIsReady.
-    ready_.store(true);
-  }
-
-  void OnNext(RequestId request_id, JobScheduledEvent e) {
-    if (!AcquireIsReady()) {
-      return;
-    }
-
-    if (!subscriber_->is_subscribed()) {
-      return;
-    }
-
-    subscriber_->on_next(std::pair<RequestId, JobScheduledEvent>{std::move(request_id), std::move(e)});
-
-  }
-
-  void OnCompleted() {
-    if (!AcquireIsReady()) {
-      return;
-    }
-
-    subscriber_->on_completed();
-  }
-
- private:
-  bool AcquireIsReady() {
-    // Synchronizes-with the release-edge in Subscribe.
-    // This can happen much later, only once the subscription actually happens.
-
-    // However, as far as I know, 'rxcpp::subscriber' is not thread safe,
-    // (but the observable chain itself can be made thread-safe via #observe_on, etc).
-    // so we must avoid reading it until it has been fully synchronized.
-    //
-    // TODO: investigate rxcpp subscribers and see if we can get rid of this atomics,
-    // to make it simpler.
-    return ready_.load();
-  }
-
-  // TODO: also track the RequestId ?
-
-  std::atomic<bool> ready_{false};
-
-  std::optional<rxcpp::subscriber<std::pair<RequestId, JobScheduledEvent>>> subscriber_;
-};
-
-std::ostream& operator<<(std::ostream& os, const android::content::pm::PackageChangeEvent& event) {
-  os << "PackageChangeEvent{";
-  os << "packageName=" << event.packageName << ",";
-  os << "version=" << event.version << ",";
-  os << "lastUpdateTimeMillis=" << event.lastUpdateTimeMillis;
-  os << "}";
-  return os;
-}
-
-class EventManager::Impl {
- public:
-  Impl(/*borrow*/perfetto::RxProducerFactory& perfetto_factory)
-    : perfetto_factory_(perfetto_factory),
-      worker_thread_(rxcpp::observe_on_new_thread()),
-      worker_thread2_(rxcpp::observe_on_new_thread()),
-      io_thread_(perfetto::ObserveOnNewIoThread()) {
-    // Try to create version map
-    RetryCreateVersionMap();
-
-    iorap::common::StderrLogPrinter printer{"iorapd"};
-    RefreshSystemProperties(printer);
-
-    rx_lifetime_ = InitializeRxGraph();
-    rx_lifetime_jobs_ = InitializeRxGraphForJobScheduledEvents();
-
-    android::add_sysprop_change_callback(&Impl::OnSyspropChanged, /*priority*/-10000);
-  }
-
-  void RetryCreateVersionMap() {
-    android::base::Timer timer{};
-    version_map_ = binder::PackageVersionMap::Create();
-    std::chrono::milliseconds duration_ms = timer.duration();
-    LOG(DEBUG) << "Got versions for "
-               << version_map_->Size()
-               << " packages in "
-               << duration_ms.count()
-               << "ms";
-  }
-
-  void SetTaskResultCallbacks(std::shared_ptr<TaskResultCallbacks> callbacks) {
-    DCHECK(callbacks_.expired());
-    callbacks_ = callbacks;
-  }
-
-  void Join() {
-    async_pool_.Join();
-  }
-
-  bool OnAppLaunchEvent(RequestId request_id,
-                        const AppLaunchEvent& event) {
-    LOG(VERBOSE) << "EventManager::OnAppLaunchEvent("
-                 << "request_id=" << request_id.request_id << ","
-                 << event;
-
-    // Filter any incoming events through a defender that enforces
-    // that all state transitions are as contractually documented in
-    // ActivityMetricsLaunchObserver's javadoc.
-    AppLaunchEvent overwrite_event{};
-    AppLaunchEventDefender::Result result =
-        app_launch_event_defender_.OnAppLaunchEvent(request_id, event, /*out*/&overwrite_event);
-
-    switch (result) {
-      case AppLaunchEventDefender::Result::kAccept:
-        app_launch_event_subject_.OnNext(event);
-        return true;
-      case AppLaunchEventDefender::Result::kOverwrite:
-        app_launch_event_subject_.OnNext(overwrite_event);
-        return false;
-      case AppLaunchEventDefender::Result::kReject:
-        // Intentionally left-empty: we drop the event completely.
-        return false;
-    }
-
-    // In theory returns BAD_VALUE to the other side of this binder connection.
-    // In practice we use 'oneway' flags so this doesn't matter on a regular build.
-    return false;
-  }
-
-  bool OnDexOptEvent(RequestId request_id,
-                     const DexOptEvent& event) {
-    LOG(VERBOSE) << "EventManager::OnDexOptEvent("
-                 << "request_id=" << request_id.request_id << ","
-                 << event.package_name
-                 << ")";
-
-    if (common::ExcludeDexFiles(kExcludeDexFilesDefault)) {
-      LOG(VERBOSE) << "Dex files are excluded. Skip the purging.";
-      return true;
-    }
-    return PurgePackage(event.package_name);
-  }
-
-  bool OnJobScheduledEvent(RequestId request_id,
-                           const JobScheduledEvent& event) {
-    LOG(VERBOSE) << "EventManager::OnJobScheduledEvent("
-                 << "request_id=" << request_id.request_id << ",event=TODO).";
-
-    job_scheduled_event_subject_.OnNext(std::move(request_id), event);
-
-    return true;  // No errors.
-  }
-
-  bool OnPackageChanged(const android::content::pm::PackageChangeEvent& event) {
-    LOG(DEBUG) << "Received " << event;
-    if (event.isDeleted) {
-      // Do nothing if the package is deleted rignt now.
-      // The package will be removed from db during maintenance.
-      return true;
-    }
-    // Update the version map.
-    if (version_map_->Update(event.packageName, event.version)) {
-      return true;
-    }
-
-    // Sometimes a package is updated without any version change.
-    // Clean it up in this case.
-    db::DbHandle db{db::SchemaModel::GetSingleton()};
-    db::CleanUpFilesForPackage(db, event.packageName, event.version);
-    return true;
-  }
-
-  void Dump(/*borrow*/::android::Printer& printer) {
-    ::iorap::prefetcher::ReadAhead::Dump(printer);
-    ::iorap::perfetto::PerfettoConsumerImpl::Dump(/*borrow*/printer);
-    ::iorap::maintenance::Dump(db::SchemaModel::GetSingleton(), printer);
-  }
-
-  rxcpp::composite_subscription InitializeRxGraph() {
-    LOG(VERBOSE) << "EventManager::InitializeRxGraph";
-
-    app_launch_events_ = rxcpp::observable<>::create<AppLaunchEventRefWrapper>(
-      [&](rxcpp::subscriber<AppLaunchEventRefWrapper> subscriber) {
-        app_launch_event_subject_.Subscribe(std::move(subscriber));
-      });
-
-    rxcpp::composite_subscription lifetime;
-
-    if (!tracing_allowed_) {
-      LOG(WARNING) << "Tracing disabled by system property";
-    }
-    if (!readahead_allowed_) {
-      LOG(WARNING) << "Readahead disabled by system property";
-    }
-
-    AppLaunchEventState initial_state{&perfetto_factory_,
-                                      readahead_allowed_,
-                                      tracing_allowed_,
-                                      package_blacklister_,
-                                      &worker_thread2_,
-                                      &io_thread_,
-                                      &async_pool_,
-                                      version_map_};
-    app_launch_events_
-      .subscribe_on(worker_thread_)
-      .scan(std::move(initial_state),
-            [](AppLaunchEventState state, AppLaunchEventRefWrapper event) {
-              state.OnNewEvent(event.get());
-              return state;
-            })
-      .subscribe(/*out*/lifetime, [](const AppLaunchEventState& state) {
-                   // Intentionally left blank.
-                   (void)state;
-                 });
-
-    return lifetime;
-  }
-
-  // Runs the maintenance code to compile perfetto traces to compiled
-  // trace for a package.
-  void StartMaintenance(bool output_text,
-                        std::optional<std::string> inode_textcache,
-                        bool verbose,
-                        bool recompile,
-                        uint64_t min_traces,
-                        std::string package_name,
-                        bool should_update_versions) {
-    ScopedFormatTrace atrace_bg_scope(ATRACE_TAG_PACKAGE_MANAGER,
-                                      "Background Job Scope");
-
-    db::DbHandle db{db::SchemaModel::GetSingleton()};
-    if (should_update_versions) {
-      {
-        ScopedFormatTrace atrace_update_versions(ATRACE_TAG_PACKAGE_MANAGER,
-                                                 "Update package versions map cache");
-        // Update the version map.
-        version_map_->UpdateAll();
-      }
-
-      {
-        ScopedFormatTrace atrace_cleanup_db(ATRACE_TAG_PACKAGE_MANAGER,
-                                            "Clean up obsolete data in database");
-        // Cleanup the obsolete data in the database.
-        maintenance::CleanUpDatabase(db, version_map_);
-      }
-    }
-
-    {
-      ScopedFormatTrace atrace_compile_apps(ATRACE_TAG_PACKAGE_MANAGER,
-                                            "Compile apps on device");
-      // Compilation
-      maintenance::ControllerParameters params{
-        output_text,
-        inode_textcache,
-        verbose,
-        recompile,
-        min_traces,
-        std::make_shared<maintenance::Exec>(),
-        common::ExcludeDexFiles(kExcludeDexFilesDefault)};
-
-      LOG(DEBUG) << "StartMaintenance: min_traces=" << min_traces;
-      maintenance::CompileSingleAppOnDevice(db, params, package_name);
-    }
-  }
-
-  rxcpp::composite_subscription InitializeRxGraphForJobScheduledEvents() {
-    LOG(VERBOSE) << "EventManager::InitializeRxGraphForJobScheduledEvents";
-
-    using RequestAndJobEvent = std::pair<RequestId, JobScheduledEvent>;
-
-    job_scheduled_events_ = rxcpp::observable<>::create<RequestAndJobEvent>(
-      [&](rxcpp::subscriber<RequestAndJobEvent> subscriber) {
-        job_scheduled_event_subject_.Subscribe(std::move(subscriber));
-      });
-
-    rxcpp::composite_subscription lifetime;
-
-    job_scheduled_events_
-      .observe_on(worker_thread_)  // async handling.
-      .tap([this](const RequestAndJobEvent& e) {
-        LOG(VERBOSE) << "EventManager#JobScheduledEvent#tap(1) - job begins";
-        this->NotifyProgress(e.first, TaskResult{TaskResult::State::kBegan});
-
-        LOG(VERBOSE) << "Compile " << std::get<1>(e).package_name;
-        StartMaintenance(/*output_text=*/false,
-                         /*inode_textcache=*/std::nullopt,
-                         /*verbose=*/false,
-                         /*recompile=*/false,
-                         s_min_traces,
-                         std::get<1>(e).package_name,
-                         std::get<1>(e).should_update_versions);
-
-        // TODO: probably this shouldn't be emitted until most of the usual DCHECKs
-        // (for example, validate a job isn't already started, the request is not reused, etc).
-        // In this way we could block from the client until it sees 'kBegan' and Log.wtf otherwise.
-      })
-      .tap([](const RequestAndJobEvent& e) {
-        // TODO. Actual work.
-        LOG(VERBOSE) << "EventManager#JobScheduledEvent#tap(2) - job is being processed";
-
-        // TODO: abort functionality for in-flight jobs.
-        //
-        // maybe something like scan that returns an observable<Job> + flat map to that job.
-        // then we could unsubscribe from the scan to do a partial abort? need to try it and see if it works.
-        //
-        // other option is to create a new outer subscription for each job id which seems less ideal.
-      })
-      .subscribe(/*out*/lifetime,
-        /*on_next*/
-        [this](const RequestAndJobEvent& e) {
-          LOG(VERBOSE) << "EventManager#JobScheduledEvent#subscribe - job completed";
-          this->NotifyComplete(e.first, TaskResult{TaskResult::State::kCompleted});
-        }
-#if 0
-        ,
-        /*on_error*/
-        [](rxcpp::util::error_ptr err) {
-          LOG(ERROR) << "Scheduled job event failed: " << rxcpp::util::what(err);
-
-          //std::shared_ptr<TaskResultCallbacks> callbacks = callbacks_.lock();
-          //if (callbacks != nullptr) {
-            // FIXME: How do we get the request ID back out of the error? Seems like a problem.
-            // callbacks->OnComplete(, TaskResult{TaskResult::kError});
-            // We may have to wrap with an iorap::expected instead of using on_error.
-          //}
-
-          // FIXME: need to add a 'OnErrorResumeNext' operator?
-          DCHECK(false) << "forgot to implement OnErrorResumeNext";
-        }
-#endif
-      );
-
-    // TODO: error output should happen via an observable.
-
-    return lifetime;
-  }
-
-  void NotifyComplete(RequestId request_id, TaskResult result) {
-      std::shared_ptr<TaskResultCallbacks> callbacks = callbacks_.lock();
-      if (callbacks != nullptr) {
-        callbacks->OnComplete(std::move(request_id), std::move(result));
-      } else {
-        LOG(WARNING) << "EventManager: TaskResultCallbacks may have been released early";
-      }
-  }
-
-  void NotifyProgress(RequestId request_id, TaskResult result) {
-      std::shared_ptr<TaskResultCallbacks> callbacks = callbacks_.lock();
-      if (callbacks != nullptr) {
-        callbacks->OnProgress(std::move(request_id), std::move(result));
-      } else {
-        LOG(WARNING) << "EventManager: TaskResultCallbacks may have been released early";
-      }
-  }
-
-  static void OnSyspropChanged() {
-    LOG(DEBUG) << "OnSyspropChanged";
-  }
-
-  void RefreshSystemProperties(::android::Printer& printer) {
-    // TODO: read all properties from one config class.
-    // PH properties do not work if they contain ".". "_" was instead used here.
-    tracing_allowed_ = common::IsTracingEnabled(/*default_value=*/"false");
-    s_tracing_allowed = tracing_allowed_;
-    printer.printFormatLine("iorapd.perfetto.enable = %s", tracing_allowed_ ? "true" : "false");
-
-    readahead_allowed_ = common::IsReadAheadEnabled(/*default_value=*/"false");
-    s_readahead_allowed = readahead_allowed_;
-    printer.printFormatLine("iorapd.readahead.enable = %s", s_readahead_allowed ? "true" : "false");
-
-    s_min_traces =
-        ::android::base::GetUintProperty<uint64_t>("iorapd.maintenance.min_traces", /*default*/1);
-    uint64_t min_traces = s_min_traces;
-    printer.printFormatLine("iorapd.maintenance.min_traces = %" PRIu64, min_traces);
-
-    printer.printFormatLine("iorapd.exclude_dex_files = %s",
-                            common::ExcludeDexFiles(kExcludeDexFilesDefault) ? "true" : "false");
-
-    package_blacklister_ = PackageBlacklister{
-        /* Colon-separated string list of blacklisted packages, e.g.
-         * "foo.bar.baz;com.fake.name" would blacklist {"foo.bar.baz", "com.fake.name"} packages.
-         *
-         * Blacklisted packages are ignored by iorapd.
-         */
-        server_configurable_flags::GetServerConfigurableFlag(
-            common::ph_namespace,
-            "iorap_blacklisted_packages",
-            ::android::base::GetProperty("iorapd.blacklist_packages",
-                                         /*default*/""))
-    };
-
-    LOG(DEBUG) << "RefreshSystemProperties";
-  }
-
-  bool PurgePackage(::android::Printer& printer, const std::string& package_name) {
-    (void)printer;
-    return PurgePackage(package_name);
-  }
-
-  bool PurgePackage(const std::string& package_name) {
-    db::DbHandle db{db::SchemaModel::GetSingleton()};
-    db::CleanUpFilesForPackage(db, package_name);
-    LOG(DEBUG) << "PurgePackage: " << package_name;
-    return true;
-  }
-
-  bool CompilePackage(::android::Printer& printer, const std::string& package_name) {
-    (void)printer;
-
-    ScopedFormatTrace atrace_compile_app(ATRACE_TAG_PACKAGE_MANAGER,
-                                         "Compile one app on device");
-
-    maintenance::ControllerParameters params{
-      /*output_text*/false,
-      /*inode_textcache*/std::nullopt,
-      WOULD_LOG(VERBOSE),
-      /*recompile*/false,
-      s_min_traces,
-      std::make_shared<maintenance::Exec>(),
-      common::ExcludeDexFiles(kExcludeDexFilesDefault)};
-
-    db::DbHandle db{db::SchemaModel::GetSingleton()};
-    bool res = maintenance::CompileSingleAppOnDevice(db, std::move(params), package_name);
-    LOG(DEBUG) << "CompilePackage: " << package_name;
-
-    return res;
-  }
-
-  bool readahead_allowed_{true};
-
-  perfetto::RxProducerFactory& perfetto_factory_;
-  bool tracing_allowed_{true};
-
-  PackageBlacklister package_blacklister_{};
-
-  std::weak_ptr<TaskResultCallbacks> callbacks_;  // avoid cycles with weakptr.
-
-  using AppLaunchEventRefWrapper = AppLaunchEventSubject::RefWrapper;
-  rxcpp::observable<AppLaunchEventRefWrapper> app_launch_events_;
-  AppLaunchEventSubject app_launch_event_subject_;
-  AppLaunchEventDefender app_launch_event_defender_;
-
-  rxcpp::observable<std::pair<RequestId, JobScheduledEvent>> job_scheduled_events_;
-  JobScheduledEventSubject job_scheduled_event_subject_;
-
-  rxcpp::observable<RequestId> completed_requests_;
-
-  // regular-priority thread to handle binder callbacks.
-  observe_on_one_worker worker_thread_;
-  observe_on_one_worker worker_thread2_;
-  // low priority idle-class thread for IO operations.
-  observe_on_one_worker io_thread_;
-  // async futures pool for async rx operations.
-  AsyncPool async_pool_;
-
-  rxcpp::composite_subscription rx_lifetime_;  // app launch events
-  rxcpp::composite_subscription rx_lifetime_jobs_;  // job scheduled events
-
-  // package version map
-  std::shared_ptr<binder::PackageVersionMap> version_map_;
-
-//INTENTIONAL_COMPILER_ERROR_HERE:
-  // FIXME:
-  // ok so we want to expose a 'BlockingSubscribe' or a 'Subscribe' or some kind of function
-  // that the main thread can call. This would subscribe on all the observables we internally
-  // have here (probably on an event-manager-dedicated thread for simplicity).
-  //
-  // ideally we'd just reuse the binder thread to handle the events but I'm not super sure,
-  // maybe this already works with the identity_current_thread coordination?
-};
-using Impl = EventManager::Impl;
-
-EventManager::EventManager(perfetto::RxProducerFactory& perfetto_factory)
-    : impl_(new Impl(perfetto_factory)) {}
-
-std::shared_ptr<EventManager> EventManager::Create() {
-  static perfetto::PerfettoDependencies::Injector injector{
-    perfetto::PerfettoDependencies::CreateComponent
-  };
-  static perfetto::RxProducerFactory producer_factory{
-    /*borrow*/injector
-  };
-  return EventManager::Create(/*borrow*/producer_factory);
-}
-
-std::shared_ptr<EventManager> EventManager::Create(perfetto::RxProducerFactory& perfetto_factory) {
-  std::shared_ptr<EventManager> p{new EventManager{/*borrow*/perfetto_factory}};
-  return p;
-}
-
-void EventManager::SetTaskResultCallbacks(std::shared_ptr<TaskResultCallbacks> callbacks) {
-  return impl_->SetTaskResultCallbacks(std::move(callbacks));
-}
-
-void EventManager::Join() {
-  return impl_->Join();
-}
-
-bool EventManager::OnAppLaunchEvent(RequestId request_id,
-                                    const AppLaunchEvent& event) {
-  return impl_->OnAppLaunchEvent(request_id, event);
-}
-
-bool EventManager::OnDexOptEvent(RequestId request_id,
-                                 const DexOptEvent& event) {
-  return impl_->OnDexOptEvent(request_id, event);
-}
-
-bool EventManager::OnJobScheduledEvent(RequestId request_id,
-                                       const JobScheduledEvent& event) {
-  return impl_->OnJobScheduledEvent(request_id, event);
-}
-
-bool EventManager::OnPackageChanged(const android::content::pm::PackageChangeEvent& event) {
-  return impl_->OnPackageChanged(event);
-}
-
-void EventManager::Dump(/*borrow*/::android::Printer& printer) {
-  return impl_->Dump(printer);
-}
-
-void EventManager::RefreshSystemProperties(::android::Printer& printer) {
-  return impl_->RefreshSystemProperties(printer);
-}
-
-bool EventManager::PurgePackage(::android::Printer& printer, const std::string& package_name) {
-  return impl_->PurgePackage(printer, package_name);
-}
-
-bool EventManager::CompilePackage(::android::Printer& printer, const std::string& package_name) {
-  return impl_->CompilePackage(printer, package_name);
-}
-
-}  // namespace iorap::manager
diff --git a/src/manager/event_manager.h b/src/manager/event_manager.h
deleted file mode 100644
index fa09eec..0000000
--- a/src/manager/event_manager.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IORAP_MANAGER_EVENT_MANAGER_H_
-#define IORAP_MANAGER_EVENT_MANAGER_H_
-
-#include "binder/app_launch_event.h"
-#include "binder/dexopt_event.h"
-#include "binder/job_scheduled_event.h"
-#include "binder/request_id.h"
-#include "binder/task_result.h"
-
-#include <android/content/pm/PackageChangeEvent.h>
-
-#include <memory>
-
-namespace android {
-class Printer;
-}  // namespace android
-
-namespace iorap::perfetto {
-struct RxProducerFactory;
-}  // namespace iorap::perfetto
-
-namespace iorap::manager {
-
-// These callbacks are invoked by the EventManager to provide asynchronous notification for the status
-// of an event handler.
-//
-// Calling 'On_Event' in EventManager should be considered merely to start the task.
-// Calling 'OnComplete' here is considered to terminate the request (either with a success or error).
-// OnProgress is optional, but if it is called it must be called prior to 'OnComplete'.
-//
-// All callbacks for the same request-id are sequentially consistent.
-class TaskResultCallbacks {
- public:
-  virtual void OnProgress(iorap::binder::RequestId request_id, iorap::binder::TaskResult task_result) {}
-  virtual void OnComplete(iorap::binder::RequestId request_id, iorap::binder::TaskResult task_result) {}
-
-  virtual ~TaskResultCallbacks() {}
-};
-
-class EventManager {
- public:
-  static std::shared_ptr<EventManager> Create();
-  static std::shared_ptr<EventManager> Create(
-      /*borrow*/perfetto::RxProducerFactory& perfetto_factory);
-  void SetTaskResultCallbacks(std::shared_ptr<TaskResultCallbacks> callbacks);
-
-  // Joins any background threads created by EventManager.
-  void Join();
-
-  // Handles an AppLaunchEvent:
-  //
-  // * Intent starts and app launch starts are treated critically
-  //   and will be handled immediately. This means the caller
-  //   (e.g. the binder pool thread) could be starved in the name
-  //   of low latency.
-  //
-  // * Other types are handled in a separate thread.
-  bool OnAppLaunchEvent(binder::RequestId request_id,
-                        const binder::AppLaunchEvent& event);
-
-  // Handles a DexOptEvent:
-  //
-  // Clean up the invalidate traces after package is updated by dexopt.
-  bool OnDexOptEvent(binder::RequestId request_id,
-                     const binder::DexOptEvent& event);
-
-
-  // Handles a JobScheduledEvent:
-  //
-  // * Start/stop background jobs (typically for idle maintenance).
-  // * For example, this could kick off a background compiler.
-  bool OnJobScheduledEvent(binder::RequestId request_id,
-                           const binder::JobScheduledEvent& event);
-
-  // Handles a PackageChangeEvent:
-  //
-  // * The package manager service send this event for package install
-  //   update or delete.
-  bool OnPackageChanged(const android::content::pm::PackageChangeEvent& event);
-
-  // Print to adb shell dumpsys (for bugreport info).
-  void Dump(/*borrow*/::android::Printer& printer);
-
-  // A dumpsys --refresh-properties command signaling that we should
-  // refresh our system properties.
-  void RefreshSystemProperties(::android::Printer& printer);
-
-  // A dumpsys --purge-package <name> command signaling
-  // that all db rows and files associated with a package should be deleted.
-  bool PurgePackage(::android::Printer& printer, const std::string& package_name);
-
-  // A dumpsys --compile-package <name> command signaling
-  // that a package should be recompiled.
-  bool CompilePackage(::android::Printer& printer, const std::string& package_name);
-
-  class Impl;
- private:
-  std::unique_ptr<Impl> impl_;
-
-  EventManager(perfetto::RxProducerFactory& perfetto_factory);
-};
-
-}  // namespace iorap::manager
-
-#endif  // IORAP_MANAGER_EVENT_MANAGER_H_
diff --git a/src/perfetto/main.cc b/src/perfetto/main.cc
deleted file mode 100644
index 0b1056e..0000000
--- a/src/perfetto/main.cc
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//#undef NDEBUG // get DCHECK etc.
-
-
-#include "common/debug.h"
-#include "common/expected.h"
-#include "perfetto/rx_producer.h"
-
-#include <android-base/unique_fd.h>
-#include <android-base/parseint.h>
-#include <android-base/file.h>
-
-#include "rxcpp/rx.hpp"
-#include <iostream>
-#include <optional>
-
-#include <sched.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <syscall.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-using namespace iorap::perfetto;  // NOLINT
-
-#if defined(IORAP_PERFETTO_MAIN)
-
-void Usage(char** argv) {
-  std::cerr << "Usage: " << argv[0] << " [--config-proto=config.pb] [--duration-ms=5000] [--output-proto=output.pb]" << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "  Request a perfetto trace, blocking until it's complete. The resulting trace proto" << std::endl;
-  std::cerr << "  is output to stdout as text, or to --output-proto as a binary." << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "  Optional flags:" << std::endl;
-  std::cerr << "    --help,-h                  Print this Usage." << std::endl;
-  std::cerr << "    --output-proto $,-op $     Perfetto tracebuffer output file (default stdout)." << std::endl;
-  std::cerr << "    --config-proto $,-cp $     Path to binary protobuf config." << std::endl;
-  std::cerr << "    --duration-ms $,-dm $      How long to run trace for in milliseconds." << std::endl;
-  std::cerr << "    --simple                   Simplest possible perfetto state transitions (default off)." << std::endl;
-  std::cerr << "    --verbose,-v               Set verbosity (default off)." << std::endl;
-  std::cerr << "    --wait,-w                  Wait for key stroke before continuing (default off)." << std::endl;
-  exit(1);
-}
-
-PerfettoDependencies::Component CreateCommandLinePerfettoDependenciesComponent(
-    uint32_t duration_ms) {
-  // TODO: read from command line.
-  static const uint32_t kBufferSize = 4096;
-
-  // TODO: remove this hack.
-  static const uint32_t kTraceDurationMs = duration_ms;
-
-  // fruit: using 'bindInstance' causes a segfault every time.
-#if 0
-
-  // fruit: Can't use a stateful lambda, so use bindInstance instead of registerProvider.
-  auto config = PerfettoDependencies::CreateConfig(duration_ms,
-                                                   /*deferred_start*/true,
-                                                   kBufferSize);
-
-  .... bindInstance(config);
-#endif
-
-  return fruit::createComponent()
-    .bind<PerfettoConsumer, PerfettoConsumerImpl>()
-    .registerProvider([]() /* -> TraceConfig */ {
-        return PerfettoDependencies::CreateConfig(kTraceDurationMs,
-                                                  /*deferred_start*/true,
-                                                  kBufferSize);
-    });
-}
-
-static void CollectPerfettoTraceBufferViaAbstractions(
-    RxProducerFactory& producer_factory,
-    const std::string& arg_output_proto,
-    const int arg_duration_ms) {
-  LOG(VERBOSE) << "CollectPerfettoTraceBufferViaAbstractions";
-
-  // Don't create a subscriber to emit the PerfettoStreamCommand.
-  // RxCpp is "greedy" and consumes every possible item emitted (it doesn't support 'pull'). We want
-  // to operate on a (command,state) iteration every time, just like in a real scenario.
-  // Adding the 'interval' turns into a non-greedy version (i.e. push).
-
-  // Immediately emit 'kStartTracing', wait and emit kStopTracing, wait and emit kShutdown.
-  // In reality, there would be a delay between all these events.
-  auto /*observable<PerfettoStreamCommand>*/ commands =
-      rxcpp::observable<>::just(PerfettoStreamCommand::kStartTracing)
-          // wait 1x
-          .concat(
-              // Pick a value longer than the perfetto config delay_ms, so that we send
-              // 'kShutdown' after tracing has already finished.
-              rxcpp::observable<>::interval(std::chrono::milliseconds(arg_duration_ms * 2))
-                  .take(2)  // kStopTracing, kShutdown.
-                  .map([](int value) {
-                         // value is 1,2,3,...
-                         return static_cast<PerfettoStreamCommand>(value);  // 1,2, ...
-                       })
-          );
-
-  auto /*observable<PerfettoTraceProto>*/ trace_proto_stream =
-      producer_factory.CreateTraceStream(commands);
-
-  trace_proto_stream
-    .observe_on(ObserveOnNewIoThread())  // Write data on an idle-class-priority thread.
-    .as_blocking()  // Wait for observable to terminate with on_completed or on_error.
-    .subscribe(/*on_next*/[arg_output_proto]
-      (PerfettoTraceProto trace_proto) {
-             if (!trace_proto.WriteFullyToFile(arg_output_proto)) {
-               LOG(ERROR) << "Failed to save TraceBuffer to " << arg_output_proto;
-             } else {
-               LOG(INFO) << "TraceBuffer saved to file: " << arg_output_proto;
-               LOG(INFO);
-               LOG(INFO) << "To print this in a human readable form, execute these commands:";
-               LOG(INFO) << "$> adb pull '" << arg_output_proto << "'";
-               LOG(INFO) << "$> trace_to_text systrace <filename.pb>";
-             }
-      },
-      /*on_error*/[](rxcpp::util::error_ptr err) {
-        LOG(ERROR) << "Perfetto trace proto collection error: " << rxcpp::util::what(err);
-      });
-}
-
-namespace iorap::perfetto {
-// Reach inside rx_producer.cc
-// Not part of any headers because it's internal.
-void CollectPerfettoTraceBufferImmediately(
-    RxProducerFactory& producer_factory,
-    const std::string& arg_output_proto);
-}
-
-int main(int argc, char** argv) {
-  android::base::InitLogging(argv);
-  android::base::SetLogger(android::base::StderrLogger);
-
-  bool wait_for_keystroke = false;
-  bool enable_verbose = false;
-
-  std::string arg_output_proto;
-  std::string arg_config_proto;
-  uint32_t arg_duration_ms = 1000;
-  bool arg_simple = false;
-
-  if (argc == 1) {
-    Usage(argv);
-  }
-
-  for (int arg = 1; arg < argc; ++arg) {
-    std::string argstr = argv[arg];
-    bool has_arg_next = (arg+1)<argc;
-    std::string arg_next = has_arg_next ? argv[arg+1] : "";
-
-    if (argstr == "--help" || argstr == "-h") {
-      Usage(argv);
-    } else if (argstr == "--output-proto" || argstr == "-op") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --output-proto <value>" << std::endl;
-        return 1;
-      }
-      arg_output_proto = arg_next;
-      ++arg;
-    } else if (argstr == "--config-proto" || argstr == "-cp") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --config-proto <value>" << std::endl;
-        return 1;
-      }
-      arg_config_proto = arg_next;
-      LOG(WARNING) << "TODO: parse configs from a file, not implemented yet.";
-      ++arg;
-    } else if (argstr == "--duration-ms" || argstr == "-dm") {
-      if (!has_arg_next) {
-        std::cerr << "Missing --duration-ms <value>" << std::endl;
-        return 1;
-      }
-      if (!android::base::ParseUint(arg_next.c_str(), /*out*/&arg_duration_ms)) {
-        std::cerr << "Invalid --duration-ms " << arg_next << ", reason: " << strerror(errno);
-        return 1;
-      }
-      ++arg;
-    } else if (argstr == "--simple") {
-      arg_simple = true;
-    } else if (argstr == "--verbose" || argstr == "-v") {
-      enable_verbose = true;
-    } else if (argstr == "--wait" || argstr == "-w") {
-      wait_for_keystroke = true;
-    }
-  }
-
-  if (enable_verbose) {
-    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
-
-    LOG(VERBOSE) << "Verbose check";
-    LOG(VERBOSE) << "Debug check: " << ::iorap::kIsDebugBuild;
-  }
-
-  // Useful to attach a debugger...
-  // 1) $> iorap-cmd-perfetto -w <args>
-  // 2) $> gdbclient <pid>
-  if (wait_for_keystroke) {
-    LOG(INFO) << "Self pid: " << getpid();
-    LOG(INFO) << "Press any key to continue...";
-    std::cin >> wait_for_keystroke;
-  }
-
-  int return_code = 0;
-  // TODO: convert #on-error into a non-0 return code.
-
-  PerfettoDependencies::Injector injector{
-      CreateCommandLinePerfettoDependenciesComponent,
-      arg_duration_ms
-  };
-  RxProducerFactory rx_producer_factory{/*borrow*/injector};
-
-  if (arg_simple) {
-    // To debug any kind of low-level perfetto issues.
-    CollectPerfettoTraceBufferImmediately(/*inout*/rx_producer_factory, arg_output_proto);
-  } else {
-    // To debug our own iorap internal abstractions.
-    CollectPerfettoTraceBufferViaAbstractions(/*inout*/rx_producer_factory,
-                                              arg_output_proto,
-                                              arg_duration_ms);
-  }
-
-  // Uncomment this if we want to leave the process around to inspect it from adb shell.
-  // sleep(100000);
-
-  // 0 -> successfully wrote the TraceProto out to file.
-  // 1 -> failed along the way (#on_error and also see the error logs).
-  return return_code;
-}
-
-#endif
diff --git a/src/perfetto/perfetto_consumer.cc b/src/perfetto/perfetto_consumer.cc
deleted file mode 100644
index 4fe677b..0000000
--- a/src/perfetto/perfetto_consumer.cc
+++ /dev/null
@@ -1,608 +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 "perfetto/perfetto_consumer.h"
-
-#include "common/trace.h"
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <utils/Looper.h>
-#include <utils/Printer.h>
-
-#include <limits>
-#include <map>
-#include <memory>
-#include <mutex>
-#include <sstream>
-#include <vector>
-
-#include <inttypes.h>
-#include <time.h>
-
-namespace iorap::perfetto {
-
-using State = PerfettoConsumer::State;
-using Handle = PerfettoConsumer::Handle;
-static constexpr Handle kInvalidHandle = PerfettoConsumer::kInvalidHandle;
-using OnStateChangedCb = PerfettoConsumer::OnStateChangedCb;
-using TraceBuffer = PerfettoConsumer::TraceBuffer;
-
-enum class StateKind {
-  kUncreated,
-  kCreated,
-  kStartedTracing,
-  kReadTracing,
-  kTimedOutDestroyed,  // same as kDestroyed but timed out.
-  kDestroyed,          // calling kDestroyed before timing out.
-};
-
-std::ostream& operator<<(std::ostream& os, StateKind kind) {
-  switch (kind) {
-    case StateKind::kUncreated:
-      os << "kUncreated";
-      break;
-    case StateKind::kCreated:
-      os << "kCreated";
-      break;
-    case StateKind::kStartedTracing:
-      os << "kStartedTracing";
-      break;
-    case StateKind::kReadTracing:
-      os << "kReadTracing";
-      break;
-    case StateKind::kTimedOutDestroyed:
-      os << "kTimedOutDestroyed";
-      break;
-    case StateKind::kDestroyed:
-      os << "kDestroyed";
-      break;
-    default:
-      os << "(invalid)";
-      break;
-  }
-  return os;
-}
-
-std::string ToString(StateKind kind) {
-  std::stringstream ss;
-  ss << kind;
-  return ss.str();
-}
-
-static constexpr uint64_t kSecToNano = 1000000000LL;
-
-static uint64_t GetTimeNanoseconds() {
-  struct timespec now;
-  clock_gettime(CLOCK_REALTIME, &now);
-
-  uint64_t now_ns = (now.tv_sec * kSecToNano + now.tv_nsec);
-  return now_ns;
-}
-
-// Describe the state of our handle in detail for debugging/logging.
-struct HandleDescription {
-  Handle handle_;
-  StateKind kind_{StateKind::kUncreated};  // Our state. required for correctness.
-  OnStateChangedCb callback_{nullptr};  // Required for Destroy callbacks.
-  void* callback_arg_{nullptr};
-
-  // For dumping to logs:
-  State state_{State::kSessionNotFound};  // perfetto state
-  std::optional<uint64_t> started_tracing_ns_; // when StartedTracing last called.
-  std::optional<uint64_t> read_trace_ns_;  // When ReadTrace last called.
-  std::uint64_t last_transition_ns_{0};
-  std::optional<uint64_t> trace_cookie_;  // atrace beginning at StartTracing.
-  bool trace_ended_{false};               // atrace ending at ReadTrace or Destroy.
-
-  HandleDescription(Handle handle): handle_(handle) {}
-};
-
-// pimpl idiom to hide the implementation details from header
-//
-// Track and verify that our perfetto usage is sane.
-struct PerfettoConsumerImpl::Impl {
-  Impl() : raw_{new PerfettoConsumerRawImpl{}},
-      message_handler_{new TraceMessageHandler{this}} {
-    std::thread watchdog_thread{ [this]() {
-      ::android::sp<::android::Looper> looper;
-      {
-        std::lock_guard<std::mutex> guard{looper_mutex_};
-        looper = ::android::Looper::prepare(/*opts*/0);
-        looper_ = looper;
-      }
-
-      static constexpr int kTimeoutMillis = std::numeric_limits<int>::max();
-
-      while (true) {
-        // Execute any pending callbacks, otherwise just block forever.
-        int result = looper->pollAll(kTimeoutMillis);
-
-        if (result == ::android::Looper::POLL_ERROR) {
-          LOG(ERROR) << "PerfettoConsumerImpl::Looper got a POLL_ERROR";
-        } else {
-          LOG(DEBUG) << "PerfettoConsumerImpl::Looper result was " << result;
-        }
-      }
-    }};
-
-    // Let thread run freely on its own.
-    watchdog_thread.detach();
-
-    // Block until looper_ is prepared.
-    while (true) {
-      std::lock_guard<std::mutex> guard{looper_mutex_};
-      if (looper_ != nullptr) {
-        break;
-      }
-    }
-  }
-
- private:
-  std::unique_ptr<PerfettoConsumerRawImpl> raw_;
-  std::map<Handle, HandleDescription> states_;
-
-  // We need this to be a counter to avoid memory leaks.
-  Handle last_created_{0};
-  Handle last_destroyed_{0};
-  uint64_t trace_cookie_{0};
-
-  std::mutex mutex_;  // Guard above values.
-
-  ::android::sp<::android::Looper> looper_;
-  std::mutex looper_mutex_;  // Guard looper_.
-
-  struct TraceMessageHandler : public ::android::MessageHandler {
-    TraceMessageHandler(Impl* impl) : impl_{impl} {
-      CHECK(impl != nullptr);
-    }
-
-    Impl* impl_;
-
-    virtual void handleMessage(const ::android::Message& message) override {
-      impl_->OnTraceMessage(static_cast<Handle>(message.what));
-    }
-  };
-
-  ::android::sp<TraceMessageHandler> message_handler_;
-
- public:
-  Handle Create(const void* config_proto,
-                size_t config_len,
-                OnStateChangedCb callback,
-                void* callback_arg) {
-    LOG(VERBOSE) << "PerfettoConsumer::Create("
-                 << "config_len=" << config_len << ")";
-    Handle handle = raw_->Create(config_proto, config_len, callback, callback_arg);
-
-    std::lock_guard<std::mutex> guard{mutex_};
-
-    // Assume every Handle starts at 0 and then increments by 1 every Create.
-    ++last_created_;
-    CHECK_EQ(last_created_, handle) << "perfetto handle had unexpected behavior.";
-    // Without this^ increment-by-1 behavior our detection of untracked state values is broken.
-    // If we have to, we can go with Untracked=Uncreated|Destroyed but it's better to distinguish
-    // the two if possible.
-
-    HandleDescription handle_desc{handle};
-    handle_desc.handle_ = handle;
-    handle_desc.callback_ = callback;
-    handle_desc.callback_arg_ = callback_arg;
-    UpdateHandleDescription(/*inout*/&handle_desc, StateKind::kCreated);
-
-    // assume we never wrap around due to using int64
-    bool inserted = states_.insert({handle, handle_desc}).second;
-    CHECK(inserted) << "perfetto handle was re-used: " << handle;
-
-    return handle;
-  }
-
-  void StartTracing(Handle handle) {
-    LOG(DEBUG) << "PerfettoConsumer::StartTracing(handle=" << handle << ")";
-
-    uint64_t trace_cookie;
-    {
-      std::lock_guard<std::mutex> guard{mutex_};
-
-      auto it = states_.find(handle);
-      if (it == states_.end()) {
-        LOG(ERROR) << "Cannot StartTracing(" << handle << "), untracked handle";
-        return;
-      }
-      HandleDescription& handle_desc = it->second;
-
-      raw_->StartTracing(handle);
-      UpdateHandleDescription(/*inout*/&handle_desc, StateKind::kStartedTracing);
-    }
-
-    // Use a looper here to add a timeout and immediately destroy the trace buffer.
-    CHECK_LE(static_cast<int64_t>(handle), static_cast<int64_t>(std::numeric_limits<int>::max()));
-    int message_code = static_cast<int>(handle);
-    ::android::Message message{message_code};
-
-    std::lock_guard<std::mutex> looper_guard{looper_mutex_};
-    looper_->sendMessageDelayed(static_cast<nsecs_t>(GetPropertyTraceTimeoutNs()),
-                                message_handler_,
-                                message);
-  }
-
-  TraceBuffer ReadTrace(Handle handle) {
-    LOG(DEBUG) << "PerfettoConsumer::ReadTrace(handle=" << handle << ")";
-
-    std::lock_guard<std::mutex> guard{mutex_};
-
-    auto it = states_.find(handle);
-    if (it == states_.end()) {
-      LOG(ERROR) << "Cannot ReadTrace(" << handle << "), untracked handle";
-      return TraceBuffer{};
-    }
-
-    HandleDescription& handle_desc = it->second;
-
-    TraceBuffer trace_buffer = raw_->ReadTrace(handle);
-    UpdateHandleDescription(/*inout*/&handle_desc, StateKind::kReadTracing);
-
-    return trace_buffer;
-  }
-
-  void Destroy(Handle handle) {
-    HandleDescription handle_desc{handle};
-    TryDestroy(handle, /*do_destroy*/true, /*out*/&handle_desc);;
-  }
-
-  bool TryDestroy(Handle handle, bool do_destroy, /*out*/HandleDescription* handle_desc_out) {
-    CHECK(handle_desc_out != nullptr);
-
-    LOG(VERBOSE) << "PerfettoConsumer::Destroy(handle=" << handle << ")";
-
-    std::lock_guard<std::mutex> guard{mutex_};
-
-    auto it = states_.find(handle);
-    if (it == states_.end()) {
-      // Leniency for calling Destroy multiple times. It's not a mistake.
-      LOG(ERROR) << "Cannot Destroy(" << handle << "), untracked handle";
-      return false;
-    }
-
-    HandleDescription& handle_desc = it->second;
-
-    if (do_destroy) {
-      raw_->Destroy(handle);
-    }
-    UpdateHandleDescription(/*inout*/&handle_desc, StateKind::kDestroyed);
-
-    *handle_desc_out = handle_desc;
-
-    // No longer track this handle to avoid memory leaks.
-    last_destroyed_ = handle;
-    states_.erase(it);
-
-    return true;
-  }
-
-  State PollState(Handle handle) {
-    // Just pass-through the call, we never use it directly anyway.
-    return raw_->PollState(handle);
-  }
-
-  // Either fetch or infer the current handle state from a handle.
-  // Meant for debugging/logging only.
-  HandleDescription GetOrInferHandleDescription(Handle handle) {
-    std::lock_guard<std::mutex> guard{mutex_};
-
-    auto it = states_.find(handle);
-    if (it == states_.end()) {
-      HandleDescription state{handle};
-      // If it's untracked it hasn't been created yet, or it was already destroyed.
-      if (IsDestroyed(handle)) {
-        UpdateHandleDescription(/*inout*/&state, StateKind::kDestroyed);
-      } else {
-        if (!IsUncreated(handle)) {
-          LOG(WARNING) << "bad state detection";
-        }
-        UpdateHandleDescription(/*inout*/&state, StateKind::kUncreated);
-      }
-      return state;
-    }
-    return it->second;
-  }
-
-  void OnTraceMessage(Handle handle) {
-    LOG(VERBOSE) << "OnTraceMessage(" << static_cast<int64_t>(handle) << ")";
-    HandleDescription handle_desc{handle};
-    {
-      std::lock_guard<std::mutex> guard{mutex_};
-
-      auto it = states_.find(handle);
-      if (it == states_.end()) {
-        // Handle values are never re-used, so we can simply ignore the message here
-        // instead of having to remove it from the message queue.
-        LOG(VERBOSE) << "OnTraceMessage(" << static_cast<int64_t>(handle)
-                     << ") no longer tracked handle";
-        return;
-      }
-      handle_desc = it->second;
-    }
-
-    // First check. Has this trace been active for too long?
-    uint64_t now_ns = GetTimeNanoseconds();
-    if (handle_desc.kind_ == StateKind::kStartedTracing) {
-      // Ignore other kinds of traces because they don't exhaust perfetto resources.
-      CHECK(handle_desc.started_tracing_ns_.has_value()) << static_cast<int64_t>(handle);
-
-      uint64_t started_tracing_ns = *handle_desc.started_tracing_ns_;
-
-      if ((now_ns - started_tracing_ns) > GetPropertyTraceTimeoutNs()) {
-        LOG(WARNING) << "Perfetto Handle timed out after " << (now_ns - started_tracing_ns) << "ns"
-                     << ", forcibly destroying";
-
-        // Let the callback handler call Destroy.
-        handle_desc.callback_(handle, State::kTraceFailed, handle_desc.callback_arg_);
-      }
-    }
-
-    // Second check. Are there too many traces now? Cull the old traces.
-    std::vector<HandleDescription> handle_list;
-    do {
-      std::lock_guard<std::mutex> guard{mutex_};
-
-      size_t max_trace_count = GetPropertyMaxTraceCount();
-      if (states_.size() > max_trace_count) {
-        size_t overflow_count = states_.size() - max_trace_count;
-        LOG(WARNING) << "Too many perfetto handles, overflowed by " << overflow_count
-                     << ", pruning down to " << max_trace_count;
-      } else {
-        break;
-      }
-
-      size_t prune_count = states_.size() - max_trace_count;
-      auto it = states_.begin();
-      for (size_t i = 0; i < prune_count; ++i) {
-        // Simply prune by handle 1,2,3,4...
-        // We could do better with a timestamp if we wanted to.
-        ++it;
-        handle_list.push_back(it->second);
-      }
-    } while (false);
-
-    for (HandleDescription& handle_desc : handle_list) {
-      LOG(DEBUG) << "Perfetto handle pruned: " << static_cast<int64_t>(handle);
-
-      // Let the callback handler call Destroy.
-      handle_desc.callback_(handle, State::kTraceFailed, handle_desc.callback_arg_);
-    }
-  }
-
- private:
-  static uint64_t GetPropertyTraceTimeoutNs() {
-    static uint64_t value =                       // property is timeout in seconds
-        ::android::base::GetUintProperty<uint64_t>("iorapd.perfetto.timeout", /*default*/10);
-    return value * kSecToNano;
-  }
-
-  static size_t GetPropertyMaxTraceCount() {
-    static size_t value =
-        ::android::base::GetUintProperty<size_t>("iorapd.perfetto.max_traces", /*default*/5);
-    return value;
-  }
-
-  void UpdateHandleDescription(/*inout*/HandleDescription* handle_desc, StateKind kind) {
-    CHECK(handle_desc != nullptr);
-    handle_desc->kind_ = kind;
-    handle_desc->state_ = raw_->PollState(handle_desc->handle_);
-
-    handle_desc->last_transition_ns_ = GetTimeNanoseconds();
-    if (kind == StateKind::kStartedTracing) {
-      if (!handle_desc->started_tracing_ns_) {
-        handle_desc->started_tracing_ns_ = handle_desc->last_transition_ns_;
-
-        handle_desc->trace_cookie_ = ++trace_cookie_;
-
-        atrace_async_begin(ATRACE_TAG_ACTIVITY_MANAGER,
-                           "Perfetto Scoped Trace",
-                           *handle_desc->trace_cookie_);
-        atrace_int(ATRACE_TAG_ACTIVITY_MANAGER,
-                   "Perfetto::Trace Handle",
-                   static_cast<int32_t>(handle_desc->handle_));
-      }
-    }
-
-    if (kind == StateKind::kReadTracing) {
-      if (!handle_desc->read_trace_ns_) {
-        handle_desc->read_trace_ns_ = handle_desc->last_transition_ns_;
-
-        if (handle_desc->trace_cookie_.has_value() && !handle_desc->trace_ended_) {
-          atrace_async_end(ATRACE_TAG_ACTIVITY_MANAGER,
-                           "Perfetto Scoped Trace",
-                           handle_desc->trace_cookie_.value());
-
-          handle_desc->trace_ended_ = true;
-        }
-      }
-    }
-
-    // If Destroy is called prior to ReadTrace, mark the atrace as finished.
-    if (kind == StateKind::kDestroyed && handle_desc->trace_cookie_ && !handle_desc->trace_ended_) {
-      atrace_async_end(ATRACE_TAG_ACTIVITY_MANAGER,
-                       "Perfetto Scoped Trace",
-                       *handle_desc->trace_cookie_);
-      handle_desc->trace_ended_ = true;
-    }
-  }
-
-  // The following state detection is for debugging only.
-  // We figure out if something is destroyed, uncreated, or live.
-
-  // Does not distinguish between kTimedOutDestroyed and kDestroyed.
-  bool IsDestroyed(Handle handle) const {
-    auto it = states_.find(handle);
-    if (it != states_.end()) {
-      // Tracked values are not destroyed yet.
-      return false;
-    }
-
-    if (handle == kInvalidHandle) {
-      return false;
-    }
-
-    // The following assumes handles are incrementally generated:
-    if (it == states_.end()) {
-      // value is in range of [0, last_destroyed]  => destroyed.
-      return handle <= last_destroyed_;
-    }
-
-    auto min_it = states_.begin();
-    if (handle < min_it->first) {
-      // value smaller than anything tracked: it was destroyed and we stopped tracking it.
-      return true;
-    }
-
-    auto max_it = states_.rbegin();
-    if (handle > max_it->first) {
-      // value too big: it's uncreated;
-      return false;
-    }
-
-    // else it was a value that was previously tracked within [min,max] but no longer
-    return true;
-  }
-
-  bool IsUncreated(Handle handle) const {
-    auto it = states_.find(handle);
-    if (it != states_.end()) {
-      // Tracked values are not uncreated.
-      return false;
-    }
-
-    if (handle == kInvalidHandle) {
-      // Strangely enough, an invalid handle can never be created.
-      return true;
-    }
-
-    // The following assumes handles are incrementally generated:
-    if (it == states_.end()) {
-      // value is in range of (last_destroyed, inf)  => uncreated.
-      return handle > last_destroyed_;
-    }
-
-    auto min_it = states_.begin();
-    if (handle < min_it->first) {
-      // value smaller than anything tracked: it was destroyed and we stopped tracking it.
-      return false;
-    }
-
-    auto max_it = states_.rbegin();
-    if (handle > max_it->first) {
-      // value too big: it's uncreated;
-      return true;
-    }
-
-    // else it was a value that was previously tracked within [min,max] but no longer
-    return false;
-  }
-
- public:
-  void Dump(::android::Printer& printer) {
-    // Locking can fail if we dump during a deadlock, so just do a best-effort lock here.
-    bool is_it_locked = mutex_.try_lock();
-
-    printer.printFormatLine("Perfetto consumer state:");
-    if (!is_it_locked) {
-      printer.printLine("""""  (possible deadlock)");
-    }
-    printer.printFormatLine("  Last destroyed handle: %" PRId64, last_destroyed_);
-    printer.printFormatLine("  Last created handle: %" PRId64, last_created_);
-    printer.printFormatLine("");
-    printer.printFormatLine("  In-flight handles:");
-
-    for (auto it = states_.begin(); it != states_.end(); ++it) {
-      HandleDescription& handle_desc = it->second;
-      uint64_t started_tracing =
-          handle_desc.started_tracing_ns_ ? *handle_desc.started_tracing_ns_ : 0;
-      printer.printFormatLine("    Handle %" PRId64, handle_desc.handle_);
-      printer.printFormatLine("      Kind: %s", ToString(handle_desc.kind_).c_str());
-      printer.printFormatLine("      Perfetto State: %d", static_cast<int>(handle_desc.state_));
-      printer.printFormatLine("      Started tracing at: %" PRIu64, started_tracing);
-      printer.printFormatLine("      Last transition at: %" PRIu64,
-                              handle_desc.last_transition_ns_);
-    }
-    if (states_.empty()) {
-      printer.printFormatLine("    (None)");
-    }
-
-    printer.printFormatLine("");
-
-    if (is_it_locked) {  // u.b. if calling unlock on an unlocked mutex.
-      mutex_.unlock();
-    }
-  }
-
-  static PerfettoConsumerImpl::Impl* GetImplSingleton() {
-    static PerfettoConsumerImpl::Impl impl;
-    return &impl;
-  }
-};
-
-// Use a singleton because fruit instantiates a new PerfettoConsumer object for every
-// new rx chain in RxProducerFactory. However, we want to track all perfetto transitions globally
-// through 1 impl object.
-//
-// TODO: Avoiding a singleton would mean a more significant refactoring to remove the fruit/perfetto
-// usage.
-
-
-//
-// Forward all calls to PerfettoConsumerImpl::Impl
-//
-
-PerfettoConsumerImpl::~PerfettoConsumerImpl() {
-  // delete impl_;  // TODO: no singleton
-}
-
-void PerfettoConsumerImpl::Initialize() {
-  // impl_ = new PerfettoConsumerImpl::Impl();  // TODO: no singleton
-  impl_ = PerfettoConsumerImpl::Impl::GetImplSingleton();
-}
-
-void PerfettoConsumerImpl::Dump(::android::Printer& printer) {
-  PerfettoConsumerImpl::Impl::GetImplSingleton()->Dump(/*borrow*/printer);
-}
-
-PerfettoConsumer::Handle PerfettoConsumerImpl::Create(const void* config_proto,
-                                    size_t config_len,
-                                    PerfettoConsumer::OnStateChangedCb callback,
-                                    void* callback_arg) {
-  return impl_->Create(config_proto,
-                       config_len,
-                       callback,
-                       callback_arg);
-}
-
-void PerfettoConsumerImpl::StartTracing(PerfettoConsumer::Handle handle) {
-  impl_->StartTracing(handle);
-}
-
-PerfettoConsumer::TraceBuffer PerfettoConsumerImpl::ReadTrace(PerfettoConsumer::Handle handle) {
-  return impl_->ReadTrace(handle);
-}
-
-void PerfettoConsumerImpl::Destroy(PerfettoConsumer::Handle handle) {
-  impl_->Destroy(handle);
-}
-
-PerfettoConsumer::State PerfettoConsumerImpl::PollState(PerfettoConsumer::Handle handle) {
-  return impl_->PollState(handle);
-}
-
-}  // namespace iorap::perfetto
diff --git a/src/perfetto/perfetto_consumer.h b/src/perfetto/perfetto_consumer.h
deleted file mode 100644
index 2d828c0..0000000
--- a/src/perfetto/perfetto_consumer.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_PERFETTO_PERFETTO_CONSUMER_H_
-#define IORAP_SRC_PERFETTO_PERFETTO_CONSUMER_H_
-
-#include <fruit/fruit.h>
-#include <perfetto/public/consumer_api.h>  // libperfetto
-
-namespace android {
-class Printer;
-}  // namespace android
-
-namespace iorap::perfetto {
-
-// Abstract out the Perfetto C API behind a virtual interface:
-// This enables us to use dependency injection to provide mock implementations
-// during tests.
-struct PerfettoConsumer {
-  // 1:1 aliasing of type definitions and constants in perfetto/public/consumer_api.h
-  // Refer to the documentation there.
-  using State = ::perfetto::consumer::State;
-  using Handle = ::perfetto::consumer::Handle;
-  static constexpr Handle kInvalidHandle = ::perfetto::consumer::kInvalidHandle;
-  using OnStateChangedCb = ::perfetto::consumer::OnStateChangedCb;
-  using TraceBuffer = ::perfetto::consumer::TraceBuffer;
-
-  // 1:1 forwarding of C-style functions in perfetto/public/consumer_api.h
-  // Refer to the documentation there.
-
-  virtual Handle Create(const void* config_proto,
-                        size_t config_len,
-                        OnStateChangedCb callback,
-                        void* callback_arg) = 0;
-  virtual void StartTracing(Handle) = 0;
-  virtual TraceBuffer ReadTrace(Handle) = 0;
-  virtual void Destroy(Handle) = 0;
-  virtual State PollState(Handle) = 0;
-
-  virtual ~PerfettoConsumer() {}
-};
-
-// "Live" implementation that calls down to libperfetto.
-struct PerfettoConsumerRawImpl : public PerfettoConsumer {
-  // Marks this constructor as the one to use for injection.
-  INJECT(PerfettoConsumerRawImpl()) = default;
-
-  virtual Handle Create(const void* config_proto,
-                        size_t config_len,
-                        OnStateChangedCb callback,
-                        void* callback_arg) override {
-    return ::perfetto::consumer::Create(config_proto,
-                                      config_len,
-                                      callback,
-                                      callback_arg);
-  }
-
-  virtual void StartTracing(Handle handle) override {
-    ::perfetto::consumer::StartTracing(handle);
-  }
-
-  virtual TraceBuffer ReadTrace(Handle handle) override {
-    return ::perfetto::consumer::ReadTrace(handle);
-  }
-
-  virtual void Destroy(Handle handle) override {
-    ::perfetto::consumer::Destroy(handle);
-  }
-  virtual State PollState(Handle handle) override {
-    return ::perfetto::consumer::PollState(handle);
-  }
-
-  virtual ~PerfettoConsumerRawImpl() {}
-};
-
-// "Safe" implementation that has extra checking around it.
-class PerfettoConsumerImpl : public PerfettoConsumer {
- public:
-  // Marks this constructor as the one to use for injection.
-  INJECT(PerfettoConsumerImpl()) { Initialize(); }
-
-  virtual Handle Create(const void* config_proto,
-                        size_t config_len,
-                        OnStateChangedCb callback,
-                        void* callback_arg) override;
-  virtual void StartTracing(Handle handle) override;
-  virtual TraceBuffer ReadTrace(Handle handle) override;
-  virtual void Destroy(Handle handle) override;
-  virtual State PollState(Handle handle) override;
-
-  virtual ~PerfettoConsumerImpl();
-
-  static void Dump(/*borrow*/::android::Printer& printer);
-
- private:
-  void Initialize();
-  struct Impl;
-  PerfettoConsumerImpl::Impl* impl_;
-};
-
-}  // namespace iorap::perfetto
-
-#endif  // IORAP_SRC_PERFETTO_PERFETTO_CONSUMER_H_
-
diff --git a/src/perfetto/rx_producer.cc b/src/perfetto/rx_producer.cc
deleted file mode 100644
index 824600c..0000000
--- a/src/perfetto/rx_producer.cc
+++ /dev/null
@@ -1,939 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "common/debug.h"
-#include "common/expected.h"
-#include "perfetto/rx_producer.h"
-
-#include <android-base/file.h>
-#include <android-base/properties.h>
-#include <android-base/unique_fd.h>
-
-#include <iostream>
-
-#include <sched.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <syscall.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-// TODO: move to perfetto code
-namespace perfetto {
-namespace consumer {
-
-std::ostream& operator<<(std::ostream& os, State state) {
-  switch (state) {
-    case State::kTraceFailed:
-      os << "kTraceFailed";
-      break;
-    case State::kConnectionError:
-      os << "kConnectionError";
-      break;
-    case State::kSessionNotFound:
-      os << "kSessionNotFound";
-      break;
-    case State::kIdle:
-      os << "kIdle";
-      break;
-    case State::kConnecting:
-      os << "kConnecting";
-      break;
-    case State::kConfigured:
-      os << "kConfigured";
-      break;
-    case State::kTracing:
-      os << "kTracing";
-      break;
-    case State::kTraceEnded:
-      os << "kTraceEnded";
-      break;
-    default:
-      os << "(unknown)";  // did someone forget to update this code?
-      break;
-  }
-  return os;
-}
-
-}  // namespace consumer
-}  // namespace perfetto
-
-namespace iorap::perfetto {
-
-PerfettoDependencies::Component PerfettoDependencies::CreateComponent() {
-  // TODO: read from config.
-  static const uint32_t kTraceDurationMs =
-      ::android::base::GetUintProperty("iorapd.perfetto.trace_duration_ms", /*default*/5000U);
-
-  static const uint32_t kBufferSize =
-      ::android::base::GetUintProperty("iorapd.perfetto.buffer_size", /*default*/4096U);
-
-  return fruit::createComponent()
-    .bind<PerfettoConsumer, PerfettoConsumerImpl>()
-    .registerProvider([]() /* -> TraceConfig */ {
-        return CreateConfig(kTraceDurationMs,
-                            /*deferred_start*/false,
-                            kBufferSize);
-    });
-}
-
-::perfetto::protos::TraceConfig PerfettoDependencies::CreateConfig(uint32_t duration_ms,
-                                                                   bool deferred_start,
-                                                                   uint32_t buffer_size) {
-  ::perfetto::protos::TraceConfig trace_config;
-
-  trace_config.set_duration_ms(duration_ms);
-  trace_config.add_buffers()->set_size_kb(buffer_size);
-  trace_config.set_deferred_start(deferred_start);
-
-  auto* ds_config = trace_config.add_data_sources()->mutable_config();
-  ds_config->set_name("linux.ftrace");
-  ds_config->mutable_ftrace_config()->add_ftrace_events(
-      "mm_filemap_add_to_page_cache");
-  ds_config->mutable_ftrace_config()->add_ftrace_events(
-      "mm_filemap_delete_from_page_cache");
-  ds_config->set_target_buffer(0);
-
-  return trace_config;
-}
-
-// RAII-style wrapper around a perfetto handle that calls Destroy
-// in a thread-safe manner.
-struct PerfettoConsumerHandle {
- private:
-  std::shared_ptr<PerfettoConsumer> consumer_;
-  PerfettoConsumer::Handle handle_;
-
- public:
-  // Takes over ownership of the 'handle'.
-  //
-  // Consumer must not be null.
-  PerfettoConsumerHandle(std::shared_ptr<PerfettoConsumer> consumer,
-                         PerfettoConsumer::Handle handle)
-    : consumer_{std::move(consumer)},
-      handle_{std::move(handle)} {
-    DCHECK(consumer_ != nullptr);
-  }
-
-  std::shared_ptr<PerfettoConsumer> GetConsumer() const {
-    return consumer_;
-  }
-
-  PerfettoConsumer::Handle GetHandle() const {
-    return handle_;
-  }
-
-  ~PerfettoConsumerHandle() {
-    LOG(VERBOSE) << "PerfettoConsumerHandle::Destroy(" << handle_ << ")";
-    consumer_->Destroy(handle_);
-  }
-
-  bool operator==(const PerfettoConsumerHandle& other) const {
-    return handle_ == other.handle_ && consumer_ == other.consumer_;
-  }
-
-  bool operator!=(const PerfettoConsumerHandle& other) const {
-    return !(*this == other);
-  }
-};
-
-
-// Snapshot of a single perfetto OnStateChanged callback.
-//
-// Operate on the PerfettoConsumer to further change the state.
-//
-// The Handle is kept 'valid' until all references to the PerfettoConsumerHandle
-// are dropped to 0. This ensures the Handle is not destroyed too early. All
-// direct usages of 'Handle' must be scoped by the PerfettoConsumerHandle.
-struct PerfettoStateChange {
- public:
-  using State = ::perfetto::consumer::State;
-  using Handle = ::perfetto::consumer::Handle;
-
-  State state;                                                           // Never invalid.
-  std::shared_ptr<PerfettoConsumerHandle> perfetto_consumer_and_handle;  // Never null.
-
-  // Safety: Use only within scope of the PerfettoStateChange.
-  Handle GetHandle() const {
-    // TODO: it would be even safer to wrap all the calls to the handle inside a class,
-    // instead of exposing this raw Handle.
-    return perfetto_consumer_and_handle->GetHandle();
-  }
-
-  std::shared_ptr<PerfettoConsumer> GetConsumer() const {
-    return perfetto_consumer_and_handle->GetConsumer();
-  }
-};
-
-std::ostream& operator<<(std::ostream& os, const PerfettoStateChange& state_change) {
-  os << "PerfettoStateChange{" << state_change.state << ","
-     << state_change.GetHandle() << ","
-     << state_change.GetConsumer().get() << "}";
-  return os;
-}
-
-// Once created, this acts as a hot observable, emitting 'PerfettoStateChange' transition items.
-// Only the 'state' will vary, the handle and perfetto_consumer are always the same value.
-//
-// Clients only need to handle the success states in #on_next, all failure states will go to
-// #on_error.
-//
-// Upon reaching the appropriate terminal states, either #on_completed or #on_error is called.
-// No future callbacks will then occur, so this object should be subsequently deleted.
-//
-// The Handle is destroyed automatically after the last item is emitted, so it must only be
-// manipulated from the #on_next callbacks. Do not save the Handle and use it at other times.
-class StateChangedSubject {
- public:
-  using State = ::perfetto::consumer::State;
-  using Handle = ::perfetto::consumer::Handle;
-
-  // Static members to solve use-after-free bug.
-  // The object is accessed from not only perfetto thread, but also iorap
-  // thread. Use this global map to manage it.
-  static std::mutex state_subject_mutex_;
-  static std::unordered_map<Handle, StateChangedSubject*> state_subject_map_;
-
-  StateChangedSubject(const ::perfetto::protos::TraceConfig& trace_config,
-                      rxcpp::subscriber<PerfettoStateChange> destination,
-                      std::shared_ptr<PerfettoConsumer> perfetto_consumer)
-    : deferred_start(trace_config.deferred_start()),
-      dest(std::move(destination)),
-      perfetto_consumer_(std::move(perfetto_consumer)) {
-    DCHECK(perfetto_consumer_ != nullptr);
-  }
-
- private:
-  struct StateChangedError : public std::runtime_error {
-    explicit StateChangedError(const std::string& what_arg) : std::runtime_error(what_arg) {}
-  };
-
-  std::shared_ptr<PerfettoConsumerHandle> handle_;  // non-null after bound_ == true.
-  std::atomic<bool> bound_{false};  // synchronize-with for BindHandle -> OnStateChanged.
-
-  State last_state{State::kIdle};
-  bool deferred_start{false};
-
-  rxcpp::subscriber<PerfettoStateChange> dest;
-  std::shared_ptr<PerfettoConsumer> perfetto_consumer_;  // This is never null.
-
-  void DcheckBadStateTransition(State state, bool fail_unless = false) const {
-    DCHECK(fail_unless) << "Invalid state transition to " << state << " from " << last_state;
-  }
-
-  void DcheckValidStateTransition(State state) {
-    // State must not be out of range.
-    DCHECK_GE(state, State::kTraceFailed);
-    DCHECK_LE(state, State::kTraceEnded);
-
-    // Internal state that should never leak out into public perfetto API:
-    DCHECK_NE(state, State::kIdle);
-    // These can only be returned by PollState:
-    DCHECK_NE(state, State::kSessionNotFound);
-
-    // Validate state transitions as per the perfetto API contract.
-    // See the 'state diagram' in consumer_api.h
-    switch (last_state) {
-      case State::kTraceFailed:  // Final and unrecoverable.
-        // b/122548195: this can transition to 'kConnectionError' if selinux is disabled.
-        if (state == State::kConnectionError) {
-          LOG(WARNING) << "b/122548195: kTraceFailed is non-terminal, ignoring.";
-          // This is a bit awkward: rxcpp will drop the #on_error calls if its more than once.
-          break;
-        }
-        DcheckBadStateTransition(state);
-        break;
-      case State::kConnectionError:  // Final and unrecoverable.
-        DcheckBadStateTransition(state);
-        break;
-      case State::kSessionNotFound:
-        DcheckBadStateTransition(state);
-        break;
-      case State::kIdle:
-        // OK: we initialized our own state to idle prior to the first callback.
-        break;
-      case State::kConnecting:
-        switch (state) {
-          case State::kConfigured:
-            // kConfigured, if |deferred_start| == true in the trace config.
-            DcheckBadStateTransition(state, deferred_start);
-            break;
-          case State::kTracing:
-            // kTracing, if |deferred_start| == false.
-            DcheckBadStateTransition(state, !deferred_start);
-            break;
-          case State::kConnectionError:
-            // An error state, e.g. if cannot reach the traced daemon.
-            break;
-          default:
-            // Unconditionally invalid state transitions from kConnecting to anything else.
-            DcheckBadStateTransition(state);
-        }
-        break;
-      case State::kConfigured:
-        DCHECK(deferred_start);
-        if (state != State::kTracing  // OK: this is documented.
-            && state != State::kTraceFailed) {  // Undocumented selinux failure.
-            // Undocumented, but it appears to go directly from Configured->TraceEnded
-            // it can also go to kTraceFailed if e.g. there's an selinux violation
-            // however this appears to be underdocumented.
-            // b/122607276 #2
-
-          if (state != State::kTraceEnded) {  // b/122607276 #1
-            DcheckBadStateTransition(state);
-          }
-        }
-        break;
-      case State::kTracing:
-        switch (state) {
-          case State::kTraceEnded:
-            break;
-          case State::kTraceFailed:
-            break;
-          default:
-            DcheckBadStateTransition(state);
-        }
-        break;
-      case State::kTraceEnded:
-        // Cannot transition from terminal state to another state.
-        DcheckBadStateTransition(state);
-        break;
-
-      // default: This list is exhaustive
-    }
-  }
-
-  constexpr bool IsTerminalState() const {
-    switch (last_state) {
-      case State::kTraceFailed:
-      case State::kConnectionError:
-      case State::kTraceEnded:
-        return true;
-      default:
-        return false;
-    }
-  }
-
-  // Returns true for non-terminal states (i.e. this callback will be invoked again).
-  // Returns false otherwise.
-  bool OnStateChanged(Handle handle, State state) {
-    using namespace ::perfetto::consumer;
-
-    // Block until 'BoundHandle' is called by the other thread.
-    while (!bound_.load()) {}  // seq_cst acquire.
-
-    std::shared_ptr<PerfettoConsumerHandle> handle_ptr = handle_;
-    DCHECK(handle_ptr != nullptr);
-
-    DCHECK_EQ(handle_ptr->GetHandle(), handle);
-    DcheckValidStateTransition(state);
-
-    switch (state) {
-      // Error states (terminal).
-      case State::kTraceFailed:
-        EmitError("kTraceFailed");
-        break;
-      case State::kConnectionError:
-        EmitError("kConnectionError");
-        break;
-
-      // Regular transitions (non-terminal).
-      case State::kConnecting:
-      case State::kConfigured:
-      case State::kTracing:
-        EmitNext(state);
-        break;
-      // Regular transitions (terminal).
-      case State::kTraceEnded:  // XX: do we even need to emit the 'TraceEnded' state?
-        EmitNext(state);
-        dest.on_completed();
-        break;
-      default:
-        DcheckBadStateTransition(state);
-    }
-
-    bool force_non_terminal = false;
-
-    if (last_state == State::kConfigured &&  state == State::kConnectionError) {
-      // b/122548195: this can transition to 'kConnectionError' if selinux is disabled.
-      force_non_terminal = true;
-      // This function must 'return true' in this buggy case, otherwise we will
-      // call the destructor too early and subsequent callbacks will crash.
-    }
-
-    // Remember the state to validate prior state transitions.
-    last_state = state;
-
-    // The owner of this class should avoid leaking memory once we reach a terminal state.
-    return !IsTerminalState() || force_non_terminal;
-  }
-
- public:
-  // Thread safety: Called by main thread, terminates the rx stream.
-  // When this function is invoked, no calls to this class from other threads can occur.
-  void OnCreateFailed() {
-    // returned when an invalid handle is passed to PollState().
-    last_state = State::kSessionNotFound;
-    EmitError("Create returned kInvalidHandle");
-  }
-
-  // Thread safety: Called by main thread, this could be concurrent to
-  // 'CallbackOnStateChanged'.
-  void BindHandle(const std::shared_ptr<PerfettoConsumerHandle>& handle) {
-    handle_ = handle;
-
-    // Unblock OnStateChanged.
-    bound_.store(true);  // seq_cst release.
-  }
-
-
-  // Called by libperfetto background thread (same one every time) and iorap
-  // thread.
-  static void CallbackOnStateChanged(Handle handle, State state, void* callback_arg) {
-    LOG(VERBOSE) << "CallbackOnStateChanged(handle=" << handle << ",state=" << state
-                 << ",callback_arg=" << callback_arg << ")";
-
-    // Validate OnStateChanged callback invariants, guaranteed by libperfetto.
-    DCHECK_NE(handle, ::perfetto::consumer::kInvalidHandle);
-
-    // TODO: the memory ordering guarantees should be explicitly specified in consumer_api.h:
-    // This isn't specific enough:
-    // "The callback will be invoked on an internal thread and must not block."
-    // However looking at the implementation it posts onto a single-thread task runner,
-    // so this must be the case.
-
-    // This current thread owns 'StateChangedSubject', no other threads must access it.
-    // Explicit synchronization is not necessary.
-
-    {
-      std::lock_guard<std::mutex> guard(StateChangedSubject::state_subject_mutex_);
-      auto it = StateChangedSubject::state_subject_map_.find(handle);
-      // If the object is already deleted, do nothing.
-      if (it == StateChangedSubject::state_subject_map_.end()) {
-        return;
-      }
-
-      StateChangedSubject* state_subject = it->second;
-      if (!state_subject->OnStateChanged(handle, state)) {
-        // Clean up the state tracker when we reach a terminal state.
-        // This means that no future callbacks will occur anymore.
-        StateChangedSubject::state_subject_map_.erase(it);
-        delete state_subject;
-      }
-    }
-  }
-
- private:
-  void EmitError(const std::string& msg) {
-    // Sidenote: Exact error class does not matter, rxcpp only lets us access the error
-    // as a string (rxcpp::util::what).
-    //
-    // Either way, the recovery strategy is identical (log then try and restart).
-    dest.on_error(rxcpp::util::make_error_ptr(StateChangedError{msg}));
-  }
-
-  void EmitNext(State state) {
-    if (WOULD_LOG(VERBOSE) && !dest.is_subscribed()) {
-      // This is purely for logging: #on_next already filters out items after unsubscription.
-      LOG(VERBOSE) << "StateChangedSubject#EmitNext(" << state << ") - drop due to unsubscribe";
-    }
-
-    auto handle_ptr = handle_;
-    DCHECK(handle_ptr != nullptr);
-
-    // Non-null guarantee for the items emitted into this stream.
-    PerfettoStateChange state_change{state, handle_ptr};
-    dest.on_next(std::move(state_change));
-  }
-
-  // TODO: inherit from rx subject and handle #unsubscribe explicitly, instead
-  // of just being subject-like?
-};
-
-std::mutex StateChangedSubject::state_subject_mutex_;
-std::unordered_map<::perfetto::consumer::Handle,
-    StateChangedSubject*> StateChangedSubject::state_subject_map_;
-
-// Note: The states will be emitted on a separate thread, so e.g. #as_blocking()
-// needs to be used to avoid dropping everything on the floor.
-//
-// Important: The #on_error case must be handled explicitly by the observable,
-// because the default behavior is to 'throw' which will cause an std::terminate with -fno-except.
-static auto /*[observable<State>, shared_ptr<PerfettoConsumerHandle>]*/
-    CreatePerfettoStateStream(::perfetto::protos::TraceConfig perfetto_config,
-                              std::shared_ptr<PerfettoConsumer> perfetto_consumer) {
-  auto obs = rxcpp::observable<>::create<PerfettoStateChange>(
-    [perfetto_config = std::move(perfetto_config), perfetto_consumer = std::move(perfetto_consumer)]
-        (rxcpp::subscriber<PerfettoStateChange> subscriber) {
-      std::unique_ptr<StateChangedSubject> state_subject{
-          new StateChangedSubject{perfetto_config, subscriber, perfetto_consumer}};
-
-      // Perfetto API requires a pointer to a serialized protobuf, it doesn't accept
-      // the code-generated object.
-      std::string perfetto_config_str = perfetto_config.SerializeAsString();
-
-      ::perfetto::consumer::Handle handle =
-          perfetto_consumer->Create(perfetto_config_str.data(),
-                                    perfetto_config_str.size(),
-                                    // executes on the same background thread repeatedly.
-                                    &StateChangedSubject::CallbackOnStateChanged,
-                                    // inter-thread-move
-                                    reinterpret_cast<void*>(state_subject.get()));
-      // perfetto::consumer::Create synchronizes-with OnStateChanged callback, this means
-      // we don't need to explicitly synchronize state_subject here so long as we don't access
-      // it on this thread again.
-      LOG(DEBUG) << "Create Perfetto handle " << handle;
-
-      if (handle == ::perfetto::consumer::kInvalidHandle) {
-        LOG(ERROR) << "Failed to create Perfetto handle";
-        // No callbacks will occur, so our thread still owns the state subject.
-        state_subject->OnCreateFailed();
-        return;
-      }
-
-      {
-        std::lock_guard<std::mutex> guard(StateChangedSubject::state_subject_mutex_);
-        StateChangedSubject::state_subject_map_[handle] = state_subject.get();
-      }
-
-      std::shared_ptr<PerfettoConsumerHandle> safe_handle{
-          new PerfettoConsumerHandle{perfetto_consumer, handle}};
-
-      // Share ownership of the Handle with the StateSubject.
-      // This way we defer calling 'Destroy' until the callback reaches a terminal state
-      // *and* all users of the stream are done with the handle.
-      state_subject->BindHandle(safe_handle);
-
-      // state_subject ownership is taken over by OnStateChanged.
-      // It will also be touched in a separate thread, so we must never access it here again.
-      state_subject.release();
-
-      // 'subscriber#add' is actually a call to register an on_unsubscribe listener.
-      subscriber.add([safe_handle]() {
-        LOG(VERBOSE) << "PerfettoStateChange#unsubscribe";
-
-        // Release our ref-count to the handle.
-        // safe_handle.reset();  // This happens implicitly.
-
-        // TODO: I think this won't handle the case where we need to shut down early.
-        // Need to use the explicit kShutdown for that?
-      });
-
-      // TODO: this would be an excellent place to shuffle the perfetto config protobuf
-      // into a global debug state for dumpsys.
-    });
-
-  return obs;
-}
-
-template <typename T>
-bool BinaryWireProtobuf<T>::WriteFullyToFile(const std::string& path,
-                                             bool follow_symlinks) const {
-  // TODO: it would be great if android::base had a string_view overload to avoid copying
-  // data into an std::string.
-
-  // u  g  o
-  // rw-rw----
-  //
-  // Protobufs can be read/written but not executed.
-  static constexpr const mode_t kMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
-
-  int flags =
-      O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY | (follow_symlinks ? 0 : O_NOFOLLOW);
-  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags, kMode)));
-
-  if (fd == -1) {
-    PLOG(ERROR) << "BinaryWireProtobuf::WriteFullyToFile open failed";
-    return false;
-  }
-
-  if (!::android::base::WriteFully(fd, data_.data(), size())) {
-    PLOG(ERROR) << "BinaryWireProtobuf::WriteFullyToFile write failed";
-    return CleanUpAfterFailedWrite(path);
-  }
-
-  return true;
-}
-
-template <typename T>
-bool BinaryWireProtobuf<T>::CleanUpAfterFailedWrite(const std::string& path) {
-  // Something went wrong. Let's not leave a corrupt file lying around.
-  int saved_errno = errno;
-  unlink(path.c_str());
-  errno = saved_errno;
-  return false;
-}
-
-template <typename T>
-bool BinaryWireProtobuf<T>::WriteStringToFd(int fd) const {
-  const char* p = reinterpret_cast<const char*>(data_.data());
-  size_t left = size();
-  while (left > 0) {
-    ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, left));
-    if (n == -1) {
-      return false;
-    }
-    p += n;
-    left -= n;
-  }
-  return true;
-}
-
-template <typename T>
-std::optional<BinaryWireProtobuf<T>> BinaryWireProtobuf<T>::ReadFullyFromFile(
-    const std::string& path,
-    bool follow_symlinks) {
-  std::vector<std::byte> data;
-
-  int flags = O_RDONLY | O_CLOEXEC | O_BINARY | (follow_symlinks ? 0 : O_NOFOLLOW);
-  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags)));
-  if (fd == -1) {
-    return std::nullopt;
-  }
-
-  if (ReadFdToString(fd.get(), /*out*/&data)) {
-    return BinaryWireProtobuf<T>{std::move(data)};
-  } else {
-    return std::nullopt;
-  }
-}
-
-template <typename T>
-bool BinaryWireProtobuf<T>::operator==(const BinaryWireProtobuf<T>& other) const {
-  if (data_.size() != other.data_.size()) {
-    return false;
-  }
-  return std::equal(data_.begin(), data_.end(), other.data_.begin());
-}
-
-template <typename T>
-bool BinaryWireProtobuf<T>::ReadFdToString(int fd, /*out*/std::vector<std::byte>* content) {
-  DCHECK(content != nullptr);
-
-  content->clear();
-
-  struct stat sb;
-  if (fstat(fd, /*out*/&sb) != -1 && sb.st_size > 0) {
-    content->reserve(sb.st_size);
-  }
-
-  char buf[BUFSIZ];
-  auto it = content->begin();
-  ssize_t n;
-  while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
-    content->insert(it,
-                    reinterpret_cast<std::byte*>(&buf[0]),
-                    reinterpret_cast<std::byte*>(&buf[n]));
-
-    std::advance(/*inout*/it, static_cast<size_t>(n));
-
-    static_assert(sizeof(char) == sizeof(std::byte), "sanity check for reinterpret cast");
-  }
-  return (n == 0) ? true : false;
-}
-
-// explicit template instantiation.
-template struct BinaryWireProtobuf<::google::protobuf::MessageLite>;
-// TODO: refactor this not to need the template instantiation.
-
-// Copy of the 2.6.18 kernel header (linux/ioprio.h)
-
-#define IOPRIO_WHO_PROCESS (1)
-#define IOPRIO_CLASS_IDLE (3)
-
-#define IOPRIO_BITS		(16)
-#define IOPRIO_CLASS_SHIFT	(13)
-#define IOPRIO_PRIO_MASK	((1UL << IOPRIO_CLASS_SHIFT) - 1)
-
-#define IOPRIO_PRIO_CLASS(mask)	((mask) >> IOPRIO_CLASS_SHIFT)
-#define IOPRIO_PRIO_DATA(mask)	((mask) & IOPRIO_PRIO_MASK)
-#define IOPRIO_PRIO_VALUE(class, data)	(((class) << IOPRIO_CLASS_SHIFT) | data)
-
-static int ioprio_get(int which, int who) {
-  return syscall(SYS_ioprio_get, which, who);
-}
-
-static int ioprio_set(int which, int who, int ioprio) {
-  return syscall(SYS_ioprio_set, which, who, ioprio);
-}
-
-// An rx Coordination, which will cause a new thread to spawn for each new Worker.
-//
-// Idle-class priority is set for the CPU and IO priorities on the new thread.
-rxcpp::observe_on_one_worker ObserveOnNewIoThread() {
-  // IO thread factory for idle-priority threads.
-  // Both the CPU scheduler and the IO scheduler are set to idle.
-  //
-  // Use this when needing to schedule disk access from a normal-priority thread onto a
-  // very low priority thread, but not so low that we need to use a BackgroundJobScheduler.
-  struct io_thread_factory {
-    std::thread operator()(std::function<void()> start) const {
-      return std::thread{
-        [start=std::move(start)]() {
-          // Set IO priority to idle.
-          do {
-            int value = ioprio_get(IOPRIO_WHO_PROCESS, /*pid*/0);
-            if (value == -1) {
-              PLOG(ERROR) << "io_thread_factory failed ioprio_get";
-              break;  // Can't set the ioprio, we don't know what data to use.
-            }
-
-            int data = IOPRIO_PRIO_DATA(value); // priority level
-            // This appears to be '4' in practice. We may want to raise to
-            // be the highest-priority within the idle class.
-
-            // idle scheduling class. only access disk when nobody else needs disk.
-            int res = ioprio_set(IOPRIO_WHO_PROCESS,
-                                 /*pid*/0,
-                                 IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, data));
-            if (res < 0) {
-              PLOG(ERROR) << "io_thread_factory failed ioprio_set";
-              break;
-            }
-
-            // Changing the IO priority only has any effect with cfq scheduler:
-            // $> cat /sys/block/sda/queue/scheduler
-            LOG(VERBOSE) << "ioprio_set(WHO_PROCESS, class=IDLE, data=" << data << ")";
-          } while (false);
-
-          // Set CPU priority to idle.
-          do {
-            struct sched_param param{};
-            param.sched_priority = 0;  // Required to be statically 0 when used with SCHED_IDLE.
-
-            if (sched_setscheduler(/*pid*/0,  // current thread,
-                                   SCHED_IDLE,
-                                   /*in*/&param) != 0) {
-              PLOG(ERROR) << "io_thread_factory failed sched_setscheduler";
-              break;
-            }
-
-            LOG(VERBOSE) << "sched_setscheduler(self, IDLE)";
-          } while (false);
-
-          // XX: if changing the scheduling is too aggressive (i.e. it causes starvation),
-          // we may want to stick with the default class and change the nice (priority) levels
-          // to the minimum.
-
-          // TODO: future work, maybe use cgroups configuration file instead?
-
-          // Call the rxcpp-supplied code.
-          start();
-        }
-      };
-    }
-  };
-
-  static rxcpp::schedulers::scheduler thread_scheduler =
-      rxcpp::schedulers::make_new_thread(io_thread_factory{});
-
-  static rxcpp::observe_on_one_worker observe_on_io_thread{thread_scheduler};
-
-  return observe_on_io_thread;
-}
-
-static auto/*observable<PerfettoTraceProto>*/
-    CreatePerfettoStream(rxcpp::observable<PerfettoStreamCommand> input,
-                         std::shared_ptr<PerfettoConsumer> perfetto_consumer,
-                         const ::perfetto::protos::TraceConfig& trace_config) {
-        // XX: should I also take a scheduler for input here???
-
-  auto /*observable<PerfettoStateChange>*/ perfetto_states =
-    CreatePerfettoStateStream(trace_config, perfetto_consumer);
-
-  using State = ::perfetto::consumer::State;
-
-  auto/*coordinator*/ serialize_coordinator = rxcpp::observe_on_new_thread();
-  // Rx note:
-  // The optimal thing to do would be to have a lock/unlock for an entire subset of a chain.
-  // This would avoid creating new threads, and could also be used to intentionally block
-  // the regular C-callback perfetto thread.
-  //
-  // It seems possible to create a coordinator to lock a single operator in a chain, but this
-  // appears to be unsound. In particular, it doesn't even make life any simpler below because
-  // it would only apply the synchronization to 'zip' but not 'flat_map' which is unsound.
-  //
-  // There is also the built-in 'serialize_new_thread' which seems to create a new thread but
-  // then never actually uses it, that seems unfortunate and wasteful.
-  //
-  // Instead, do the simple thing which is create a new thread and always queue on there.
-  // Execution an action on that worker is itself unsynchronized, but this doesn't matter since
-  // the worker is only backed by 1 thread (no 2 schedulables can be executed concurrently
-  // on the 'observe_new_thread' worker).
-  return input
-    .tap([](PerfettoStreamCommand command) {
-           LOG(VERBOSE) << "CreatePerfettoStreamCommand#tap(command=" << command << ")";
-         })
-    // Input A, thread tA. Input B, thread tB. Continue execution with (A,B) on thread tC.
-    .zip(serialize_coordinator,  // rest of chain is also executed on the same thread.
-         perfetto_states)
-    // Note: zip terminates when either of the streams complete.
-    .flat_map(
-         [](std::tuple<PerfettoStreamCommand, PerfettoStateChange> p) {
-           auto& [command, state_change] = p;
-           LOG(VERBOSE) << "CreatePerfettoStream#combine("
-                        << command << "," << state_change << ")";
-           if (command == PerfettoStreamCommand::kShutdown) {
-             // Perfetto: Always safe to call ::perfetto::consumer::Destroy
-             // at any time.
-             //
-             // XX: How do we clean up the StateChangedSubject without racing
-             // against the callback? It strikes me that we may need a 'kDestroyed'
-             // state that perfetto can transition to from kConfigured.
-             LOG(VERBOSE) << "Call Perfetto_Consumer->Destroy";
-             state_change.GetConsumer()->Destroy(state_change.GetHandle());
-
-             // XX: Do we even have any guarantees about not getting more callbacks?
-             // We could just say 'there can still be spurious output after Shutdown'
-             // and just ignore it (e.g. Shutdown and immediately unsubscribe).
-           } else if (command == PerfettoStreamCommand::kStartTracing
-                          && state_change.state == State::kConfigured) {
-             LOG(VERBOSE) << "Call Perfetto_Consumer->StartTracing";
-             state_change.GetConsumer()->StartTracing(state_change.GetHandle());
-           } else if (command == PerfettoStreamCommand::kStopTracing &&
-                          state_change.state == State::kTraceEnded) {
-             // TODO: if perfetto actually had a 'StopTracing' we could call that here.
-             // right now we just pretend it exists, but rely on the config timer instead.
-             ::perfetto::consumer::TraceBuffer trace_buffer =
-                 state_change.GetConsumer()->ReadTrace(state_change.GetHandle());
-
-             LOG(VERBOSE) << "Perfetto Trace ended"
-                          << ", addr=" << reinterpret_cast<void*>(trace_buffer.begin)
-                          << ",size= " << trace_buffer.size;
-
-             PerfettoTraceProto wire_proto{trace_buffer.begin, trace_buffer.size};
-             return rxcpp::observable<>::just(std::move(wire_proto)).as_dynamic();
-           }
-           return rxcpp::observable<>::empty<PerfettoTraceProto>().as_dynamic();
-         }
-    );
-}
-
-std::ostream& operator<<(std::ostream& os, PerfettoStreamCommand c) {
-  switch (c) {
-    case PerfettoStreamCommand::kStartTracing:
-      os << "kStartTracing";
-      break;
-    case PerfettoStreamCommand::kStopTracing:
-      os << "kStopTracing";
-      break;
-    case PerfettoStreamCommand::kShutdown:
-      os << "kShutdown";
-      break;
-    default:
-      os << "(unknown)";
-      break;
-  }
-  return os;
-}
-
-RxProducerFactory::RxProducerFactory(PerfettoDependencies::Injector& injector)
-  : injector_(injector) {
-}
-
-// TODO: (fruit) maybe this could be streamlined further by avoiding this boilerplate?
-rxcpp::observable<PerfettoTraceProto> RxProducerFactory::CreateTraceStream(
-    rxcpp::observable<PerfettoStreamCommand> commands) {
-  std::shared_ptr<PerfettoConsumer> perfetto_consumer =
-      injector_.get<std::shared_ptr<PerfettoConsumer>>();
-  const ::perfetto::protos::TraceConfig& trace_config =
-      injector_.get<::perfetto::protos::TraceConfig>();
-
-  DCHECK(perfetto_consumer != nullptr);
-  DCHECK(reinterpret_cast<volatile const void*>(&trace_config) != nullptr);
-
-  return CreatePerfettoStream(commands,
-                              perfetto_consumer,
-                              trace_config);
-}
-
-// For testing/debugging only.
-//
-// Saves protobuf results in file name specified by 'arg_output_proto'.
-void CollectPerfettoTraceBufferImmediately(
-    RxProducerFactory& producer_factory,
-    const std::string& arg_output_proto) {
-  LOG(VERBOSE) << "CollectPerfettoTraceBufferImmediately";
-
-  std::shared_ptr<PerfettoConsumer> perfetto_consumer =
-      producer_factory.injector_.get<std::shared_ptr<PerfettoConsumer>>();
-  const ::perfetto::protos::TraceConfig& trace_config =
-      producer_factory.injector_.get<const ::perfetto::protos::TraceConfig&>();
-
-  auto /*observable<PerfettoStateChange>*/ perfetto_states =
-    CreatePerfettoStateStream(trace_config, perfetto_consumer);
-
-  perfetto_states
-    .as_blocking()  // Wait for observable to terminate with on_completed or on_error.
-    .subscribe(/*on_next*/[&](auto state_change) {
-       LOG(VERBOSE) << "Perfetto post-processed State change: " << state_change;
-
-       using State = ::perfetto::consumer::State;
-       switch (state_change.state) {
-         case State::kConnecting:
-           LOG(VERBOSE) << "Perfetto Tracing is Connecting";
-           // Transitional state. No-op.
-           break;
-         case State::kConfigured:
-           state_change.GetConsumer()->StartTracing(state_change.GetHandle());
-           break;
-         case State::kTracing:
-           LOG(VERBOSE) << "Perfetto Tracing started";
-           // Transitional state. No-op.
-           break;
-         case State::kTraceEnded: {
-           ::perfetto::consumer::TraceBuffer trace_buffer =
-             state_change.GetConsumer()->ReadTrace(state_change.GetHandle());
-
-           LOG(VERBOSE) << "Perfetto Trace ended"
-                        << ", addr=" << reinterpret_cast<void*>(trace_buffer.begin)
-                        << ",size= " << trace_buffer.size;
-
-           if (!arg_output_proto.empty()) {
-             std::string trace_buffer_str;
-             trace_buffer_str.resize(trace_buffer.size);
-             std::copy(trace_buffer.begin,
-                       trace_buffer.begin + trace_buffer.size,
-                       trace_buffer_str.data());
-             if (!android::base::WriteStringToFile(trace_buffer_str, arg_output_proto)) {
-               LOG(ERROR) << "Failed to save TraceBuffer to " << arg_output_proto;
-             } else {
-               LOG(INFO) << "TraceBuffer saved to file: " << arg_output_proto;
-               LOG(INFO);
-               LOG(INFO) << "To print this in a human readable form, execute these commands:";
-               LOG(INFO) << "$> adb pull '" << arg_output_proto << "'";
-               LOG(INFO) << "$> trace_to_text systrace <filename.pb>";
-             }
-           }
-
-           // TODO: something more useful with this TraceBuffer, such as saving it to a file
-           // and printing the output.
-           break;
-         }
-         default:
-           // No other states are possible, because they go to #on_error or cause a dcheck.
-           DCHECK(false) << "Invalid state: " << state_change;
-       }
-
-       //INTENTIONAL_COMPILER_ERROR_HERE // lets make sure this code actually does a trace.
-
-     }, /*on_error*/[](rxcpp::util::error_ptr err) {
-       LOG(ERROR) << "Perfetto post-processed state change failed: " << rxcpp::util::what(err);
-     }, /*on_completed*/[]() {
-       LOG(VERBOSE) << "Perfetto post-processed State #on_completed";
-     });
-}
-
-
-}  // namespace iorap::perfetto
diff --git a/src/perfetto/rx_producer.h b/src/perfetto/rx_producer.h
deleted file mode 100644
index 4e93f0d..0000000
--- a/src/perfetto/rx_producer.h
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef IORAP_SRC_PERFETTO_RX_PRODUCER_H_
-#define IORAP_SRC_PERFETTO_RX_PRODUCER_H_
-
-#include "perfetto/perfetto_consumer.h"       // libiorap
-
-#include <perfetto/config/trace_config.pb.h>  // libperfetto
-#include <rxcpp/rx.hpp>
-
-#include <iosfwd>
-#include <functional>
-#include <optional>
-#include <vector>
-
-namespace iorap::perfetto {
-
-struct PerfettoDependencies {
-  using Component =
-      fruit::Component<PerfettoConsumer, ::perfetto::protos::TraceConfig>;
-  using Injector =
-      fruit::Injector<PerfettoConsumer, ::perfetto::protos::TraceConfig>;
-  using NormalizedComponent =
-      fruit::NormalizedComponent<PerfettoConsumer, ::perfetto::protos::TraceConfig>;
-
-  // Create a 'live' component that will talk to perfetto via traced.
-  static Component CreateComponent(/*TODO: config params*/);
-
-  // Create perfetto.protos.TraceConfig , serialized as a (machine-readable) string.
-  //
-  // The following ftrace events are enabled:
-  // * mm_filemap_add_to_page_cache
-  // * mm_filemap_delete_from_page_cache
-  //
-  // If deferred starting is also enabled, no tracing will begin until
-  // ::perfetto::consumer::StartTracing is invoked.
-  static ::perfetto::protos::TraceConfig CreateConfig(uint32_t duration_ms,
-                                                      bool deferred_start = true,
-                                                      uint32_t buffer_size = 4096);
-};
-
-namespace detail {
-  template <typename T>
-  struct concept_message_lite_base {
-    static_assert(std::is_base_of_v<::google::protobuf::MessageLite, T>,
-                  "T must inherit from MessageLite");
-    using type = T;
-  };
-
-  template <typename T>
-  using concept_message_lite_base_t = typename concept_message_lite_base<T>::type;
-}  // namespace detail
-
-/*
- * In Android's version of libprotobuf, move-constructors are not generated.
- * This results in a legitimate (~10sec per TracePacket being compiled) slowdown,
- * so we need to avoid it everywhere.
- *
- * 1) Don't copy the protos, move them instead.
- * 2) Use 'shared_ptr' because rxcpp won't compile with unique_ptr.
- */
-template <typename T>
-using ProtobufPtr = std::shared_ptr<detail::concept_message_lite_base_t<const T>>;
-
-template <typename T>
-using ProtobufMutablePtr = std::shared_ptr<detail::concept_message_lite_base_t<T>>;
-
-// This acts as a lightweight type marker so that we know what data has actually
-// encoded under the hood.
-template <typename T>
-struct BinaryWireProtobuf {
-  static_assert(std::is_base_of_v<::google::protobuf::MessageLite, T>,
-                "T should be a base class of MessageLite");
-
-  std::vector<std::byte>& data() {
-    return data_;
-  }
-
-  const std::vector<std::byte>& data() const {
-    return data_;
-  }
-
-  size_t size() const {
-    return data_.size();
-  }
-
-  explicit BinaryWireProtobuf(char* data, size_t size)
-    : BinaryWireProtobuf(reinterpret_cast<std::byte*>(data), size) {
-  }
-
-  explicit BinaryWireProtobuf(std::byte* data, size_t size) {
-    data_.resize(size);
-    std::copy(data,
-              data + size,
-              data_.data());
-  }
-
-  explicit BinaryWireProtobuf(std::vector<std::byte> data) : data_{std::move(data)} {
-  }
-
-  // You wouldn't want to accidentally copy a giant multi-megabyte chunk would you?
-  // BinaryWireProtobuf(const BinaryWireProtobuf& other) = delete;  // FIXME: rx likes to copy.
-  BinaryWireProtobuf(const BinaryWireProtobuf& other) = default;
-  BinaryWireProtobuf(BinaryWireProtobuf&& other) = default;
-
-  // Important: Deserialization could fail, for example data is truncated or
-  // some minor disc corruption occurred.
-  template <typename U>
-  std::optional<ProtobufPtr<U>> MaybeUnserialize() {
-    ProtobufMutablePtr<U> unencoded{new U{}};
-
-    if (!unencoded->ParseFromArray(data_.data(), data_.size())) {
-      return std::nullopt;
-    }
-
-    return {std::move(unencoded)};
-  }
-
-  bool WriteFullyToFile(const std::string& path,
-                        bool follow_symlinks = false) const;
-
-  static std::optional<BinaryWireProtobuf<T>> ReadFullyFromFile(const std::string& path,
-                                                                bool follow_symlinks = false);
-
-  bool operator==(const BinaryWireProtobuf<T>& other) const;
-  bool operator!=(const BinaryWireProtobuf<T>& other) const {
-    return !(*this == other);
-  }
-
- private:
-  static bool CleanUpAfterFailedWrite(const std::string& path);
-  bool WriteStringToFd(int fd) const;
-
-  static bool ReadFdToString(int fd, /*out*/std::vector<std::byte>* data);
-
-  std::vector<std::byte> data_;
-};
-
-//using PerfettoTraceProto = BinaryWireProtobuf<::perfetto::protos::Trace>;
-using PerfettoTraceProto = BinaryWireProtobuf<::google::protobuf::MessageLite>;
-
-enum class PerfettoStreamCommand {
-  kStartTracing, // -> () | on_error
-  kStopTracing,  // -> on_next(PerfettoTraceProto) | on_error
-  kShutdown,     // -> on_completed | on_error
-  // XX: should shutdown be converted to use the rx suscriber#unsubscribe instead?
-};
-
-std::ostream& operator<<(std::ostream& os, PerfettoStreamCommand c);
-
-struct RxProducerFactory {
-  // Passing anything by value leads to a lot of pain and headache.
-  // Pass in the injector by reference because nothing else seems to work.
-  explicit RxProducerFactory(PerfettoDependencies::Injector& injector);
-
-  // Create a one-shot perfetto observable that will begin
-  // asynchronously producing a PerfettoTraceProto after the 'kStartTracing'
-  // command is observed.
-  //
-  // libperfetto is immediately primed (i.e. connected in a deferred state)
-  // upon calling this function, to reduce the latency of 'kStartTracing'.
-  //
-  // To finish the trace, push 'kStopTracing'. To cancel or tear down at any
-  // time, push 'kShutdown'.
-  //
-  // The TraceProto may come out at any time after 'kStartTracing',
-  // this is controlled by duration_ms in the TraceConfig.
-  //
-  // TODO: libperfetto should actually stop tracing when we ask it to,
-  // instead of using a hardcoded time.
-  //
-  // The observable may go into #on_error at any time, if the underlying
-  // libperfetto states transition to a failing state.
-  // This usually means the OS is not configured correctly.
-  rxcpp::observable<PerfettoTraceProto> CreateTraceStream(
-      rxcpp::observable<PerfettoStreamCommand> commands);
-
-  // TODO: is this refactor-able into a subscriber factory that takes
-  // the commands-observable as a parameter?
-
-  // TODO: infinite perfetto stream.
-
- private:
-  // XX: why doesn't this just let me pass in a regular Component?
-  PerfettoDependencies::Injector& injector_;
-
-  friend void CollectPerfettoTraceBufferImmediately(
-      RxProducerFactory& producer_factory,
-      const std::string& arg_output_proto);
-};
-
-// An rx Coordination, which will cause a new thread to spawn for each new Worker.
-//
-// Idle-class priority is set for the CPU and IO priorities on the new thread.
-//
-// TODO: move to separate file
-rxcpp::observe_on_one_worker ObserveOnNewIoThread();
-
-}  // namespace iorap::perfetto
-#endif  // IORAP_SRC_PERFETTO_RX_PRODUCER_H_
diff --git a/src/prefetcher/main.cc b/src/prefetcher/main.cc
deleted file mode 100644
index 94ba141..0000000
--- a/src/prefetcher/main.cc
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "common/debug.h"
-#include "common/loggers.h"
-#include "prefetcher/prefetcher_daemon.h"
-
-#include <android-base/parseint.h>
-#include <android-base/logging.h>
-
-#include <iostream>
-#include <optional>
-#include <string_view>
-#include <string>
-#include <vector>
-
-#include <signal.h>
-
-#if defined(IORAP_PREFETCHER_MAIN)
-
-namespace iorap::prefetcher {
-
-void Usage(char** argv) {
-  std::cerr << "Usage: " << argv[0] << " [--input-fd=#] [--output-fd=#]" << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "  Run the readahead daemon which can prefetch files given a command." << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "  Optional flags:" << std::endl;
-  std::cerr << "    --help,-h                  Print this Usage." << std::endl;
-  std::cerr << "    --input-fd,-if             Input FD (default stdin)." << std::endl;
-  std::cerr << "    --output-fd,-of            Output FD (default stdout)." << std::endl;
-  std::cerr << "    --use-sockets,-us          Use AF_UNIX sockets (default off)." << std::endl;
-  std::cerr << "    --command-format=[text|binary],-cf   (default text)." << std::endl;
-  std::cerr << "    --verbose,-v               Set verbosity (default off)." << std::endl;
-  std::cerr << "    --wait,-w                  Wait for key stroke before continuing (default off)." << std::endl;
-  exit(1);
-}
-
-int Main(int argc, char** argv) {
-  // Go to system logcat + stderr when running from command line.
-  android::base::InitLogging(argv, iorap::common::StderrAndLogdLogger{android::base::SYSTEM});
-
-  bool wait_for_keystroke = false;
-  bool enable_verbose = false;
-
-  bool command_format_text = false; // false = binary.
-
-  int arg_input_fd = -1;
-  int arg_output_fd = -1;
-
-  std::vector<std::string> arg_input_filenames;
-  bool arg_use_sockets = false;
-
-  LOG(VERBOSE) << "argparse: argc=" << argc;
-
-  for (int arg = 1; arg < argc; ++arg) {
-    std::string argstr = argv[arg];
-    bool has_arg_next = (arg+1)<argc;
-    std::string arg_next = has_arg_next ? argv[arg+1] : "";
-
-    LOG(VERBOSE) << "argparse: argv[" << arg << "]=" << argstr;
-
-    if (argstr == "--help" || argstr == "-h") {
-      Usage(argv);
-    } else if (argstr == "--input-fd" || argstr == "-if") {
-      if (!has_arg_next) {
-        LOG(ERROR) << "--input-fd=<numeric-value>";
-        Usage(argv);
-      }
-      if (!::android::base::ParseInt(arg_next, /*out*/&arg_input_fd)) {
-        LOG(ERROR) << "--input-fd value must be numeric";
-        Usage(argv);
-      }
-    } else if (argstr == "--output-fd" || argstr == "-of") {
-      if (!has_arg_next) {
-        LOG(ERROR) << "--output-fd=<numeric-value>";
-        Usage(argv);
-      }
-      if (!::android::base::ParseInt(arg_next, /*out*/&arg_output_fd)) {
-        LOG(ERROR) << "--output-fd value must be numeric";
-        Usage(argv);
-      }
-    } else if (argstr == "--command-format=" || argstr == "-cf") {
-      if (!has_arg_next) {
-        LOG(ERROR) << "--command-format=text|binary";
-        Usage(argv);
-      }
-      if (arg_next == "text") {
-        command_format_text = true;
-      } else if (arg_next == "binary") {
-        command_format_text = false;
-      } else {
-        LOG(ERROR) << "--command-format must be one of {text,binary}";
-        Usage(argv);
-      }
-    } else if (argstr == "--use-sockets" || argstr == "-us") {
-      arg_use_sockets = true;
-    } else if (argstr == "--verbose" || argstr == "-v") {
-      enable_verbose = true;
-    } else if (argstr == "--wait" || argstr == "-w") {
-      wait_for_keystroke = true;
-    } else {
-      arg_input_filenames.push_back(argstr);
-    }
-  }
-
-  if (enable_verbose) {
-    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
-
-    LOG(VERBOSE) << "Verbose check";
-    LOG(VERBOSE) << "Debug check: " << ::iorap::kIsDebugBuild;
-  } else {
-    android::base::SetMinimumLogSeverity(android::base::DEBUG);
-  }
-
-  LOG(VERBOSE) << "argparse: argc=" << argc;
-
-  for (int arg = 1; arg < argc; ++arg) {
-    std::string argstr = argv[arg];
-
-    LOG(VERBOSE) << "argparse: argv[" << arg << "]=" << argstr;
-  }
-
-  // Useful to attach a debugger...
-  // 1) $> iorap.cmd.readahead -w <args>
-  // 2) $> gdbclient <pid>
-  if (wait_for_keystroke) {
-    LOG(INFO) << "Self pid: " << getpid();
-
-    raise(SIGSTOP);
-    // LOG(INFO) << "Press any key to continue...";
-    // std::cin >> wait_for_keystroke;
-  }
-
-  // auto system_call = std::make_unique<SystemCallImpl>();
-  // TODO: mock readahead calls?
-  //
-  // Uncomment this if we want to leave the process around to inspect it from adb shell.
-  // sleep(100000);
-
-  int return_code = 0;
-
-  LOG(VERBOSE) << "Hello world";
-
-  if (arg_input_fd == -1) {
-    arg_input_fd = STDIN_FILENO;
-  }
-  if (arg_output_fd == -1) {
-    arg_output_fd = STDOUT_FILENO;
-  }
-
-  PrefetcherForkParameters params{};
-  params.input_fd = arg_input_fd;
-  params.output_fd = arg_output_fd;
-  params.format_text = command_format_text;
-  params.use_sockets = arg_use_sockets;
-
-  LOG(VERBOSE) << "main: Starting PrefetcherDaemon: "
-               << "input_fd=" << params.input_fd
-               << ",output_fd=" << params.output_fd;
-  {
-    PrefetcherDaemon daemon;
-    // Blocks until receiving an exit command.
-    daemon.Main(std::move(params));
-  }
-  LOG(VERBOSE) << "main: Terminating";
-
-  // 0 -> successfully executed all commands.
-  // 1 -> failed along the way (#on_error and also see the error logs).
-  return return_code;
-}
-
-}  // namespace iorap::prefetcher
-
-int main(int argc, char** argv) {
-  return ::iorap::prefetcher::Main(argc, argv);
-}
-
-#endif  // IORAP_PREFETCHER_MAIN
diff --git a/src/prefetcher/main_client.cc b/src/prefetcher/main_client.cc
deleted file mode 100644
index ff7ee6d..0000000
--- a/src/prefetcher/main_client.cc
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "common/debug.h"
-#include "prefetcher/read_ahead.h"
-#include "prefetcher/task_id.h"
-
-#include <android-base/parseint.h>
-#include <android-base/logging.h>
-
-#include <iostream>
-#include <optional>
-#include <string_view>
-#include <string>
-#include <vector>
-
-#include <signal.h>
-#include <unistd.h>
-
-
-namespace iorap::prefetcher {
-
-static void UsageClient(char** argv) {
-  std::cerr << "UsageClient: " << argv[0] << " <path-to-compiled-trace.pb> [... pathN]" << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "  Run the readahead daemon which can prefetch files given a command." << std::endl;
-  std::cerr << "" << std::endl;
-  std::cerr << "  Optional flags:" << std::endl;
-  std::cerr << "    --help,-h                  Print this UsageClient." << std::endl;
-  std::cerr << "    --verbose,-v               Set verbosity (default off)." << std::endl;
-  std::cerr << "    --task-duration-ms,-tdm    Set task duration (default: 0ms)." << std::endl;
-  std::cerr << "    --use-sockets,-us          Use AF_UNIX sockets (default: off)" << std::endl;
-  std::cerr << "    --wait,-w                  Wait for key stroke before continuing (default off)." << std::endl;
-  exit(1);
-}
-
-int MainClient(int argc, char** argv) {
-  android::base::InitLogging(argv);
-  android::base::SetLogger(android::base::StderrLogger);
-
-  bool wait_for_keystroke = false;
-  bool enable_verbose = false;
-
-  bool command_format_text = false; // false = binary.
-
-  unsigned int arg_task_duration_ms = 10000;
-  std::vector<std::string> arg_input_filenames;
-  bool arg_use_sockets = false;
-
-  LOG(VERBOSE) << "argparse: argc=" << argc;
-
-  for (int arg = 1; arg < argc; ++arg) {
-    std::string argstr = argv[arg];
-    bool has_arg_next = (arg+1)<argc;
-    std::string arg_next = has_arg_next ? argv[arg+1] : "";
-
-    LOG(VERBOSE) << "argparse: argv[" << arg << "]=" << argstr;
-
-    if (argstr == "--help" || argstr == "-h") {
-      UsageClient(argv);
-    } else if (argstr == "--use-sockets" || argstr == "-us") {
-      arg_use_sockets = true;
-    } else if (argstr == "--verbose" || argstr == "-v") {
-      enable_verbose = true;
-    } else if (argstr == "--wait" || argstr == "-w") {
-      wait_for_keystroke = true;
-    } else if (argstr == "--task-duration-ms" || argstr == "-tdm") {
-      if (!has_arg_next) {
-        LOG(ERROR) << "--task-duration-ms: requires uint parameter";
-        UsageClient(argv);
-      } else if (!::android::base::ParseUint(arg_next, &arg_task_duration_ms)) {
-        LOG(ERROR) << "--task-duration-ms: requires non-negative parameter";
-        UsageClient(argv);
-      }
-    } else {
-      arg_input_filenames.push_back(argstr);
-    }
-  }
-
-  if (enable_verbose) {
-    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
-
-    LOG(VERBOSE) << "Verbose check";
-    LOG(VERBOSE) << "Debug check: " << ::iorap::kIsDebugBuild;
-  } else {
-    android::base::SetMinimumLogSeverity(android::base::DEBUG);
-  }
-
-  LOG(VERBOSE) << "argparse: argc=" << argc;
-
-  for (int arg = 1; arg < argc; ++arg) {
-    std::string argstr = argv[arg];
-
-    LOG(VERBOSE) << "argparse: argv[" << arg << "]=" << argstr;
-  }
-
-  // Useful to attach a debugger...
-  // 1) $> iorap.cmd.readahead -w <args>
-  // 2) $> gdbclient <pid>
-  if (wait_for_keystroke) {
-    LOG(INFO) << "Self pid: " << getpid();
-
-    raise(SIGSTOP);
-    // LOG(INFO) << "Press any key to continue...";
-    // std::cin >> wait_for_keystroke;
-  }
-
-  // auto system_call = std::make_unique<SystemCallImpl>();
-  // TODO: mock readahead calls?
-  //
-  // Uncomment this if we want to leave the process around to inspect it from adb shell.
-  // sleep(100000);
-
-  int return_code = 0;
-
-  LOG(VERBOSE) << "Hello world";
-
-  ReadAhead read_ahead{arg_use_sockets};  // Don't count the time it takes to fork+exec.
-
-  size_t task_id_counter = 0;
-  for (const std::string& compiled_trace_path : arg_input_filenames) {
-    TaskId task_id{task_id_counter++, compiled_trace_path};
-
-    LOG(DEBUG) << "main: ReadAhead BeginTask: "
-                 << "task_duration_ms=" << arg_task_duration_ms << ","
-                 << task_id;
-
-    read_ahead.BeginTask(task_id);
-    usleep(arg_task_duration_ms*1000);
-
-    LOG(DEBUG) << "main: ReadAhead FinishTask: " << task_id;
-
-    read_ahead.FinishTask(task_id);
-  }
-  LOG(VERBOSE) << "main: Terminating";
-
-  // 0 -> successfully executed all commands.
-  // 1 -> failed along the way (#on_error and also see the error logs).
-  return return_code;
-}
-
-}  // namespace iorap::prefetcher
-
-#if defined(IORAP_PREFETCHER_MAIN_CLIENT)
-int main(int argc, char** argv) {
-  return ::iorap::prefetcher::MainClient(argc, argv);
-}
-
-#endif  // IORAP_PREFETCHER_MAIN_CLIENT
diff --git a/src/prefetcher/minijail.cc b/src/prefetcher/minijail.cc
deleted file mode 100644
index df4b11b..0000000
--- a/src/prefetcher/minijail.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "prefetcher/minijail.h"
-
-#include <android-base/logging.h>
-#include <libminijail.h>
-
-namespace iorap::prefetcher {
-
-static const char kSeccompFilePath[] = "/system/etc/seccomp_policy/iorap.prefetcherd.policy";
-
-bool MiniJail() {
-  /* no seccomp policy for this architecture */
-  if (access(kSeccompFilePath, R_OK) == -1) {
-      LOG(WARNING) << "No seccomp filter defined for this architecture.";
-      return true;
-  }
-
-  struct minijail* jail = minijail_new();
-  if (jail == NULL) {
-      LOG(WARNING) << "Failed to create minijail.";
-      return false;
-  }
-
-  minijail_no_new_privs(jail);
-  minijail_log_seccomp_filter_failures(jail);
-  minijail_use_seccomp_filter(jail);
-  minijail_parse_seccomp_filters(jail, kSeccompFilePath);
-  minijail_enter(jail);
-  minijail_destroy(jail);
-
-  LOG(DEBUG) << "minijail installed.";
-
-  return true;
-}
-
-}
diff --git a/src/prefetcher/minijail.h b/src/prefetcher/minijail.h
deleted file mode 100644
index 9caefe6..0000000
--- a/src/prefetcher/minijail.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_PREFETCHER_MINIJAIL_H
-#define SRC_PREFETCHER_MINIJAIL_H
-
-namespace iorap::prefetcher {
-// Install a minijail using seccomp_policy/prefetcherd.{ARCH}.policy file.
-bool MiniJail();
-}
-
-#endif  // SRC_PREFETCHER_MINIJAIL_H
diff --git a/src/prefetcher/prefetcher_daemon.cc b/src/prefetcher/prefetcher_daemon.cc
deleted file mode 100644
index f4b9087..0000000
--- a/src/prefetcher/prefetcher_daemon.cc
+++ /dev/null
@@ -1,1367 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "prefetcher/minijail.h"
-#include "common/cmd_utils.h"
-#include "prefetcher/prefetcher_daemon.h"
-#include "prefetcher/session_manager.h"
-#include "prefetcher/session.h"
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-
-#include <deque>
-#include <iomanip>
-#include <string>
-#include <sstream>
-#include <vector>
-
-#include <fcntl.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-namespace iorap::prefetcher {
-
-// Gate super-spammy IPC logging behind a property.
-// This is beyond merely annoying, enabling this logging causes prefetching to be about 1000x slower.
-static bool LogVerboseIpc() {
-  static bool initialized = false;
-  static bool verbose_ipc;
-
-  if (initialized == false) {
-    initialized = true;
-
-    verbose_ipc =
-        ::android::base::GetBoolProperty("iorapd.readahead.verbose_ipc", /*default*/false);
-  }
-
-  return verbose_ipc;
-}
-
-static const bool kInstallMiniJail =
-    ::android::base::GetBoolProperty("iorapd.readahead.minijail", /*default*/true);
-
-static constexpr const char kCommandFileName[] = "/system/bin/iorap.prefetcherd";
-
-static constexpr size_t kPipeBufferSize = 1024 * 1024;  // matches /proc/sys/fs/pipe-max-size
-
-using ArgString = const char*;
-
-std::ostream& operator<<(std::ostream& os, ReadAheadKind ps) {
-  switch (ps) {
-    case ReadAheadKind::kFadvise:
-      os << "fadvise";
-      break;
-    case ReadAheadKind::kMmapLocked:
-      os << "mmap";
-      break;
-    case ReadAheadKind::kMlock:
-      os << "mlock";
-      break;
-    default:
-      os << "<invalid>";
-  }
-  return os;
-}
-
-std::ostream& operator<<(std::ostream& os, CommandChoice choice) {
-  switch (choice) {
-    case CommandChoice::kRegisterFilePath:
-      os << "kRegisterFilePath";
-      break;
-    case CommandChoice::kUnregisterFilePath:
-      os << "kUnregisterFilePath";
-      break;
-    case CommandChoice::kReadAhead:
-      os << "kReadAhead";
-      break;
-    case CommandChoice::kExit:
-      os << "kExit";
-      break;
-    case CommandChoice::kCreateSession:
-      os << "kCreateSession";
-      break;
-    case CommandChoice::kDestroySession:
-      os << "kDestroySession";
-      break;
-    case CommandChoice::kDumpSession:
-      os << "kDumpSession";
-      break;
-    case CommandChoice::kDumpEverything:
-      os << "kDumpEverything";
-      break;
-    case CommandChoice::kCreateFdSession:
-      os << "kCreateFdSession";
-      break;
-    default:
-      CHECK(false) << "forgot to handle this choice";
-      break;
-  }
-  return os;
-}
-
-std::ostream& operator<<(std::ostream& os, const Command& command) {
-  os << "Command{";
-  os << "choice=" << command.choice << ",";
-
-  bool has_session_id = true;
-  bool has_id = true;
-  switch (command.choice) {
-    case CommandChoice::kDumpEverything:
-    case CommandChoice::kExit:
-      has_session_id = false;
-      FALLTHROUGH_INTENDED;
-    case CommandChoice::kCreateFdSession:
-    case CommandChoice::kCreateSession:
-    case CommandChoice::kDestroySession:
-    case CommandChoice::kDumpSession:
-      has_id = false;
-      break;
-    default:
-      break;
-  }
-
-  if (has_session_id) {
-    os << "sid=" << command.session_id << ",";
-  }
-
-  if (has_id) {
-    os << "id=" << command.id << ",";
-  }
-
-  switch (command.choice) {
-    case CommandChoice::kRegisterFilePath:
-      os << "file_path=";
-
-      if (command.file_path) {
-        os << *(command.file_path);
-      } else {
-        os << "(nullopt)";
-      }
-      break;
-    case CommandChoice::kUnregisterFilePath:
-      break;
-    case CommandChoice::kReadAhead:
-      os << "read_ahead_kind=" << command.read_ahead_kind << ",";
-      os << "length=" << command.length << ",";
-      os << "offset=" << command.offset << ",";
-      break;
-    case CommandChoice::kExit:
-      break;
-    case CommandChoice::kCreateFdSession:
-      os << "fd=";
-      if (command.fd.has_value()) {
-        os << command.fd.value();
-      } else {
-        os << "(nullopt)";
-      }
-      os << ",";
-    FALLTHROUGH_INTENDED;
-    case CommandChoice::kCreateSession:
-      os << "description=";
-      if (command.file_path) {
-        os << "'" << *(command.file_path) << "'";
-      } else {
-        os << "(nullopt)";
-      }
-      break;
-    case CommandChoice::kDestroySession:
-      break;
-    case CommandChoice::kDumpSession:
-      break;
-    case CommandChoice::kDumpEverything:
-      break;
-    default:
-      CHECK(false) << "forgot to handle this choice";
-      break;
-  }
-
-  os << "}";
-
-  return os;
-}
-
-template <typename T>
-struct ParseResult {
-  T value;
-  char* next_token;
-  size_t stream_size;
-
-  ParseResult() : value{}, next_token{nullptr}, stream_size{} {
-  }
-
-  constexpr operator bool() const {
-    return next_token != nullptr;
-  }
-};
-
-// Very spammy: Keep it off by default. Set to true if changing this code.
-static constexpr bool kDebugParsingRead = false;
-
-#define DEBUG_PREAD if (kDebugParsingRead) LOG(VERBOSE) << "ParsingRead "
-
-
-
-// Parse a strong type T from a buffer stream.
-// If there's insufficient space left to parse the value, an empty ParseResult is returned.
-template <typename T>
-ParseResult<T> ParsingRead(char* stream, size_t stream_size) {
-  if (stream == nullptr) {
-    DEBUG_PREAD << "stream was null";
-    return {};
-  }
-
-  if constexpr (std::is_same_v<T, std::string>) {
-    ParseResult<uint32_t> length = ParsingRead<uint32_t>(stream, stream_size);
-
-    if (!length) {
-      DEBUG_PREAD << "could not find length";
-      // Not enough bytes left?
-      return {};
-    }
-
-    ParseResult<std::string> string_result;
-    string_result.value.reserve(length);
-
-    stream = length.next_token;
-    stream_size = length.stream_size;
-
-    for (size_t i = 0; i < length.value; ++i) {
-      ParseResult<char> char_result = ParsingRead<char>(stream, stream_size);
-
-      stream = char_result.next_token;
-      stream_size = char_result.stream_size;
-
-      if (!char_result) {
-        DEBUG_PREAD << "too few chars in stream, expected length: " << length.value;
-        // Not enough bytes left?
-        return {};
-      }
-
-      string_result.value += char_result.value;
-
-      DEBUG_PREAD << "string preliminary is : " << string_result.value;
-    }
-
-    DEBUG_PREAD << "parsed string to: " << string_result.value;
-    string_result.next_token = stream;
-    return string_result;
-  } else {
-    if (sizeof(T) > stream_size) {
-      return {};
-    }
-
-    ParseResult<T> result;
-    result.next_token = stream + sizeof(T);
-    result.stream_size = stream_size - sizeof(T);
-
-    memcpy(&result.value, stream, sizeof(T));
-
-    return result;
-  }
-}
-
-// Convenience overload to chain multiple ParsingRead together.
-template <typename T, typename U>
-ParseResult<T> ParsingRead(ParseResult<U> result) {
-  return ParsingRead<T>(result.next_token, result.stream_size);
-}
-
-class CommandParser {
- public:
-  CommandParser(PrefetcherForkParameters params) {
-    params_ = params;
-  }
-
-  std::vector<Command> ParseSocketCommands(bool& eof) {
-    eof = false;
-
-    std::vector<Command> commands_vec;
-
-    std::vector<char> buf_vector;
-    buf_vector.resize(1024*1024);  // 1MB.
-    char* buf = &buf_vector[0];
-
-    // Binary only parsing. The higher level code can parse text
-    // with ifstream if it really wants to.
-    char* stream = &buf[0];
-    size_t stream_size = buf_vector.size();
-
-    while (true) {
-      if (stream_size == 0) {
-        // TODO: reply with an overflow command.
-        LOG(WARNING) << "prefetcher_daemon command overflow, dropping all commands.";
-        stream = &buf[0];
-        stream_size = buf_vector.size();
-        memset(&buf[0], /*c*/0, buf_vector.size());
-      }
-
-      if (LogVerboseIpc()) {
-        LOG(VERBOSE) << "PrefetcherDaemon block recvmsg for commands (fd=" << params_.input_fd << ")";
-      }
-
-      ssize_t count;
-      struct msghdr hdr;
-      memset(&hdr, 0, sizeof(hdr));
-
-      {
-        union {
-          struct cmsghdr cmh;
-          char   control[CMSG_SPACE(sizeof(int))];
-        } control_un;
-        memset(&control_un, 0, sizeof(control_un));
-
-        /* Set 'control_un' to describe ancillary data that we want to receive */
-        control_un.cmh.cmsg_len = CMSG_LEN(sizeof(int));  /* fd is sizeof(int) */
-        control_un.cmh.cmsg_level = SOL_SOCKET;
-        control_un.cmh.cmsg_type = SCM_CREDENTIALS;
-
-        // the regular message data will be read into stream
-        struct iovec iov;
-        memset(&iov, 0, sizeof(iov));
-        iov.iov_base = stream;
-        iov.iov_len = stream_size;
-
-        /* Set hdr fields to describe 'control_un' */
-        hdr.msg_control = control_un.control;
-        hdr.msg_controllen = sizeof(control_un.control);
-        hdr.msg_iov = &iov;
-        hdr.msg_iovlen = 1;
-        hdr.msg_name = nullptr; /* no peer address */
-        hdr.msg_namelen = 0;
-
-        count = TEMP_FAILURE_RETRY(recvmsg(params_.input_fd, &hdr, /*flags*/0));
-      }
-
-      if (LogVerboseIpc()) {
-        LOG(VERBOSE) << "PrefetcherDaemon recvmsg " << count << " for stream size:" << stream_size;
-      }
-
-      if (count < 0) {
-        PLOG(ERROR) << "failed to recvmsg from input fd";
-        break;
-        // TODO: let the daemon be restarted by higher level code?
-      } else if (count == 0) {
-        LOG(WARNING) << "prefetcher_daemon input_fd end-of-file; terminating";
-        eof = true;
-        break;
-        // TODO: let the daemon be restarted by higher level code?
-      }
-
-      {
-        /* Extract fd from ancillary data if present */
-        struct cmsghdr* hp;
-        hp = CMSG_FIRSTHDR(&hdr);
-        if (hp                                              &&
-            // FIXME: hp->cmsg_len returns an absurdly large value. is it overflowing?
-            // (hp->cmsg_len == CMSG_LEN(sizeof(int)))          &&
-            (hp->cmsg_level == SOL_SOCKET)                   &&
-            (hp->cmsg_type == SCM_RIGHTS)) {
-
-          int passed_fd = *(int*) CMSG_DATA(hp);
-          if (LogVerboseIpc()) {
-            LOG(VERBOSE) << "PrefetcherDaemon received FD " << passed_fd;
-          }
-
-          // tack the FD into our dequeue.
-          // we assume the FDs are sent in-order same as the regular iov are sent in-order.
-          longbuf_fds_.insert(longbuf_fds_.end(), passed_fd);
-        } else if (hp != nullptr) {
-          if (LogVerboseIpc()) {
-            LOG(VERBOSE) << "PrefetcherDaemon::read got CMSG but it wasn't matching SCM_RIGHTS,"
-                         << "cmsg_len=" << hp->cmsg_len << ","
-                         << "cmsg_level=" << hp->cmsg_level << ","
-                         << "cmsg_type=" << hp->cmsg_type;
-          }
-        }
-      }
-
-      longbuf_.insert(longbuf_.end(), stream, stream + count);
-      if (LogVerboseIpc()) {
-        LOG(VERBOSE) << "PrefetcherDaemon updated longbuf size: " << longbuf_.size();
-      }
-
-      // reconstruct a stream of [iov_Command chdr_fd?]* back into [Command]*
-      {
-        if (longbuf_.size() == 0) {
-          break;
-        }
-
-        std::vector<char> v(longbuf_.begin(),
-                            longbuf_.end());
-
-        std::vector<int> v_fds{longbuf_fds_.begin(), longbuf_fds_.end()};
-
-        if (LogVerboseIpc()) {
-          LOG(VERBOSE) << "PrefetcherDaemon longbuf_ size: " << v.size();
-          if (WOULD_LOG(VERBOSE)) {
-            std::stringstream dump;
-            dump << std::hex << std::setfill('0');
-            for (size_t i = 0; i < v.size(); ++i) {
-              dump << std::setw(2) << static_cast<unsigned>(v[i]);
-            }
-
-            LOG(VERBOSE) << "PrefetcherDaemon longbuf_ dump: " << dump.str();
-          }
-          LOG(VERBOSE) << "PrefetcherDaemon longbuf_fds_ size: " << v_fds.size();
-          if (WOULD_LOG(VERBOSE)) {
-            std::stringstream dump;
-            for (size_t i = 0; i < v_fds.size(); ++i) {
-              dump << v_fds[i] << ", ";
-            }
-
-            LOG(VERBOSE) << "PrefetcherDaemon longbuf_fds_ dump: " << dump.str();
-          }
-
-        }
-
-        size_t v_fds_off = 0;
-        size_t consumed_fds_total = 0;
-
-        size_t v_off = 0;
-        size_t consumed_bytes = std::numeric_limits<size_t>::max();
-        size_t consumed_total = 0;
-
-        while (true) {
-          std::optional<Command> maybe_command;
-          maybe_command = Command::Read(&v[v_off], v.size() - v_off, &consumed_bytes);
-          consumed_total += consumed_bytes;
-          // Normal every time we get to the end of a buffer.
-          if (!maybe_command) {
-              if (LogVerboseIpc()) {
-                LOG(VERBOSE) << "failed to read command, v_off=" << v_off << ",v_size:" << v.size();
-              }
-              break;
-          }
-
-          if (maybe_command->RequiresFd()) {
-            if (v_fds_off < v_fds.size()) {
-              maybe_command->fd = v_fds[v_fds_off++];
-              consumed_fds_total++;
-              if (LogVerboseIpc()) {
-                LOG(VERBOSE) << "Append the FD to " << *maybe_command;
-              }
-            } else {
-              LOG(WARNING) << "Failed to acquire FD for " << *maybe_command;
-            }
-          }
-
-          // in the next pass ignore what we already consumed.
-          v_off += consumed_bytes;
-
-          // true as long we don't hit the 'break' above.
-          DCHECK_EQ(v_off, consumed_total);
-          if (LogVerboseIpc()) {
-            LOG(VERBOSE) << "success to read command, v_off=" << v_off << ",v_size:" << v.size()
-                         << "," << *maybe_command;
-
-            // Pretty-print a single command for debugging/testing.
-            LOG(VERBOSE) << *maybe_command;
-          }
-
-          // add to the commands we parsed.
-          commands_vec.push_back(*maybe_command);
-        }
-
-        // erase however many were consumed
-        longbuf_.erase(longbuf_.begin(), longbuf_.begin() + consumed_total);
-
-        // erase however many FDs were consumed.
-        longbuf_fds_.erase(longbuf_fds_.begin(), longbuf_fds_.begin() + consumed_fds_total);
-      }
-      break;
-    }
-
-    return commands_vec;
-  }
-
-  std::vector<Command> ParseCommands(bool& eof) {
-    eof = false;
-
-    std::vector<Command> commands_vec;
-
-    std::vector<char> buf_vector;
-    buf_vector.resize(kPipeBufferSize);
-    char* buf = &buf_vector[0];
-
-    // Binary only parsing. The higher level code can parse text
-    // with ifstream if it really wants to.
-    char* stream = &buf[0];
-    size_t stream_size = buf_vector.size();
-
-    while (true) {
-      if (stream_size == 0) {
-        // TODO: reply with an overflow command.
-        LOG(WARNING) << "prefetcher_daemon command overflow, dropping all commands.";
-        stream = &buf[0];
-        stream_size = buf_vector.size();
-        memset(&buf[0], /*c*/0, buf_vector.size());
-      }
-
-      if (LogVerboseIpc()) {
-        LOG(VERBOSE) << "PrefetcherDaemon block read for commands (fd=" << params_.input_fd << ")";
-      }
-      ssize_t count = TEMP_FAILURE_RETRY(read(params_.input_fd, stream, stream_size));
-      if (LogVerboseIpc()) {
-        LOG(VERBOSE) << "PrefetcherDaemon::read " << count << " for stream size:" << stream_size;
-      }
-
-      if (count < 0) {
-        PLOG(ERROR) << "failed to read from input fd";
-        break;
-        // TODO: let the daemon be restarted by higher level code?
-      } else if (count == 0) {
-        LOG(WARNING) << "prefetcher_daemon input_fd end-of-file; terminating";
-        eof = true;
-        break;
-        // TODO: let the daemon be restarted by higher level code?
-      }
-
-      longbuf_.insert(longbuf_.end(), stream, stream + count);
-      if (LogVerboseIpc()) {
-        LOG(VERBOSE) << "PrefetcherDaemon updated longbuf size: " << longbuf_.size();
-      }
-
-      std::optional<Command> maybe_command;
-      {
-        if (longbuf_.size() == 0) {
-          break;
-        }
-
-        std::vector<char> v(longbuf_.begin(),
-                            longbuf_.end());
-
-        if (LogVerboseIpc()) {
-          LOG(VERBOSE) << "PrefetcherDaemon longbuf_ size: " << v.size();
-          if (WOULD_LOG(VERBOSE)) {
-            std::stringstream dump;
-            dump << std::hex << std::setfill('0');
-            for (size_t i = 0; i < v.size(); ++i) {
-              dump << std::setw(2) << static_cast<unsigned>(v[i]);
-            }
-
-            LOG(VERBOSE) << "PrefetcherDaemon longbuf_ dump: " << dump.str();
-          }
-        }
-
-        size_t v_off = 0;
-        size_t consumed_bytes = std::numeric_limits<size_t>::max();
-        size_t consumed_total = 0;
-
-        while (true) {
-          maybe_command = Command::Read(&v[v_off], v.size() - v_off, &consumed_bytes);
-          consumed_total += consumed_bytes;
-          // Normal every time we get to the end of a buffer.
-          if (!maybe_command) {
-              if (LogVerboseIpc()) {
-                LOG(VERBOSE) << "failed to read command, v_off=" << v_off << ",v_size:" << v.size();
-              }
-              break;
-          }
-
-          // in the next pass ignore what we already consumed.
-          v_off += consumed_bytes;
-
-          // true as long we don't hit the 'break' above.
-          DCHECK_EQ(v_off, consumed_total);
-          if (LogVerboseIpc()) {
-            LOG(VERBOSE) << "success to read command, v_off=" << v_off << ",v_size:" << v.size()
-                         << "," << *maybe_command;
-
-            // Pretty-print a single command for debugging/testing.
-            LOG(VERBOSE) << *maybe_command;
-          }
-
-          // add to the commands we parsed.
-          commands_vec.push_back(*maybe_command);
-        }
-
-        // erase however many were consumed
-        longbuf_.erase(longbuf_.begin(), longbuf_.begin() + consumed_total);
-      }
-      break;
-    }
-
-    return commands_vec;
-  }
-
- private:
-  bool IsTextMode() const {
-    return params_.format_text;
-  }
-
-  PrefetcherForkParameters params_;
-
-  // A buffer long enough to contain a lot of buffers.
-  // This handles reads that only contain a partial command.
-  std::deque<char> longbuf_;
-
-  // File descriptor buffers.
-  std::deque<int> longbuf_fds_;
-};
-
-static constexpr bool kDebugCommandRead = true;
-
-#define DEBUG_READ if (kDebugCommandRead) LOG(VERBOSE) << "Command::Read "
-
-std::optional<Command> Command::Read(char* buf, size_t buf_size, /*out*/size_t* consumed_bytes) {
-  *consumed_bytes = 0;
-  if (buf == nullptr) {
-    return std::nullopt;
-  }
-
-  Command cmd{};  // zero-initialize any unused fields
-  ParseResult<CommandChoice> parsed_choice = ParsingRead<CommandChoice>(buf, buf_size);
-  cmd.choice = parsed_choice.value;
-
-  if (!parsed_choice) {
-    DEBUG_READ << "no choice";
-    return std::nullopt;
-  }
-
-  switch (parsed_choice.value) {
-    case CommandChoice::kRegisterFilePath: {
-      ParseResult<uint32_t> parsed_session_id = ParsingRead<uint32_t>(parsed_choice);
-      if (!parsed_session_id) {
-        DEBUG_READ << "no parsed session id";
-        return std::nullopt;
-      }
-
-      ParseResult<uint32_t> parsed_id = ParsingRead<uint32_t>(parsed_session_id);
-      if (!parsed_id) {
-        DEBUG_READ << "no parsed id";
-        return std::nullopt;
-      }
-
-      ParseResult<std::string> parsed_file_path = ParsingRead<std::string>(parsed_id);
-
-      if (!parsed_file_path) {
-        DEBUG_READ << "no file path";
-        return std::nullopt;
-      }
-      *consumed_bytes = parsed_file_path.next_token - buf;
-
-      cmd.session_id = parsed_session_id.value;
-      cmd.id = parsed_id.value;
-      cmd.file_path = parsed_file_path.value;
-
-      break;
-    }
-    case CommandChoice::kUnregisterFilePath: {
-      ParseResult<uint32_t> parsed_session_id = ParsingRead<uint32_t>(parsed_choice);
-      if (!parsed_session_id) {
-        DEBUG_READ << "no parsed session id";
-        return std::nullopt;
-      }
-
-      ParseResult<uint32_t> parsed_id = ParsingRead<uint32_t>(parsed_session_id);
-      if (!parsed_id) {
-        DEBUG_READ << "no parsed id";
-        return std::nullopt;
-      }
-      *consumed_bytes = parsed_id.next_token - buf;
-
-      cmd.session_id = parsed_session_id.value;
-      cmd.id = parsed_id.value;
-
-      break;
-    }
-    case CommandChoice::kReadAhead: {
-      ParseResult<uint32_t> parsed_session_id = ParsingRead<uint32_t>(parsed_choice);
-      if (!parsed_session_id) {
-        DEBUG_READ << "no parsed session id";
-        return std::nullopt;
-      }
-
-      ParseResult<uint32_t> parsed_id = ParsingRead<uint32_t>(parsed_session_id);
-      if (!parsed_id) {
-        DEBUG_READ << "no parsed id";
-        return std::nullopt;
-      }
-
-      ParseResult<ReadAheadKind> parsed_kind = ParsingRead<ReadAheadKind>(parsed_id);
-      if (!parsed_kind) {
-        DEBUG_READ << "no parsed kind";
-        return std::nullopt;
-      }
-      ParseResult<uint64_t> parsed_length = ParsingRead<uint64_t>(parsed_kind);
-      if (!parsed_length) {
-        DEBUG_READ << "no parsed length";
-        return std::nullopt;
-      }
-      ParseResult<uint64_t> parsed_offset = ParsingRead<uint64_t>(parsed_length);
-      if (!parsed_offset) {
-        DEBUG_READ << "no parsed offset";
-        return std::nullopt;
-      }
-      *consumed_bytes = parsed_offset.next_token - buf;
-
-      cmd.session_id = parsed_session_id.value;
-      cmd.id = parsed_id.value;
-      cmd.read_ahead_kind = parsed_kind.value;
-      cmd.length = parsed_length.value;
-      cmd.offset = parsed_offset.value;
-
-      break;
-    }
-    case CommandChoice::kCreateSession:
-    case CommandChoice::kCreateFdSession: {
-      ParseResult<uint32_t> parsed_session_id = ParsingRead<uint32_t>(parsed_choice);
-      if (!parsed_session_id) {
-        DEBUG_READ << "no parsed session id";
-        return std::nullopt;
-      }
-
-      ParseResult<std::string> parsed_description = ParsingRead<std::string>(parsed_session_id);
-
-      if (!parsed_description) {
-        DEBUG_READ << "no description";
-        return std::nullopt;
-      }
-      *consumed_bytes = parsed_description.next_token - buf;
-
-      cmd.session_id = parsed_session_id.value;
-      cmd.file_path = parsed_description.value;
-
-      break;
-    }
-    case CommandChoice::kDestroySession:
-    case CommandChoice::kDumpSession: {
-      ParseResult<uint32_t> parsed_session_id = ParsingRead<uint32_t>(parsed_choice);
-      if (!parsed_session_id) {
-        DEBUG_READ << "no parsed session id";
-        return std::nullopt;
-      }
-
-      *consumed_bytes = parsed_session_id.next_token - buf;
-
-      cmd.session_id = parsed_session_id.value;
-
-      break;
-    }
-    case CommandChoice::kExit:
-    case CommandChoice::kDumpEverything:
-      *consumed_bytes = parsed_choice.next_token - buf;
-      // Only need to parse the choice.
-      break;
-    default:
-      LOG(FATAL) << "unrecognized command number " << static_cast<uint32_t>(parsed_choice.value);
-      break;
-  }
-
-  return cmd;
-}
-
-bool Command::Write(char* buf, size_t buf_size, /*out*/size_t* produced_bytes) const {
-  *produced_bytes = 0;
-  if (buf == nullptr) {
-    LOG(WARNING) << "null buf, is this expected?";
-    return false;
-  }
-
-  bool has_enough_space = false;
-  size_t space_requirement = std::numeric_limits<size_t>::max();
-
-  space_requirement = sizeof(choice);
-
-  switch (choice) {
-    case CommandChoice::kRegisterFilePath:
-      space_requirement += sizeof(session_id);
-      space_requirement += sizeof(id);
-      space_requirement += sizeof(uint32_t);    // string length
-
-      if (!file_path) {
-        LOG(WARNING) << "Missing file path for kRegisterFilePath";
-        return false;
-      }
-
-      space_requirement += file_path->size(); // string contents
-      break;
-    case CommandChoice::kUnregisterFilePath:
-      space_requirement += sizeof(session_id);
-      space_requirement += sizeof(id);
-      break;
-    case CommandChoice::kReadAhead:
-      space_requirement += sizeof(session_id);
-      space_requirement += sizeof(id);
-      space_requirement += sizeof(read_ahead_kind);
-      space_requirement += sizeof(length);
-      space_requirement += sizeof(offset);
-      break;
-    case CommandChoice::kCreateSession:
-    case CommandChoice::kCreateFdSession:
-      space_requirement += sizeof(session_id);
-      space_requirement += sizeof(uint32_t);    // string length
-
-      if (!file_path) {
-        LOG(WARNING) << "Missing file path for kCreateSession";
-        return false;
-      }
-
-      space_requirement += file_path->size(); // string contents
-      break;
-    case CommandChoice::kDestroySession:
-    case CommandChoice::kDumpSession:
-      space_requirement += sizeof(session_id);
-      break;
-    case CommandChoice::kExit:
-    case CommandChoice::kDumpEverything:
-      // Only need space for the choice.
-      break;
-    default:
-      LOG(FATAL) << "unrecognized command number " << static_cast<uint32_t>(choice);
-      break;
-  }
-
-  if (buf_size < space_requirement) {
-    return false;
-  }
-
-  *produced_bytes = space_requirement;
-
-  // Always write out the choice.
-  size_t buf_offset = 0;
-
-  memcpy(&buf[buf_offset], &choice, sizeof(choice));
-  buf_offset += sizeof(choice);
-
-  switch (choice) {
-    case CommandChoice::kRegisterFilePath:
-      memcpy(&buf[buf_offset], &session_id, sizeof(session_id));
-      buf_offset += sizeof(session_id);
-      memcpy(&buf[buf_offset], &id, sizeof(id));
-      buf_offset += sizeof(id);
-
-      {
-        uint32_t string_length = static_cast<uint32_t>(file_path->size());
-        memcpy(&buf[buf_offset], &string_length, sizeof(string_length));
-        buf_offset += sizeof(string_length);
-      }
-
-      DCHECK(file_path.has_value());
-
-      memcpy(&buf[buf_offset], file_path->c_str(), file_path->size());
-      buf_offset += file_path->size();
-      break;
-    case CommandChoice::kUnregisterFilePath:
-      memcpy(&buf[buf_offset], &session_id, sizeof(session_id));
-      buf_offset += sizeof(session_id);
-      memcpy(&buf[buf_offset], &id, sizeof(id));
-      buf_offset += sizeof(id);
-      break;
-    case CommandChoice::kReadAhead:
-      memcpy(&buf[buf_offset], &session_id, sizeof(session_id));
-      buf_offset += sizeof(session_id);
-      memcpy(&buf[buf_offset], &id, sizeof(id));
-      buf_offset += sizeof(id);
-      memcpy(&buf[buf_offset], &read_ahead_kind, sizeof(read_ahead_kind));
-      buf_offset += sizeof(read_ahead_kind);
-      memcpy(&buf[buf_offset], &length, sizeof(length));
-      buf_offset += sizeof(length);
-      memcpy(&buf[buf_offset], &offset, sizeof(offset));
-      buf_offset += sizeof(offset);
-      break;
-    case CommandChoice::kCreateSession:
-    case CommandChoice::kCreateFdSession:
-      memcpy(&buf[buf_offset], &session_id, sizeof(session_id));
-      buf_offset += sizeof(session_id);
-
-      {
-        uint32_t string_length = static_cast<uint32_t>(file_path->size());
-        memcpy(&buf[buf_offset], &string_length, sizeof(string_length));
-        buf_offset += sizeof(string_length);
-      }
-
-      DCHECK(file_path.has_value());
-
-      memcpy(&buf[buf_offset], file_path->c_str(), file_path->size());
-      buf_offset += file_path->size();
-
-      DCHECK_EQ(buf_offset, space_requirement) << *this << ",file_path_size:" << file_path->size();
-      DCHECK_EQ(buf_offset, *produced_bytes) << *this;
-
-      break;
-    case CommandChoice::kDestroySession:
-    case CommandChoice::kDumpSession:
-      memcpy(&buf[buf_offset], &session_id, sizeof(session_id));
-      buf_offset += sizeof(session_id);
-      break;
-    case CommandChoice::kExit:
-    case CommandChoice::kDumpEverything:
-      // Only need to write out the choice.
-      break;
-    default:
-      LOG(FATAL) << "should have fallen out in the above switch"
-                 << static_cast<uint32_t>(choice);
-      break;
-  }
-
-  DCHECK_EQ(buf_offset, space_requirement) << *this;
-  DCHECK_EQ(buf_offset, *produced_bytes) << *this;
-
-  return true;
-}
-
-class PrefetcherDaemon::Impl {
- public:
-  std::optional<PrefetcherForkParameters> StartPipesViaFork() {
-    int pipefds[2];
-    if (pipe(&pipefds[0]) != 0) {
-      PLOG(FATAL) << "Failed to create read/write pipes";
-    }
-
-    if (WOULD_LOG(VERBOSE)) {
-      long pipe_size = static_cast<long>(fcntl(pipefds[0], F_GETPIPE_SZ));
-      if (pipe_size < 0) {
-        PLOG(ERROR) << "Failed to F_GETPIPE_SZ:";
-      }
-      LOG(VERBOSE) << "StartPipesViaFork: default pipe size: " << pipe_size;
-    }
-
-    for (int i = 0; i < 2; ++i) {
-      // Default pipe size is usually 64KB.
-      // Increase to 1MB so that iorapd has to rarely run during prefetching.
-      if (fcntl(pipefds[i], F_SETPIPE_SZ, kPipeBufferSize) < 0) {
-        PLOG(FATAL) << "Failed to increase pipe size to max";
-      }
-    }
-
-    pipefd_read_ = pipefds[0];
-    pipefd_write_ = pipefds[1];
-
-    PrefetcherForkParameters params;
-    params.input_fd = pipefd_read_;
-    params.output_fd = pipefd_write_;
-    params.format_text = false;
-    params.use_sockets = false;
-
-    bool res = StartViaFork(params);
-    if (res) {
-      return params;
-    } else {
-      return std::nullopt;
-    }
-  }
-
-std::optional<PrefetcherForkParameters> StartSocketViaFork() {
-    int socket_fds[2];
-    if (socketpair(AF_UNIX, SOCK_STREAM, /*protocol*/0, &socket_fds[0]) != 0) {
-      PLOG(FATAL) << "Failed to create read/write socketpair";
-    }
-
-    pipefd_read_ = socket_fds[0];  // iorapd writer, iorap.prefetcherd reader
-    pipefd_write_ = socket_fds[1]; // iorapd reader, iorap.prefetcherd writer
-
-    PrefetcherForkParameters params;
-    params.input_fd = pipefd_read_;
-    params.output_fd = pipefd_write_;
-    params.format_text = false;
-    params.use_sockets = true;
-
-    bool res = StartViaFork(params);
-    if (res) {
-      return params;
-    } else {
-      return std::nullopt;
-    }
-  }
-
-  bool StartViaFork(PrefetcherForkParameters params) {
-    params_ = params;
-
-    forked_ = true;
-    child_ = fork();
-
-    if (child_ == -1) {
-      LOG(FATAL) << "Failed to fork PrefetcherDaemon";
-    } else if (child_ > 0) {  // we are the caller of this function
-      LOG(DEBUG) << "forked into iorap.prefetcherd, pid = " << child_;
-
-      return true;
-    } else {
-      // we are the child that was forked.
-      std::stringstream argv;  // for logging
-      std::vector<std::string> argv_vec;
-
-      {
-        std::stringstream s;
-        s << "--input-fd";
-        argv_vec.push_back(s.str());
-
-        std::stringstream s2;
-        s2 << params.input_fd;
-        argv_vec.push_back(s2.str());
-
-        argv << " --input-fd" << " " << params.input_fd;
-      }
-
-      {
-        std::stringstream s;
-        s << "--output-fd";
-        argv_vec.push_back(s.str());
-
-        std::stringstream s2;
-        s2 << params.output_fd;
-        argv_vec.push_back(s2.str());
-
-        argv << " --output-fd" << " " << params.output_fd;
-      }
-
-
-      if (params.use_sockets) {
-        std::stringstream s;
-        s << "--use-sockets";
-        argv_vec.push_back(s.str());
-
-        argv << " --use-sockets";
-      }
-
-      if (WOULD_LOG(VERBOSE)) {
-        std::stringstream s;
-        s << "--verbose";
-        argv_vec.push_back(s.str());
-
-        argv << " --verbose";
-      }
-
-      std::unique_ptr<ArgString[]> argv_ptr = common::VecToArgv(kCommandFileName, argv_vec);
-
-      LOG(DEBUG) << "fork+exec: " << kCommandFileName << " "
-                 << argv.str();
-      execve(kCommandFileName, (char **)argv_ptr.get(), /*envp*/nullptr);
-      // This should never return.
-      _exit(EXIT_FAILURE);
-    }
-
-    DCHECK(false);
-    return false;
-  }
-
-  // TODO: Not very useful since this can never return 'true'
-  // -> in the child we would've already execd which loses all this code.
-  bool IsDaemon() {
-    // In the child the pid is always 0.
-    return child_ > 0;
-  }
-
-  bool Main(PrefetcherForkParameters params) {
-    LOG(VERBOSE) << "PrefetcherDaemon::Main " << params;
-
-    CommandParser command_parser{params};
-
-    Command next_command{};
-
-    std::vector<Command> many_commands;
-
-    // Ensure alogd is pre-initialized before installing minijail.
-    LOG(DEBUG) << "Installing minijail";
-
-    // Install seccomp filter using libminijail.
-    if (kInstallMiniJail) {
-      MiniJail();
-    }
-
-    while (true) {
-      bool eof = false;
-
-      if (params.use_sockets) {
-        // use recvmsg(2). supports receiving FDs.
-        many_commands = command_parser.ParseSocketCommands(/*out*/eof);
-      } else {
-        // use read(2). does not support receiving FDs.
-        many_commands = command_parser.ParseCommands(/*out*/eof);
-      }
-
-      if (eof) {
-        LOG(WARNING) << "PrefetcherDaemon got EOF, terminating";
-        return true;
-      }
-
-      for (auto& command : many_commands) {
-        if (LogVerboseIpc()) {
-          LOG(VERBOSE) << "PrefetcherDaemon got command: " << command;
-        }
-
-        if (command.choice == CommandChoice::kExit) {
-          LOG(DEBUG) << "PrefetcherDaemon got kExit command, terminating";
-          return true;
-        }
-
-        if (!ReceiveCommand(command)) {
-          // LOG(WARNING) << "PrefetcherDaemon command processing failure: " << command;
-        }
-
-        // ReceiveCommand should dup to keep the FD. Avoid leaks.
-        if (command.fd.has_value()) {
-          close(*command.fd);
-        }
-      }
-    }
-
-    LOG(VERBOSE) << "PrefetcherDaemon::Main got exit, terminating";
-
-    return true;
-    // Terminate.
-  }
-
-  Impl(PrefetcherDaemon* daemon) {
-    session_manager_ = SessionManager::CreateManager(SessionKind::kInProcessDirect);
-    DCHECK(session_manager_ != nullptr);
-  };
-
-  ~Impl() {
-    // Don't do anything if we never called 'StartViaFork'
-    if (forked_) {
-      if (!IsDaemon()) {
-        int status;
-        waitpid(child_, /*out*/&status, /*options*/0);
-      } else {
-        LOG(WARNING) << "execve should have avoided this path";
-        // DCHECK(false) << "not possible because the execve would avoid this path";
-      }
-    }
-  }
-
-  bool SendCommand(const Command& command) {
-    // Only parent is the sender.
-    DCHECK(forked_);
-    //DCHECK(!IsDaemon());
-
-    char buf[1024];
-    size_t stream_size;
-    if (!command.Write(buf, sizeof(buf), /*out*/&stream_size)) {
-      PLOG(ERROR) << "Failed to serialize command: " << command;
-      return false;
-    }
-
-    if (LogVerboseIpc()) {
-      LOG(VERBOSE) << "pre-write(fd=" << pipefd_write_ << ", buf=" << buf
-                   << ", size=" << stream_size<< ")";
-    }
-
-    if (params_.use_sockets) {
-      /* iov contains the normal message (Command) */
-      struct iovec iov;
-      memset(&iov, 0, sizeof(iov));
-      iov.iov_base = &buf[0];
-      iov.iov_len = stream_size;
-
-      struct msghdr msg;
-      memset(&msg, 0, sizeof(msg));
-
-      /* point to iov to transmit */
-      msg.msg_iov = &iov;
-      msg.msg_iovlen = 1;
-
-      /* no dest address; socket is connected */
-      msg.msg_name = nullptr;
-      msg.msg_namelen = 0;
-
-      // append a CMSG with SCM_RIGHTS if we have an FD.
-      if (command.fd.has_value()) {
-          union {
-            struct cmsghdr cmh;
-            char   control[CMSG_SPACE(sizeof(int))]; /* sized to hold an fd (int) */
-          } control_un;
-          memset(&control_un, 0, sizeof(control_un));
-
-          msg.msg_control = &control_un.control[0];
-          msg.msg_controllen = sizeof(control_un.control);
-
-          struct cmsghdr *hp;
-          hp = CMSG_FIRSTHDR(&msg);
-          hp->cmsg_len = CMSG_LEN(sizeof(int));
-          hp->cmsg_level = SOL_SOCKET;
-          hp->cmsg_type = SCM_RIGHTS;
-          *((int *) CMSG_DATA(hp)) = *(command.fd);
-
-          DCHECK(command.RequiresFd()) << command;
-
-          if (LogVerboseIpc()) {
-            LOG(VERBOSE) << "append FD to sendmsg: " << *(command.fd);
-          }
-      }
-
-      // TODO: add CMSG for the FD passage.
-
-      if (TEMP_FAILURE_RETRY(sendmsg(pipefd_write_, &msg, /*flags*/0)) < 0) {
-        PLOG(ERROR) << "Failed to sendmsg command: " << command;
-        return false;
-      }
-    } else {
-      if (TEMP_FAILURE_RETRY(write(pipefd_write_, buf, stream_size)) < 0) {
-        PLOG(ERROR) << "Failed to write command: " << command;
-        return false;
-      }
-    }
-
-    if (LogVerboseIpc()) {
-      LOG(VERBOSE) << "write(fd=" << pipefd_write_ << ", buf=" << buf
-                   << ", size=" << stream_size<< ")";
-    }
-
-    // TODO: also read the reply?
-    return true;
-  }
-
-  bool ReceiveCommand(const Command& command) {
-    // Only child is the command receiver.
-    // DCHECK(IsDaemon());
-
-    switch (command.choice) {
-      case CommandChoice::kRegisterFilePath: {
-        std::shared_ptr<Session> session = session_manager_->FindSession(command.session_id);
-
-        if (!session) {
-          LOG(ERROR) << "ReceiveCommand: Could not find session for command: " << command;
-          return false;
-        }
-
-        CHECK(command.file_path.has_value()) << command;
-        return session->RegisterFilePath(command.id, *command.file_path);
-      }
-      case CommandChoice::kUnregisterFilePath: {
-        std::shared_ptr<Session> session = session_manager_->FindSession(command.session_id);
-
-        if (!session) {
-          LOG(ERROR) << "ReceiveCommand: Could not find session for command: " << command;
-          return false;
-        }
-
-        return session->UnregisterFilePath(command.id);
-      }
-      case CommandChoice::kReadAhead: {
-        std::shared_ptr<Session> session = session_manager_->FindSession(command.session_id);
-
-        if (!session) {
-          LOG(ERROR) << "ReceiveCommand: Could not find session for command: " << command;
-          return false;
-        }
-
-        return session->ReadAhead(command.id, command.read_ahead_kind, command.length, command.offset);
-      }
-      // TODO: unreadahead
-      case CommandChoice::kExit: {
-        LOG(WARNING) << "kExit should be handled earlier.";
-        return true;
-      }
-      case CommandChoice::kCreateSession: {
-        std::shared_ptr<Session> session = session_manager_->FindSession(command.session_id);
-        if (session != nullptr) {
-          LOG(ERROR) << "ReceiveCommand: session for ID already exists: " << command;
-          return false;
-        }
-        CHECK(command.file_path.has_value()) << command;
-        if (session_manager_->CreateSession(command.session_id, /*description*/*command.file_path)
-                == nullptr) {
-          LOG(ERROR) << "ReceiveCommand: Failure to kCreateSession: " << command;
-          return false;
-        }
-        return true;
-      }
-      case CommandChoice::kDestroySession: {
-        if (!session_manager_->DestroySession(command.session_id)) {
-          LOG(ERROR) << "ReceiveCommand: Failure to kDestroySession: " << command;
-          return false;
-        }
-        return true;
-      }
-      case CommandChoice::kDumpSession: {
-        std::shared_ptr<Session> session = session_manager_->FindSession(command.session_id);
-
-        if (!session) {
-          LOG(ERROR) << "ReceiveCommand: Could not find session for command: " << command;
-          return false;
-        }
-
-        // TODO: Consider doing dumpsys support somehow?
-        session->Dump(LOG_STREAM(DEBUG), /*multiline*/true);
-        return true;
-      }
-      case CommandChoice::kDumpEverything: {
-        session_manager_->Dump(LOG_STREAM(DEBUG), /*multiline*/true);
-        break;
-      }
-      case CommandChoice::kCreateFdSession: {
-        std::shared_ptr<Session> session = session_manager_->FindSession(command.session_id);
-        if (session != nullptr) {
-          LOG(ERROR) << "ReceiveCommand: session for ID already exists: " << command;
-          return false;
-        }
-        CHECK(command.file_path.has_value()) << command;
-        CHECK(command.fd.has_value()) << command;
-
-        LOG(VERBOSE) << "ReceiveCommand: kCreateFdSession fd=" << *(command.fd);
-
-        // TODO: Maybe use CreateFdSession instead?
-        session =
-            session_manager_->CreateSession(command.session_id,
-                                            /*description*/*command.file_path,
-                                            command.fd.value());
-        if (session == nullptr) {
-          LOG(ERROR) << "ReceiveCommand: Failure to kCreateFdSession: " << command;
-          return false;
-        }
-
-        return session->ProcessFd(*command.fd);
-      }
-    }
-
-    return true;
-  }
-
-  pid_t child_;
-  bool forked_;
-  int pipefd_read_;
-  int pipefd_write_;
-  PrefetcherForkParameters params_;
-  // do not ever use an indirect session manager here, as it would cause a lifetime cycle.
-  std::unique_ptr<SessionManager> session_manager_; // direct only.
-};
-
-PrefetcherDaemon::PrefetcherDaemon()
-  : impl_{new Impl{this}} {
-  LOG(VERBOSE) << "PrefetcherDaemon() constructor";
-}
-
-bool PrefetcherDaemon::StartViaFork(PrefetcherForkParameters params) {
-  return impl_->StartViaFork(std::move(params));
-}
-
-
-std::optional<PrefetcherForkParameters> PrefetcherDaemon::StartPipesViaFork() {
-  return impl_->StartPipesViaFork();
-}
-
-std::optional<PrefetcherForkParameters> PrefetcherDaemon::StartSocketViaFork() {
-  return impl_->StartSocketViaFork();
-}
-
-bool PrefetcherDaemon::Main(PrefetcherForkParameters params) {
-  return impl_->Main(params);
-}
-
-bool PrefetcherDaemon::SendCommand(const Command& command) {
-  return impl_->SendCommand(command);
-}
-
-PrefetcherDaemon::~PrefetcherDaemon() {
-  // required for unique_ptr for incomplete types.
-}
-
-}  // namespace iorap::prefetcher
diff --git a/src/prefetcher/prefetcher_daemon.h b/src/prefetcher/prefetcher_daemon.h
deleted file mode 100644
index 693f871..0000000
--- a/src/prefetcher/prefetcher_daemon.h
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef PREFETCHER_DAEMON_H_
-#define PREFETCHER_DAEMON_H_
-
-#include "prefetcher/session_manager.h"
-
-#include <memory>
-#include <optional>
-#include <ostream>
-
-namespace iorap {
-namespace prefetcher {
-
-struct PrefetcherForkParameters {
-  int input_fd;
-  int output_fd;
-  bool use_sockets;  // use the socket path instead of simpler read/write path.
-  bool format_text;  // true=>text, false=>binary
-};
-
-inline std::ostream& operator<<(std::ostream& os, const PrefetcherForkParameters& p) {
-  os << "PrefetcherForkParameters{";
-  os << "input_fd=" << p.input_fd << ",";
-  os << "output_fd=" << p.output_fd << ",";
-  os << "format_text=" << p.format_text << ",";
-  os << "use_sockets=" << p.use_sockets << ",";
-  os << "}";
-  return os;
-}
-
-
-#ifndef READ_AHEAD_KIND
-enum class ReadAheadKind : uint32_t {
-  kFadvise = 0,
-  kMmapLocked = 1,
-  kMlock = 2,
-};
-#define READ_AHEAD_KIND 1
-#endif
-
-std::ostream& operator<<(std::ostream& os, ReadAheadKind k);
-
-enum class CommandChoice : uint32_t {
-  kRegisterFilePath,   // kRegisterFilePath <sid:uint32> <id:uint32> <path:c-string>
-  kUnregisterFilePath, // kUnregisterFilePath <sid:uint32> <id:uint32>
-  kReadAhead,          // kReadAhead <sid:uint32> <id:uint32> <kind:uint32_t> <length:uint64> <offset:uint64>
-  kExit,               // kExit
-  kCreateSession,      // kCreateSession <sid:uint32> <description:c-string>
-  kDestroySession,     // kDestroySession <sid:uint32>
-  kDumpSession,        // kDumpSession <sid:uint32>
-  kDumpEverything,     // kDumpEverything
-  kCreateFdSession,    // kCreateFdSession $CMSG{<fd:int>} <sid:uint32> <description:c-string>
-};
-
-struct Command {
-  CommandChoice choice;
-  uint32_t session_id;
-  uint32_t id;  // file_path_id
-  std::optional<std::string> file_path;  // required for choice=kRegisterFilePath.
-  // also serves as the description for choice=kCreateSession
-
-  // choice=kReadAhead
-  ReadAheadKind read_ahead_kind;
-  uint64_t length;
-  uint64_t offset;
-
-  std::optional<int> fd;  // only valid in kCreateFdSession.
-
-  // Deserialize from a char buffer.
-  // This can only fail if buf_size is too small.
-  static std::optional<Command> Read(char* buf, size_t buf_size, /*out*/size_t* consumed_bytes);
-  // Serialize to a char buffer.
-  // This can only fail if the buf_size is too small.
-  bool Write(char* buf, size_t buf_size, /*out*/size_t* produced_bytes) const;
-
-  bool RequiresFd() const {
-    return choice == CommandChoice::kCreateFdSession;
-  }
-};
-
-std::ostream& operator<<(std::ostream& os, const Command& command);
-
-class PrefetcherDaemon {
- public:
-  PrefetcherDaemon();
-  ~PrefetcherDaemon();
-
-  // Asynchronously launch a new fork.
-  //
-  // The destructor will waitpid automatically on the child process.
-  bool StartViaFork(PrefetcherForkParameters params);
-
-  // Launch a new fork , returning the pipes as input/output fds.
-  std::optional<PrefetcherForkParameters> StartPipesViaFork();
-
-  // Launch a new fork , returning the socket pair as input/output fds.
-  std::optional<PrefetcherForkParameters> StartSocketViaFork();
-
-  // Execute the main code in-process.
-  //
-  // Intended as the execve target.
-  bool Main(PrefetcherForkParameters params);
-
-  // Send a command via IPC.
-  // The caller must be the parent process after using StartViaFork.
-  bool SendCommand(const Command& command);
-
- private:
-  class Impl;
-  std::unique_ptr<PrefetcherDaemon::Impl> impl_;
-};
-
-}  // namespace prefetcher
-}  // namespace iorap
-
-#endif
-
diff --git a/src/prefetcher/read_ahead.cc b/src/prefetcher/read_ahead.cc
deleted file mode 100644
index 8759f32..0000000
--- a/src/prefetcher/read_ahead.cc
+++ /dev/null
@@ -1,447 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "read_ahead.h"
-
-#include "common/trace.h"
-#include "prefetcher/session_manager.h"
-#include "prefetcher/session.h"
-#include "prefetcher/task_id.h"
-#include "serialize/arena_ptr.h"
-#include "serialize/protobuf_io.h"
-
-#include <android-base/chrono_utils.h>
-#include <android-base/logging.h>
-#include <android-base/scopeguard.h>
-#include <android-base/properties.h>
-#include <android-base/unique_fd.h>
-#include <cutils/trace.h>
-#include <deque>
-#include <fcntl.h>
-#include <functional>
-#include <stdint.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unordered_map>
-#include <utils/Printer.h>
-
-namespace iorap {
-namespace prefetcher {
-
-enum class PrefetchStrategy {
-  kFadvise = 0,
-  kMmapLocked = 1,
-  kMlock = 2,
-};
-
-std::ostream& operator<<(std::ostream& os, PrefetchStrategy ps) {
-  switch (ps) {
-    case PrefetchStrategy::kFadvise:
-      os << "fadvise";
-      break;
-    case PrefetchStrategy::kMmapLocked:
-      os << "mmap";
-      break;
-    case PrefetchStrategy::kMlock:
-      os << "mlock";
-      break;
-    default:
-      os << "<invalid>";
-  }
-  return os;
-}
-
-static constexpr PrefetchStrategy kPrefetchStrategy = PrefetchStrategy::kFadvise;
-static uint64_t kMaxPrefetchBytes = ::android::base::GetUintProperty<uint64_t>(
-    "iorapd.max_prefetch_bytes", /*default*/100 * 1024 * 1024); // 100MB by default
-
-static PrefetchStrategy GetPrefetchStrategy() {
-  PrefetchStrategy strat = PrefetchStrategy::kFadvise;
-
-  std::string prefetch_env =
-      ::android::base::GetProperty("iorapd.readahead.strategy", /*default*/"");
-
-  if (prefetch_env == "") {
-    LOG(VERBOSE)
-        << "ReadAhead strategy defaulted. Did you want to set iorapd.readahead.strategy ?";
-  } else if (prefetch_env == "mmap") {
-    strat = PrefetchStrategy::kMmapLocked;
-    LOG(VERBOSE) << "ReadAhead strategy: kMmapLocked";
-  } else if (prefetch_env == "mlock") {
-    strat = PrefetchStrategy::kMlock;
-    LOG(VERBOSE) << "ReadAhead strategy: kMlock";
-  } else if (prefetch_env == "fadvise") {
-    strat = PrefetchStrategy::kFadvise;
-    LOG(VERBOSE) << "ReadAhead strategy: kFadvise";
-  } else {
-    LOG(WARNING) << "Unknown iorapd.readahead.strategy: " << prefetch_env << ", ignoring";
-  }
-
-  return strat;
-}
-
-struct TaskData {
-  TaskId task_id;   // also the session ID.
-
-  size_t SessionId() const {
-    if (session != nullptr) {
-      DCHECK_EQ(session->SessionId(), task_id.id);
-    }
-
-    // good enough to be used as the session ID. Task IDs are always monotonically increasing.
-    return task_id.id;
-  }
-
-  std::shared_ptr<Session> session;
-  int32_t trace_cookie;  // async trace cookie in BeginTask/FinishTask.
-};
-
-// Remember the last 5 files being prefetched.
-static constexpr size_t kRecentDataCount = 5;
-
-struct RecentData {
-  TaskId task_id;
-  size_t file_lengths_sum;
-};
-
-struct RecentDataKeeper {
-  std::deque<RecentData> recents_;
-  std::mutex mutex_;
-
-  void RecordRecent(TaskId task_id, size_t file_lengths_sum) {
-    std::lock_guard<std::mutex> guard{mutex_};
-
-    while (recents_.size() > kRecentDataCount) {
-      recents_.pop_front();
-    }
-    recents_.push_back(RecentData{std::move(task_id), file_lengths_sum});
-  }
-
-  void Dump(/*borrow*/::android::Printer& printer) {
-    bool locked = mutex_.try_lock();
-
-    printer.printFormatLine("Recent prefetches:");
-    if (!locked) {
-      printer.printLine("""""  (possible deadlock)");
-    }
-
-    for (const RecentData& data : recents_) {
-      printer.printFormatLine("  %s", data.task_id.path.c_str());
-      printer.printFormatLine("    Task ID: %zu", data.task_id.id);
-      printer.printFormatLine("    Bytes count: %zu", data.file_lengths_sum);
-    }
-
-    if (recents_.empty()) {
-      printer.printFormatLine("  (None)");
-    }
-
-    printer.printLine("");
-
-    if (locked) {
-      mutex_.unlock();
-    }
-  }
-};
-
-struct ReadAhead::Impl {
-  Impl(bool use_sockets) {
-    // Flip this property to test in-process vs out-of-process for the prefetcher code.
-    bool out_of_process =
-        ::android::base::GetBoolProperty("iorapd.readahead.out_of_process", /*default*/true);
-
-    SessionKind session_kind =
-        out_of_process ? SessionKind::kOutOfProcessIpc : SessionKind::kInProcessDirect;
-
-    if (use_sockets) {
-      session_kind = SessionKind::kOutOfProcessSocket;
-    }
-
-    session_manager_ = SessionManager::CreateManager(session_kind);
-    session_kind_ = session_kind;
-  }
-
-  std::unique_ptr<SessionManager> session_manager_;
-  SessionKind session_kind_;
-  std::unordered_map<size_t /*task index*/, TaskData> read_ahead_file_map_;
-  static RecentDataKeeper recent_data_keeper_;
-  int32_t trace_cookie_{0};
-
-  bool UseSockets() const {
-    return session_kind_ == SessionKind::kOutOfProcessSocket;
-  }
-};
-
-RecentDataKeeper ReadAhead::Impl::recent_data_keeper_{};
-
-ReadAhead::ReadAhead() : ReadAhead(/*use_sockets*/false) {
-}
-
-ReadAhead::ReadAhead(bool use_sockets) : impl_(new Impl(use_sockets)) {
-}
-
-ReadAhead::~ReadAhead() {}
-
-static bool PerformReadAhead(std::shared_ptr<Session> session, size_t path_id, ReadAheadKind kind, size_t length, size_t offset) {
-  return session->ReadAhead(path_id, kind, length, offset);
-}
-
-void ReadAhead::FinishTask(const TaskId& id) {
-  auto it = impl_->read_ahead_file_map_.find(id.id);
-  if (it == impl_->read_ahead_file_map_.end()) {
-    LOG(DEBUG) << "Could not find any TaskData for " << id;
-    return;
-  }
-
-  TaskData& task_data = it->second;
-  atrace_async_end(ATRACE_TAG_ACTIVITY_MANAGER,
-                   "ReadAhead Task Scope (for File Descriptors)",
-                   task_data.trace_cookie);
-
-  auto deleter = [&]() {
-    impl_->read_ahead_file_map_.erase(it);
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
-  (void)scope_guard;
-
-  LOG(VERBOSE) << "ReadAhead (Finish)";
-
-  if (!impl_->session_manager_->DestroySession(task_data.SessionId())) {
-    LOG(WARNING) << "ReadAhead: Failed to destroy Session " << task_data.SessionId();
-  }
-}
-
-void ReadAhead::BeginTaskForSockets(const TaskId& id, int32_t trace_cookie) {
-  LOG(VERBOSE) << "BeginTaskForSockets: " << id;
-
-  // TODO: atrace.
-  android::base::Timer timer{};
-  android::base::Timer open_timer{};
-
-  int trace_file_fd_raw =
-      TEMP_FAILURE_RETRY(open(id.path.c_str(), /*flags*/O_RDONLY));
-
-  android::base::unique_fd trace_file_fd{trace_file_fd_raw};
-
-  if (!trace_file_fd.ok()) {
-    PLOG(ERROR) << "ReadAhead failed to open trace file: " << id.path;
-    return;
-  }
-
-  TaskData task_data;
-  task_data.task_id = id;
-  task_data.trace_cookie = trace_cookie;
-
-  std::shared_ptr<Session> session =
-      impl_->session_manager_->CreateSession(task_data.SessionId(),
-                                             /*description*/id.path,
-                                             trace_file_fd.get());
-  task_data.session = session;
-  CHECK(session != nullptr);
-
-  task_data.trace_cookie = ++trace_cookie;
-
-  // TODO: maybe getprop and a single line by default?
-  session->Dump(LOG_STREAM(INFO), /*multiline*/true);
-
-  impl_->read_ahead_file_map_[id.id] = std::move(task_data);
-  // FinishTask is identical, as it just destroys the session.
-}
-
-void ReadAhead::BeginTask(const TaskId& id) {
-  {
-    struct timeval now;
-    gettimeofday(&now, nullptr);
-
-    uint64_t now_usec = (now.tv_sec * 1000000LL + now.tv_usec);
-    LOG(DEBUG) << "BeginTask: beginning usec: " << now_usec;
-  }
-
-  int32_t trace_cookie = ++impl_->trace_cookie_;
-  atrace_async_begin(ATRACE_TAG_ACTIVITY_MANAGER,
-                     "ReadAhead Task Scope (for File Descriptors)",
-                     trace_cookie);
-
-  if (impl_->UseSockets()) {
-    BeginTaskForSockets(id, trace_cookie);
-    return;
-  }
-
-  LOG(VERBOSE) << "BeginTask: " << id;
-
-  // TODO: atrace.
-  android::base::Timer timer{};
-
-  // TODO: refactor this code with SessionDirect::ProcessFd ?
-  TaskData task_data;
-  task_data.task_id = id;
-  task_data.trace_cookie = trace_cookie;
-
-  ScopedFormatTrace atrace_begin_task(ATRACE_TAG_ACTIVITY_MANAGER,
-                                      "ReadAhead::BeginTask %s",
-                                      id.path.c_str());
-
-  // Include CreateSession above the Protobuf deserialization so that we can include
-  // the 'total_duration' as part of the Session dump (relevant when we use IPC mode only).
-  std::shared_ptr<Session> session =
-      impl_->session_manager_->CreateSession(task_data.SessionId(),
-                                             /*description*/id.path);
-
-  android::base::Timer open_timer{};
-
-  // XX: Should we rename all the 'Create' to 'Make', or rename the 'Make' to 'Create' ?
-  // Unfortunately make_unique, make_shared, etc is the standard C++ terminology.
-  serialize::ArenaPtr<serialize::proto::TraceFile> trace_file_ptr =
-      serialize::ProtobufIO::Open(id.path);
-
-  if (trace_file_ptr == nullptr) {
-    // TODO: distinguish between missing trace (this is OK, most apps wont have one)
-    // and a bad error.
-    LOG(DEBUG) << "ReadAhead could not start, missing trace file? " << id.path;
-    return;
-  }
-
-  task_data.session = session;
-  CHECK(session != nullptr);
-
-  ReadAheadKind kind = static_cast<ReadAheadKind>(GetPrefetchStrategy());
-
-  // TODO: The "Task[Id]" should probably be the one owning the trace file.
-  // When the task is fully complete, the task can be deleted and the
-  // associated arenas can go with them.
-
-  // TODO: we should probably have the file entries all be relative
-  // to the package path?
-
-  // Open every file in the trace index.
-  const serialize::proto::TraceFileIndex& index = trace_file_ptr->index();
-
-  size_t count_entries = 0;
-  {
-    ScopedFormatTrace atrace_register_file_paths(ATRACE_TAG_ACTIVITY_MANAGER,
-                                                 "ReadAhead::RegisterFilePaths %s",
-                                                 id.path.c_str());
-    for (const serialize::proto::TraceFileIndexEntry& index_entry : index.entries()) {
-      LOG(VERBOSE) << "ReadAhead: found file entry: " << index_entry.file_name();
-
-      if (index_entry.id() < 0) {
-        LOG(WARNING) << "ReadAhead: Skip bad TraceFileIndexEntry, negative ID not allowed: "
-                     << index_entry.id();
-        continue;
-      }
-
-      size_t path_id = index_entry.id();
-      const auto& path_file_name = index_entry.file_name();
-
-      if (!session->RegisterFilePath(path_id, path_file_name)) {
-        LOG(WARNING) << "ReadAhead: Failed to register file path: " << path_file_name;
-      } else {
-        ++count_entries;
-      }
-    }
-  }
-  LOG(VERBOSE) << "ReadAhead: Registered " << count_entries << " file paths";
-  std::chrono::milliseconds open_duration_ms = open_timer.duration();
-
-  LOG(DEBUG) << "ReadAhead: Opened file&headers in " << open_duration_ms.count() << "ms";
-
-  size_t length_sum = 0;
-  size_t prefetch_bytes = 0;
-  size_t entry_offset = 0;
-  {
-    ScopedFormatTrace atrace_perform_read_ahead(ATRACE_TAG_ACTIVITY_MANAGER,
-                                                "ReadAhead::PerformReadAhead entries=%zu, path=%s",
-                                                count_entries,
-                                                id.path.c_str());
-
-    // Go through every trace entry and readahead every (file,offset,len) tuple.
-    const serialize::proto::TraceFileList& file_list = trace_file_ptr->list();
-    for (const serialize::proto::TraceFileEntry& file_entry : file_list.entries()) {
-      ++entry_offset;
-
-      if (file_entry.file_length() < 0 || file_entry.file_offset() < 0) {
-        LOG(WARNING) << "ReadAhead entry negative file length or offset, illegal: "
-                     << "index_id=" << file_entry.index_id() << ", skipping";
-        continue;
-      }
-
-      // Attempt to perform readahead. This can generate more warnings dynamically.
-      if (!PerformReadAhead(session, file_entry.index_id(), kind, file_entry.file_length(), file_entry.file_offset())) {
-        // TODO: Do we need below at all? The always-on Dump already prints a % of failed entries.
-        // LOG(WARNING) << "Failed readahead, bad file length/offset in entry @ " << (entry_offset - 1);
-      } else {
-        prefetch_bytes += static_cast<size_t>(file_entry.file_length());
-        if (prefetch_bytes >= kMaxPrefetchBytes) {
-          LOG(WARNING) << "The prefetching size is "
-                       << prefetch_bytes
-                       << " and it exceeds the threshold "
-                       << kMaxPrefetchBytes;
-          break;
-        }
-      }
-
-      length_sum += static_cast<size_t>(file_entry.file_length());
-    }
-  }
-
-  {
-    ScopedFormatTrace atrace_session_dump(ATRACE_TAG_ACTIVITY_MANAGER,
-                                          "ReadAhead Session Dump entries=%zu",
-                                          entry_offset);
-    // TODO: maybe getprop and a single line by default?
-    session->Dump(LOG_STREAM(INFO), /*multiline*/true);
-  }
-
-  atrace_int(ATRACE_TAG_ACTIVITY_MANAGER,
-             "ReadAhead Bytes Length",
-             static_cast<int32_t>(length_sum));
-
-  impl_->read_ahead_file_map_[id.id] = std::move(task_data);
-
-  ReadAhead::Impl::recent_data_keeper_.RecordRecent(id, length_sum);
-}
-
-void ReadAhead::Dump(::android::Printer& printer) {
-  ReadAhead::Impl::recent_data_keeper_.Dump(printer);
-}
-
-std::optional<size_t> ReadAhead::PrefetchSizeInBytes(const std::string& file_path) {
-  serialize::ArenaPtr<serialize::proto::TraceFile> trace_file_ptr =
-      serialize::ProtobufIO::Open(file_path);
-
-  if (trace_file_ptr == nullptr) {
-    LOG(WARNING) << "PrefetchSizeInBytes: bad file at " << file_path;
-    return std::nullopt;
-  }
-
-  size_t length_sum = 0;
-  const serialize::proto::TraceFileList& file_list = trace_file_ptr->list();
-  for (const serialize::proto::TraceFileEntry& file_entry : file_list.entries()) {
-
-    if (file_entry.file_length() < 0 || file_entry.file_offset() < 0) {
-      LOG(WARNING) << "ReadAhead entry negative file length or offset, illegal: "
-                   << "index_id=" << file_entry.index_id() << ", skipping";
-      continue;
-    }
-
-    length_sum += static_cast<size_t>(file_entry.file_length());
-  }
-
-  return length_sum;
-}
-
-}  // namespace prefetcher
-}  // namespace iorap
-
diff --git a/src/prefetcher/read_ahead.h b/src/prefetcher/read_ahead.h
deleted file mode 100644
index afc6ec8..0000000
--- a/src/prefetcher/read_ahead.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef PREFETCHER_READAHEAD_H_
-#define PREFETCHER_READAHEAD_H_
-
-#include <memory>
-#include <optional>
-
-namespace android {
-class Printer;
-}  // namespace android
-
-namespace iorap {
-namespace prefetcher {
-
-struct TaskId;
-struct ReadAheadFileEntry;
-
-// Manage I/O readahead for a task.
-class ReadAhead {
-  struct Impl;
- public:
-  // Process a task *now*. Currently will block until all readaheads have been
-  // issued for all entries in that task.
-  //
-  // Any memory mapped or file descriptors opened as a side effect must be
-  // cleaned up with #FinishTask.
-  void BeginTask(const TaskId& id);
-  // Complete a task, releasing any memory/file descriptors associated with it.
-  void FinishTask(const TaskId& id);
-
-  static void Dump(/*borrow*/::android::Printer& printer);
-
-  // Calculate the sum of file_lengths. Returns nullopt if the file path does not
-  // point to a valid compiled TraceFile.
-  static std::optional<size_t> PrefetchSizeInBytes(const std::string& file_path);
-
-  ReadAhead(bool use_sockets);
-
-  ReadAhead();
-  ~ReadAhead();
- private:
-  void BeginTaskForSockets(const TaskId& id, int32_t trace_cookie);
-  std::unique_ptr<Impl> impl_;
-};
-
-}  // namespace prefetcher
-}  // namespace iorap
-
-#endif
-
diff --git a/src/prefetcher/session.cc b/src/prefetcher/session.cc
deleted file mode 100644
index 8a24b24..0000000
--- a/src/prefetcher/session.cc
+++ /dev/null
@@ -1,724 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "session.h"
-
-#include "prefetcher/prefetcher_daemon.h"
-#include "prefetcher/task_id.h"
-#include "serialize/arena_ptr.h"
-#include "serialize/protobuf_io.h"
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/unique_fd.h>
-#include <fcntl.h>
-#include <functional>
-#include <stdint.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unordered_map>
-
-namespace iorap {
-namespace prefetcher {
-
-// Print per-entry details even if successful. Default-off, too spammy.
-static constexpr bool kLogVerboseReadAhead = false;
-
-std::ostream& operator<<(std::ostream& os, const Session& session) {
-  session.Dump(os, /*multiline*/false);
-  return os;
-}
-
-Session::Session() {
-}
-
-void SessionBase::Dump(std::ostream& os, bool multiline) const {
-  if (!multiline) {
-    os << "Session{";
-    os << "session_id=" << SessionId();
-    os << "}";
-    return;
-  } else {
-    os << "Session (id=" << SessionId() << ")" << std::endl;
-    return;
-  }
-}
-
-SessionBase::SessionBase(size_t session_id, std::string description)
-  : session_id_{session_id}, description_{description} {
-}
-
-std::optional<std::string_view> SessionBase::GetFilePath(size_t path_id) const {
-  auto it = path_map_.find(path_id);
-  if (it != path_map_.end()) {
-    return {it->second};
-  } else {
-    return std::nullopt;
-  }
-}
-
-bool SessionBase::RemoveFilePath(size_t path_id) {
-  auto it = path_map_.find(path_id);
-  if (it != path_map_.end()) {
-    path_map_.erase(it);
-    return true;
-  } else {
-    return false;
-  }
-}
-
-bool SessionBase::InsertFilePath(size_t path_id, std::string file_path) {
-  path_map_.insert({path_id, std::move(file_path)});
-  return true;
-}
-
-bool SessionBase::ProcessFd(int fd) {
-  // Only SessionDirect has an implementation of this.
-  // TODO: Maybe add a CommandChoice::kProcessFd ? instead of kCreateFdSession?
-  LOG(FATAL) << "SessionBase::ProcessFd is not implemented";
-
-  return false;
-}
-
-//
-// Direct
-//
-
-std::ostream& operator<<(std::ostream& os, const SessionDirect::Entry& entry) {
-  os << "Entry{";
-  os << "path_id=" << entry.path_id << ",";
-  os << "kind=" << static_cast<int>(entry.kind) << ",";
-  os << "length=" << entry.length << ",";
-  os << "offset=" << entry.offset << ",";
-  os << "}";
-
-  return os;
-}
-
-// Just in case the failures are slowing down performance, turn them off.
-// static constexpr bool kLogFailures = true;
-static constexpr bool kLogFailures = false;
-
-bool SessionDirect::RegisterFilePath(size_t path_id, std::string_view file_path) {
-  std::string file_path_str{file_path};  // no c_str for string_view.
-
-  auto fd = TEMP_FAILURE_RETRY(open(file_path_str.c_str(), O_RDONLY));
-  if (fd < 0) {
-    if (kLogFailures) {
-      PLOG(ERROR) << "Failed to register file path: " << file_path << ", id=" << path_id
-                  << ", open(2) failed: ";
-    }
-    fd = android::base::unique_fd{};  // mark as 'bad' descriptor.
-  }
-
-  LOG(VERBOSE) << "RegisterFilePath path_id=" << path_id << ", file_path=" << file_path_str;
-
-  if (!InsertFilePath(path_id, std::move(file_path_str))) {
-    return false;
-  }
-
-  path_fd_map_.insert(std::make_pair(path_id, std::move(fd)));
-  DCHECK(entry_list_map_[path_id].empty());
-
-  return true;
-}
-
-
-bool SessionDirect::UnregisterFilePath(size_t path_id) {
-  if (!RemoveFilePath(path_id)) {
-    return false;
-  }
-
-  {  // Scoped FD reference lifetime.
-    auto maybe_fd = GetFdForPath(path_id);
-
-    DCHECK(*maybe_fd != nullptr);
-    const android::base::unique_fd& entry_fd = **maybe_fd;
-
-    auto list = entry_list_map_[path_id];
-
-    for (const EntryMapping& entry_mapping : list) {
-      ReadAheadKind kind = entry_mapping.entry.kind;
-
-      switch (kind) {
-        case ReadAheadKind::kFadvise:
-          // Nothing to do.
-          break;
-        case ReadAheadKind::kMmapLocked:
-        FALLTHROUGH_INTENDED;
-        case ReadAheadKind::kMlock:
-          // Don't do any erases in the unregister file path to avoid paying O(n^2) erase cost.
-          UnmapWithoutErase(entry_mapping);
-          break;
-      }
-    }
-  }
-
-  auto it = entry_list_map_.find(path_id);
-  auto end = entry_list_map_.end();
-  DCHECK(it != end);
-  entry_list_map_.erase(it);
-
-  // Close the FD for this file path.
-  auto fd_it = path_fd_map_.find(path_id);
-  DCHECK(fd_it != path_fd_map_.end());
-  path_fd_map_.erase(fd_it);
-
-  return true;
-}
-
-// Note: return a pointer because optional doesn't hold references directly.
-std::optional<android::base::unique_fd*> SessionDirect::GetFdForPath(size_t path_id) {
-  auto it = path_fd_map_.find(path_id);
-  if (it == path_fd_map_.end()) {
-    return std::nullopt;
-  } else {
-    return &it->second;
-  }
-}
-
-bool SessionDirect::ReadAhead(size_t path_id,
-                              ReadAheadKind kind,
-                              size_t length,
-                              size_t offset) {
-  // Take by-reference so we can mutate list at the end.
-  auto& list = entry_list_map_[path_id];
-
-  Entry entry{path_id, kind, length, offset};
-  EntryMapping entry_mapping{entry, /*address*/nullptr, /*success*/false};
-
-  bool success = true;
-
-  auto maybe_fd = GetFdForPath(path_id);
-  if (!maybe_fd) {
-    LOG(ERROR) << "SessionDirect: Failed to find FD for path_id=" << path_id;
-    return false;
-  }
-
-  DCHECK(*maybe_fd != nullptr);
-  const android::base::unique_fd& entry_fd = **maybe_fd;
-
-  std::optional<std::string_view> file_name_opt = GetFilePath(path_id);
-  DCHECK(file_name_opt.has_value());  // if one map has it, all maps have it.
-  std::string_view file_name = *file_name_opt;
-
-  if (!entry_fd.ok()) {
-    LOG(VERBOSE) << "SessionDirect: No file descriptor for (path_id=" << path_id << ") "
-                 << "path '" << file_name << "', failed to readahead entry.";
-    // Even failures get kept with success=false.
-    list.push_back(entry_mapping);
-    return false;
-  }
-
-  switch (kind) {
-    case ReadAheadKind::kFadvise:
-      if (posix_fadvise(entry_fd, offset, length, POSIX_FADV_WILLNEED) != 0) {
-        PLOG(ERROR) << "SessionDirect: Failed to fadvise entry " << file_name
-                    << ", offset=" << offset << ", length=" << length;
-        success = false;
-      }
-      break;
-    case ReadAheadKind::kMmapLocked:
-    FALLTHROUGH_INTENDED;
-    case ReadAheadKind::kMlock: {
-      const bool need_mlock = kind == ReadAheadKind::kMlock;
-
-      int flags = MAP_SHARED;
-      if (!need_mlock) {
-        // MAP_LOCKED is a best-effort to lock the page. it could still be
-        // paged in later at a fault.
-        flags |= MAP_LOCKED;
-      }
-
-      entry_mapping.address =
-        mmap(/*addr*/nullptr, length, PROT_READ, flags, entry_fd, offset);
-
-      if (entry_mapping.address == nullptr) {
-        PLOG(ERROR) << "SessionDirect: Failed to mmap entry " << file_name
-                    << ", offset=" << offset << ", length=" << length;
-        success = false;
-        break;
-      }
-
-      // Strong guarantee that page will be locked if mlock returns successfully.
-      if (need_mlock && mlock(entry_mapping.address, length) < 0) {
-        PLOG(ERROR) << "SessionDirect: Failed to mlock entry " << file_name
-                    << ", offset=" << offset << ", length=" << length;
-        // We already have a mapping address, so we should add it to the list.
-        // However this didn't succeed 100% because the lock failed, so return false later.
-        success = false;
-      }
-    }
-  }
-
-  // Keep track of success so we know in Dump() what the number of failed entry mappings were.
-  entry_mapping.success = success;
-
-  // Keep track of this so that we can clean it up later in UnreadAhead.
-  list.push_back(entry_mapping);
-
-  if (entry_mapping.success) {
-    if (kLogVerboseReadAhead) {
-      LOG(VERBOSE) << "SessionDirect: ReadAhead for " << entry_mapping.entry;
-    }
-  }  // else one of the errors above already did print.
-
-  return success;
-}
-
-bool SessionDirect::UnreadAhead(size_t path_id,
-                                ReadAheadKind kind,
-                                size_t length,
-                                size_t offset) {
-  Entry entry{path_id, kind, length, offset};
-
-  auto list = entry_list_map_[path_id];
-  if (list.empty()) {
-    return false;
-  }
-
-  std::optional<EntryMapping> entry_mapping;
-  size_t idx = 0;
-
-  for (size_t i = 0; i < list.size(); ++i) {
-    if (entry == list[i].entry) {
-      entry_mapping = list[i];
-      idx = 0;
-      break;
-    }
-  }
-
-  if (!entry_mapping) {
-    return false;
-  }
-
-  switch (kind) {
-    case ReadAheadKind::kFadvise:
-      // Nothing to do.
-      // TODO: maybe fadvise(RANDOM)?
-      return true;
-    case ReadAheadKind::kMmapLocked:
-    FALLTHROUGH_INTENDED;
-    case ReadAheadKind::kMlock:
-      UnmapWithoutErase(*entry_mapping);
-      return true;
-  }
-
-  list.erase(list.begin() + idx);
-
-  // FDs close only with UnregisterFilePath.
-  return true;
-}
-
-void SessionDirect::UnmapWithoutErase(const EntryMapping& entry_mapping) {
-  void* address = entry_mapping.address;
-  size_t length = entry_mapping.entry.length;
-
-  // munmap also unlocks. Do not need explicit munlock.
-  if (munmap(address, length) < 0) {
-    PLOG(WARNING) << "ReadAhead (Finish): Failed to munmap address: "
-                  << address << ", length: " << length;
-  }
-
-}
-
-bool SessionDirect::ProcessFd(int fd) {
-  // TODO: the path is advisory, but it would still be cleaner to pass it separately
-  const char* fd_path = SessionDescription().c_str();
-
-  android::base::Timer open_timer{};
-  android::base::Timer total_timer{};
-
-  serialize::ArenaPtr<serialize::proto::TraceFile> trace_file_ptr =
-      serialize::ProtobufIO::Open(fd, fd_path);
-
-  if (trace_file_ptr == nullptr) {
-    LOG(ERROR) << "SessionDirect::ProcessFd failed, corrupted protobuf format? " << fd_path;
-    return false;
-  }
-
-  // TODO: maybe make it part of a kProcessFd type of command?
-  ReadAheadKind kind = ReadAheadKind::kFadvise;
-
-  // TODO: The "Task[Id]" should probably be the one owning the trace file.
-  // When the task is fully complete, the task can be deleted and the
-  // associated arenas can go with them.
-
-  // TODO: we should probably have the file entries all be relative
-  // to the package path?
-
-  // Open every file in the trace index.
-  const serialize::proto::TraceFileIndex& index = trace_file_ptr->index();
-
-  size_t count_entries = 0;
-  for (const serialize::proto::TraceFileIndexEntry& index_entry : index.entries()) {
-    LOG(VERBOSE) << "ReadAhead: found file entry: " << index_entry.file_name();
-
-    if (index_entry.id() < 0) {
-      LOG(WARNING) << "ReadAhead: Skip bad TraceFileIndexEntry, negative ID not allowed: "
-                   << index_entry.id();
-      continue;
-    }
-
-    size_t path_id = index_entry.id();
-    const auto& path_file_name = index_entry.file_name();
-
-    if (!this->RegisterFilePath(path_id, path_file_name)) {
-      LOG(WARNING) << "ReadAhead: Failed to register file path: " << path_file_name;
-      ++count_entries;
-    }
-  }
-  LOG(VERBOSE) << "ReadAhead: Registered " << count_entries << " file paths";
-  std::chrono::milliseconds open_duration_ms = open_timer.duration();
-
-  LOG(DEBUG) << "ProcessFd: open+parsed headers in " << open_duration_ms.count() << "ms";
-
-  // Go through every trace entry and readahead every (file,offset,len) tuple.
-  size_t entry_offset = 0;
-  const serialize::proto::TraceFileList& file_list = trace_file_ptr->list();
-  for (const serialize::proto::TraceFileEntry& file_entry : file_list.entries()) {
-    ++entry_offset;
-
-    if (file_entry.file_length() < 0 || file_entry.file_offset() < 0) {
-      LOG(WARNING) << "ProcessFd entry negative file length or offset, illegal: "
-                   << "index_id=" << file_entry.index_id() << ", skipping";
-      continue;
-    }
-
-    // Attempt to perform readahead. This can generate more warnings dynamically.
-    if (!this->ReadAhead(file_entry.index_id(),
-                         kind,
-                         file_entry.file_length(),
-                         file_entry.file_offset())) {
-      if (kLogFailures) {
-        LOG(WARNING) << "Failed readahead, bad file length/offset in entry @ "
-                     << (entry_offset - 1);
-      }
-    }
-  }
-
-  std::chrono::milliseconds total_duration_ms = total_timer.duration();
-  LOG(DEBUG) << "ProcessFd: total duration " << total_duration_ms.count() << "ms";
-
-  {
-    struct timeval now;
-    gettimeofday(&now, nullptr);
-
-    uint64_t now_usec = (now.tv_sec * 1000000LL + now.tv_usec);
-    LOG(DEBUG) << "ProcessFd: finishing usec: " << now_usec;
-  }
-
-  return true;
-}
-
-
-static bool IsDumpEveryEntry() {
-  // Set to 'true' to dump every single entry for debugging (multiline).
-  // Otherwise it only prints per-file-path summaries.
-  return ::android::base::GetBoolProperty("iorapd.readahead.dump_all", /*default*/false);
-}
-
-static bool IsDumpEveryPath() {
-  // Dump per-file-path (entry) stats. Defaults to on if the above property is on.
-  return ::android::base::GetBoolProperty("iorapd.readahead.dump_paths", /*default*/false);
-}
-
-void SessionDirect::Dump(std::ostream& os, bool multiline) const {
-  {
-    struct timeval now;
-    gettimeofday(&now, nullptr);
-
-    uint64_t now_usec = (now.tv_sec * 1000000LL + now.tv_usec);
-    LOG(DEBUG) << "SessionDirect::Dump: beginning usec: " << now_usec;
-  }
-
-  size_t path_count = entry_list_map_.size();
-
-  size_t read_ahead_entries = 0;
-  size_t read_ahead_bytes = 0;
-
-  size_t overall_entry_count = 0;
-  size_t overall_byte_count = 0;
-  for (auto it = entry_list_map_.begin(); it != entry_list_map_.end(); ++it) {
-    const auto& entry_mapping_list = it->second;
-
-    for (size_t j = 0; j < entry_mapping_list.size(); ++j) {
-      const EntryMapping& entry_mapping = entry_mapping_list[j];
-      const Entry& entry = entry_mapping.entry;
-
-      ++overall_entry_count;
-      overall_byte_count += entry.length;
-
-      if (entry_mapping.success) {
-        ++read_ahead_entries;
-        read_ahead_bytes += entry.length;
-      }
-    }
-  }
-
-  double overall_success_entry_rate =
-      read_ahead_entries * 100.0 / overall_entry_count;
-  double overall_success_byte_rate =
-      read_ahead_bytes * 100.0 / overall_byte_count;
-
-  size_t fd_count = path_fd_map_.size();
-  size_t good_fd_count = 0;
-  for (auto it = path_fd_map_.begin(); it != path_fd_map_.end(); ++it) {
-    if (it->second.ok()) {
-      ++good_fd_count;
-    }
-  }
-  double good_fd_rate = good_fd_count * 100.0 / fd_count;
-  // double bad_fd_rate = (fd_count - good_fd_count) * 1.0 / fd_count;
-
-  if (!multiline) {
-    os << "SessionDirect{";
-    os << "session_id=" << SessionId() << ",";
-
-    os << "file_paths=" << path_count << " (good: " << good_fd_rate << "),";
-    os << "read_ahead_entries=" << read_ahead_entries;
-    os << "(" << overall_success_entry_rate << "%),";
-    os << "read_ahead_bytes=" << read_ahead_bytes << "";
-    os << "(" << overall_success_byte_rate << "%),";
-    os << "timer=" << timer_.duration().count() << ",";
-
-    os << "}";
-    return;
-  } else {
-    // Always try to pay attention to these stats below.
-    // They can be signs of potential performance problems.
-    os << "Session Direct (id=" << SessionId() << ")" << std::endl;
-
-    os << "  Summary: " << std::endl;
-    os << "    Description = " << SessionDescription() << std::endl;
-    os << "    Duration = " << timer_.duration().count() << "ms" << std::endl;
-    os << "    Total File Paths=" << path_count << " (good: " << good_fd_rate << "%)" << std::endl;
-    os << "    Total Entries=" << overall_entry_count;
-    os << " (good: " << overall_success_entry_rate << "%)" << std::endl;
-    os << "    Total Bytes=" << overall_byte_count << "";
-    os << " (good: " << overall_success_byte_rate << "%)" << std::endl;
-    os << std::endl;
-
-    // Probably too spammy, but they could narrow down the issue for a problem in above stats.
-    if (!IsDumpEveryPath() && !IsDumpEveryEntry()) {
-      return;
-    }
-
-    for (auto it = entry_list_map_.begin(); it != entry_list_map_.end(); ++it) {
-      size_t path_id = it->first;
-      const auto& entry_mapping_list = it->second;
-
-      std::optional<std::string_view> file_path = GetFilePath(path_id);
-      os << "  File Path (id=" << path_id << "): ";
-      if (file_path.has_value()) {
-        os << "'" << *file_path << "'";
-      } else {
-        os << "(nullopt)";
-      }
-
-      auto fd_it = path_fd_map_.find(path_id);
-      os << ", FD=";
-      if (fd_it != path_fd_map_.end()) {
-        const android::base::unique_fd& fd = fd_it->second;
-        os << fd.get();  // -1 for failed fd.
-      } else {
-        os << "(none)";
-      }
-      os << std::endl;
-
-      size_t total_entries = entry_mapping_list.size();
-      size_t total_bytes = 0;
-
-      size_t local_read_ahead_entries = 0;
-      size_t local_read_ahead_bytes = 0;
-      for (size_t j = 0; j < entry_mapping_list.size(); ++j) {
-        const EntryMapping& entry_mapping = entry_mapping_list[j];
-        const Entry& entry = entry_mapping.entry;
-
-        total_bytes += entry.length;
-
-        // Sidenote: Bad FDs will have 100% failed mappings.
-        // Good FDs may sometimes have failed mappings.
-        if (entry_mapping.success) {
-          ++local_read_ahead_entries;
-          local_read_ahead_bytes += entry.length;
-        }
-
-        if (IsDumpEveryEntry()) {
-          os << "    Entry " << j << " details:" << std::endl;
-          os << "      " << entry << std::endl;
-          os << "      Mapping " << (entry_mapping.success ? "Succeeded" :  "Failed")
-             << ", Address " << entry_mapping.address << std::endl;
-        }
-      }
-
-      double entry_success_rate = local_read_ahead_entries * 100.0 / total_entries;
-      double bytes_success_rate = local_read_ahead_bytes * 100.0 / total_bytes;
-
-      double entry_failure_rate = (total_entries - local_read_ahead_entries) * 100.0 / total_entries;
-      double bytes_failure_rate = (total_bytes - local_read_ahead_bytes) * 100.0 / total_bytes;
-
-      os << "    Successful: Entries=" << local_read_ahead_entries
-         << " (" << entry_success_rate << "%)"
-         << ", Bytes=" << local_read_ahead_bytes
-         << " (" << bytes_success_rate << "%)"
-         << std::endl;
-      os << "    Failed: Entries=" << (total_entries - local_read_ahead_entries)
-         << " (" << entry_failure_rate << "%)"
-         << ", Bytes=" << (total_bytes - local_read_ahead_bytes)
-         << " (" << bytes_failure_rate << "%)"
-         << std::endl;
-      os << "    Total: Entries=" << total_entries
-         << ", Bytes=" << total_bytes
-         << std::endl;
-    }
-
-    return;
-  }
-}
-
-SessionDirect::~SessionDirect() {
-  for (auto it = entry_list_map_.begin(); it != entry_list_map_.end();) {
-    size_t path_id = it->first;
-
-    ++it; // the iterator is removed in the following Unregister method.
-    UnregisterFilePath(path_id);
-  }
-}
-
-//
-// Indirect
-//
-
-SessionIndirect::SessionIndirect(size_t session_id,
-                                 std::string description,
-                                 std::shared_ptr<PrefetcherDaemon> daemon,
-                                 bool send_command)
-    : SessionBase{session_id, description},
-      daemon_{daemon} {
-  // Don't do anything in e.g. subclasses.
-  if (!send_command) {
-    return;
-  }
-
-  Command cmd{};
-  cmd.choice = CommandChoice::kCreateSession;
-  cmd.session_id = session_id;
-  cmd.file_path = description;
-
-  LOG(VERBOSE) << "SessionIndirect: " << cmd;
-
-  if (!daemon_->SendCommand(cmd)) {
-    LOG(FATAL) << "SessionIndirect: Failure to create session " << session_id
-               << ", description: " << description;
-  }
-}
-
-SessionIndirect::~SessionIndirect() {
-  Command cmd{};
-  cmd.choice = CommandChoice::kDestroySession;
-  cmd.session_id = SessionId();
-
-  if (!daemon_->SendCommand(cmd)) {
-    LOG(WARNING) << "SessionIndirect: Failure to destroy session " << SessionId()
-                 << ", description: " << SessionDescription();
-  }
-}
-
-void SessionIndirect::Dump(std::ostream& os, bool multiline) const {
-  // SessionBase::Dump(os, multiline);
-  // TODO: does having the local dump do anything for us?
-
-  Command cmd{};
-  cmd.choice = CommandChoice::kDumpSession;
-  cmd.session_id = SessionId();
-
-  daemon_->SendCommand(cmd);
-}
-
-bool SessionIndirect::RegisterFilePath(size_t path_id, std::string_view file_path) {
-  Command cmd{};
-  cmd.choice = CommandChoice::kRegisterFilePath;
-  cmd.session_id = SessionId();
-  cmd.id = path_id;
-  cmd.file_path = file_path;
-
-  return daemon_->SendCommand(cmd);
-}
-
-bool SessionIndirect::UnregisterFilePath(size_t path_id) {
-  Command cmd{};
-  cmd.choice = CommandChoice::kUnregisterFilePath;
-  cmd.session_id = SessionId();
-  cmd.id = path_id;
-
-  return daemon_->SendCommand(cmd);
-}
-bool SessionIndirect::ReadAhead(size_t path_id,
-                                ReadAheadKind kind,
-                                size_t length,
-                                size_t offset) {
-  Command cmd{};
-  cmd.choice = CommandChoice::kReadAhead;
-  cmd.session_id = SessionId();
-  cmd.id = path_id;
-  cmd.read_ahead_kind = kind;
-  cmd.length = length;
-  cmd.offset = offset;
-
-  return daemon_->SendCommand(cmd);
-}
-
-bool SessionIndirect::UnreadAhead(size_t path_id,
-                                  ReadAheadKind kind,
-                                  size_t length,
-                                  size_t offset) {
-  LOG(WARNING) << "UnreadAhead: command not implemented yet";
-  return true;
-}
-
-//
-// IndirectSocket
-//
-
-SessionIndirectSocket::SessionIndirectSocket(size_t session_id,
-                                             int fd,
-                                             std::string description,
-                                             std::shared_ptr<PrefetcherDaemon> daemon)
-    : SessionIndirect{session_id, description, daemon, /*send_command*/false} {
-  // TODO: all of the WriteCommand etc in the daemon.
-  Command cmd{};
-  cmd.choice = CommandChoice::kCreateFdSession;
-  cmd.fd = fd;
-  cmd.session_id = session_id;
-  cmd.file_path = description;
-
-  LOG(VERBOSE) << "SessionIndirectSocket: " << cmd;
-
-  if (!daemon_->SendCommand(cmd)) {
-    LOG(FATAL) << "SessionIndirectSocket: Failure to create session " << session_id
-               << ", description: " << description;
-  }
-
-  // This goes into the SessionDirect ctor + SessionDirect::ProcessFd
-  // as implemented in PrefetcherDaemon::ReceiveCommand
-}
-
-SessionIndirectSocket::~SessionIndirectSocket() {
-}
-
-}  // namespace prefetcher
-}  // namespace iorap
diff --git a/src/prefetcher/session.h b/src/prefetcher/session.h
deleted file mode 100644
index a4a9e6b..0000000
--- a/src/prefetcher/session.h
+++ /dev/null
@@ -1,236 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef PREFETCHER_SESSION_H_
-#define PREFETCHER_SESSION_H_
-
-#include <android-base/chrono_utils.h>
-#include <android-base/unique_fd.h>
-
-#include <optional>
-#include <memory>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-#include <vector>
-
-namespace iorap {
-namespace prefetcher {
-
-#ifndef READ_AHEAD_KIND
-#define READ_AHEAD_KIND 1
-enum class ReadAheadKind : uint32_t {
-  kFadvise = 0,
-  kMmapLocked = 1,
-  kMlock = 2,
-};
-#endif
-
-class Session {
- public:
-  virtual bool RegisterFilePath(size_t path_id, std::string_view file_path) = 0;
-  virtual bool UnregisterFilePath(size_t path_id) = 0;
-
-  // Immediately perform a readahead now.
-  // Fadvise: the readahead will have been queued by the kernel.
-  // MmapLocked/Mlock: the memory is pinned by the requested process.
-  virtual bool ReadAhead(size_t path_id, ReadAheadKind kind, size_t length, size_t offset) = 0;
-
-  // Cancels a readahead previously done.
-  // The length/offset should match the call of ReadAhead.
-  virtual bool UnreadAhead(size_t path_id, ReadAheadKind kind, size_t length, size_t offset) = 0;
-
-  // Multi-line detailed dump, e.g. for dumpsys.
-  // Single-line summary dump, e.g. for logcat.
-  virtual void Dump(std::ostream& os, bool multiline) const = 0;
-
-  // Process the FD for kCreateFdSession.
-  // Assumes there's a compiled_trace.pb at the fd, calling this function
-  // will immediately process it and execute any read-aheads.
-  //
-  // FD is borrowed only for the duration of the function call.
-  virtual bool ProcessFd(int fd) = 0;
-
-  // Get the session ID associated with this session.
-  // Session IDs are distinct, they are not used for new sessions.
-  virtual size_t SessionId() const = 0;
-
-  // Get this session's description.
-  // Only useful for logging/dumping.
-  virtual const std::string& SessionDescription() const = 0;
-
-  // Implicitly unregister any remaining file paths.
-  // All read-aheads are also cancelled.
-  virtual ~Session() {}
-
- protected:
-  Session();
-};
-
-// Single-line summary dump of Session.
-std::ostream& operator<<(std::ostream&os, const Session& session);
-
-class SessionBase : public Session {
- public:
-  virtual void Dump(std::ostream& os, bool multiline) const override;
-  virtual ~SessionBase() {}
-
-  virtual size_t SessionId() const override {
-    return session_id_;
-  }
-
-  virtual const std::string& SessionDescription() const override {
-    return description_;
-  }
-
-  virtual bool ProcessFd(int fd) override;
-
- protected:
-  SessionBase(size_t session_id, std::string description);
-  std::optional<std::string_view> GetFilePath(size_t path_id) const;
-  bool RemoveFilePath(size_t path_id);
-  bool InsertFilePath(size_t path_id, std::string file_path);
-
-  android::base::Timer timer_{};
- private:
-  // Note: Store filename for easier debugging and for dumping.
-  std::unordered_map</*path_id*/size_t, std::string> path_map_;
-  size_t session_id_;
-  std::string description_;
-};
-
-// In-process session.
-class SessionDirect : public SessionBase {
- public:
-  virtual bool RegisterFilePath(size_t path_id, std::string_view file_path) override;
-
-  virtual bool UnregisterFilePath(size_t path_id) override;
-  virtual bool ReadAhead(size_t path_id,
-                         ReadAheadKind kind,
-                         size_t length,
-                         size_t offset);
-
-  virtual bool UnreadAhead(size_t path_id,
-                           ReadAheadKind kind,
-                           size_t length,
-                           size_t offset) override;
-
-  virtual bool ProcessFd(int fd) override;
-
-  virtual void Dump(std::ostream& os, bool multiline) const override;
-
-  virtual ~SessionDirect();
-
-  SessionDirect(size_t session_id, std::string description)
-    : SessionBase{session_id, std::move(description)} {
-  }
- protected:
-  struct Entry {
-    size_t path_id;
-    ReadAheadKind kind;
-    size_t length;
-    size_t offset;
-
-    constexpr bool operator==(const Entry& other) const {
-      return path_id == other.path_id &&
-        kind == other.kind &&
-        length == other.length &&
-        offset == other.offset;
-    }
-    constexpr bool operator!=(const Entry& other) const {
-      return !(*this == other);
-    }
-
-    friend std::ostream& operator<<(std::ostream& os, const Entry& entry);
-  };
-
-  struct EntryMapping {
-    Entry entry;
-    void* address;
-    bool success;
-  };
-
-  // bool EntryReadAhead(const Entry& entry) const;
-  // bool EntryUnReadAhead(const Entry& entry) const;
-
-  void UnmapWithoutErase(const EntryMapping& entry_mapping);
-  std::optional<android::base::unique_fd*> GetFdForPath(size_t path_id);
-
- private:
-  std::unordered_map</*path_id*/size_t, std::vector<EntryMapping>> entry_list_map_;
-  std::unordered_map</*path_id*/size_t, android::base::unique_fd> path_fd_map_;
-
- public:
-  friend std::ostream& operator<<(std::ostream& os, const SessionDirect::Entry& entry);
-};
-
-std::ostream& operator<<(std::ostream& os, const SessionDirect::Entry& entry);
-
-class PrefetcherDaemon;
-
-// Out-of-process session. Requires prefetcher daemon.
-class SessionIndirect : public SessionBase {
- public:
-  virtual bool RegisterFilePath(size_t path_id, std::string_view file_path) override;
-
-  virtual bool UnregisterFilePath(size_t path_id) override;
-  virtual bool ReadAhead(size_t path_id,
-                         ReadAheadKind kind,
-                         size_t length,
-                         size_t offset) override;
-
-  virtual bool UnreadAhead(size_t path_id,
-                           ReadAheadKind kind,
-                           size_t length,
-                           size_t offset) override;
-
-  virtual void Dump(std::ostream& os, bool multiline) const override;
-
-  // Creates a new session indirectly.
-  // Writes to daemon the new session command.
-  SessionIndirect(size_t session_id,
-                  std::string description,
-                  std::shared_ptr<PrefetcherDaemon> daemon,
-                  bool send_command = true);
-
-  // Destroys the current session.
-  // Writes to daemon that the session is to be destroyed.
-  virtual ~SessionIndirect();
-
- protected:
-  std::shared_ptr<PrefetcherDaemon> daemon_;
-};
-
-// Out-of-process session. Requires prefetcher daemon.
-class SessionIndirectSocket : public SessionIndirect {
- public:
-  // Creates a new session indirectly.
-  // Writes to daemon the new session command.
-  SessionIndirectSocket(size_t session_id,
-                        int fd,
-                        std::string description,
-                        std::shared_ptr<PrefetcherDaemon> daemon);
-  // Destroys the current session.
-  // Writes to daemon that the session is to be destroyed.
-  virtual ~SessionIndirectSocket();
-
- private:
-};
-
-
-}  // namespace prefetcher
-}  // namespace iorap
-
-#endif
-
diff --git a/src/prefetcher/session_manager.cc b/src/prefetcher/session_manager.cc
deleted file mode 100644
index d6fab1f..0000000
--- a/src/prefetcher/session_manager.cc
+++ /dev/null
@@ -1,281 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "session_manager.h"
-
-#include "prefetcher/prefetcher_daemon.h"
-#include "prefetcher/session.h"
-#include "prefetcher/task_id.h"
-#include "serialize/arena_ptr.h"
-#include "serialize/protobuf_io.h"
-
-#include <android-base/logging.h>
-#include <android-base/chrono_utils.h>
-#include <android-base/unique_fd.h>
-#include <fcntl.h>
-#include <functional>
-#include <stdint.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unordered_map>
-
-namespace iorap {
-namespace prefetcher {
-
-std::ostream& operator<<(std::ostream& os, const SessionManager& manager) {
-  manager.Dump(os, /*multiline*/false);
-  return os;
-}
-
-SessionManager::SessionManager() {
-}
-
-class SessionManagerBase  : public SessionManager {
- public:
-  virtual void Dump(std::ostream& os, bool multiline) const {
-    if (!multiline) {
-      os << "SessionManager{";
-
-      os << "sessions=[";
-      for (auto it = sessions_map_.begin();
-           it != sessions_map_.end();
-           ++it) {
-        os << "(" << it->second.description << ") ";
-        it->second.session->Dump(os, /*multiline*/false);
-      }
-      os << "]";
-      return;
-    }
-
-    os << "SessionManager (session count = " << sessions_map_.size() << "):" << std::endl;
-    os << std::endl;
-
-    for (auto it = sessions_map_.begin();
-         it != sessions_map_.end();
-         ++it) {
-      os << "Description: " << it->second.description << std::endl;
-      it->second.session->Dump(os, /*multiline*/true);
-    }
-
-    // TODO: indentations? Use this pseudo line break for the time being.
-    os << "--------------------------------" << std::endl;
-  }
-
-  virtual ~SessionManagerBase() {}
-
-  virtual std::shared_ptr<Session> FindSession(size_t session_id) const override {
-    auto it = sessions_map_.find(session_id);
-    if (it != sessions_map_.end()) {
-      DCHECK_EQ(session_id, it->second.SessionId());
-      return it->second.session;
-    } else {
-      return nullptr;
-    }
-  }
-
-  virtual bool DestroySession(size_t session_id) override {
-    auto it = sessions_map_.find(session_id);
-    if (it != sessions_map_.end()) {
-      sessions_map_.erase(it);
-      return true;
-    } else {
-      return false;
-    }
-  }
-
- protected:
-  void InsertNewSession(std::shared_ptr<Session> session, std::string description) {
-    DCHECK(!FindSession(session->SessionId())) << "session cannot already exist";
-
-    size_t session_id = session->SessionId();
-
-    SessionData data;
-    data.session = std::move(session);
-    data.description = std::move(description);
-
-    sessions_map_.insert({session_id, std::move(data)});
-  }
-
- private:
-  struct SessionData {
-    std::shared_ptr<Session> session;
-    std::string description;
-
-    size_t SessionId() const {
-      return session->SessionId();
-    }
-  };
-
-  std::unordered_map</*session_id*/size_t, SessionData> sessions_map_;
-};
-
-class SessionManagerDirect : public SessionManagerBase {
- public:
-  virtual std::shared_ptr<Session> CreateSession(size_t session_id,
-                                                 std::string description) override {
-    LOG(VERBOSE) << "CreateSessionDirect id=" << session_id << ", description=" << description;
-
-    std::shared_ptr<Session> session =
-      std::static_pointer_cast<Session>(std::make_shared<SessionDirect>(session_id,
-                                                                        description));
-    DCHECK(FindSession(session_id) == nullptr);
-    InsertNewSession(session, std::move(description));
-    return session;
-  }
-
-  SessionManagerDirect() {
-    // Intentionally left empty.
-  }
-
- private:
-};
-
-
-class SessionManagerIndirect : public SessionManagerBase {
- public:
-  virtual std::shared_ptr<Session> CreateSession(size_t session_id,
-                                                 std::string description) override {
-    LOG(VERBOSE) << "CreateSessionIndirect id=" << session_id << ", description=" << description;
-
-    std::shared_ptr<Session> session =
-        std::static_pointer_cast<Session>(std::make_shared<SessionIndirect>(session_id,
-                                                                            description,
-                                                                            daemon_));
-    InsertNewSession(session, description);
-    return session;
-  }
-
-  SessionManagerIndirect() : daemon_{std::make_shared<PrefetcherDaemon>()} {
-    //StartViaFork etc.
-    // TODO: also expose a 'MainLoop(...) -> daemon::Main(..)' somehow in the base interface.
-    auto params = daemon_->StartPipesViaFork();
-    if (!params) {
-      LOG(FATAL) << "Failed to fork+exec iorap.prefetcherd";
-    }
-  }
-
-  virtual ~SessionManagerIndirect() {
-    Command cmd{};
-    cmd.choice = CommandChoice::kExit;
-
-    if (!daemon_->SendCommand(cmd)) {
-      LOG(FATAL) << "Failed to nicely exit iorap.prefetcherd";
-    }
-  }
-
-  virtual void Dump(std::ostream& os, bool multiline) const override {
-    Command cmd{};
-    cmd.choice = CommandChoice::kDumpEverything;
-
-    if (!daemon_->SendCommand(cmd)) {
-      LOG(ERROR) << "Failed to transmit kDumpEverything to iorap.prefetcherd";
-    }
-  }
-
-
- private:
-  // No lifetime cycle: PrefetcherDaemon only has a SessionManagerDirect in it.
-  std::shared_ptr<PrefetcherDaemon> daemon_;
-};
-
-class SessionManagerIndirectSocket : public SessionManagerBase {
- public:
-  virtual std::shared_ptr<Session> CreateSession(size_t session_id,
-                                                 std::string description) override {
-    DCHECK(false) << "not supposed to create a regular session for Socket";
-
-    LOG(VERBOSE) << "CreateSessionIndirect id=" << session_id << ", description=" << description;
-
-    std::shared_ptr<Session> session =
-        std::static_pointer_cast<Session>(std::make_shared<SessionIndirect>(session_id,
-                                                                            description,
-                                                                            daemon_));
-    InsertNewSession(session, description);
-    return session;
-  }
-
-  virtual std::shared_ptr<Session> CreateSession(size_t session_id,
-                                                 std::string description,
-                                                 std::optional<int> fd) override {
-    CHECK(fd.has_value());
-    LOG(VERBOSE) << "CreateSessionIndirectSocket id=" << session_id
-                 << ", description=" << description
-                 << ", fd=" << *fd;
-
-    std::shared_ptr<Session> session =
-        std::static_pointer_cast<Session>(std::make_shared<SessionIndirectSocket>(session_id,
-                                                                                  *fd,
-                                                                                  description,
-                                                                                  daemon_));
-    InsertNewSession(session, description);
-    return session;
-  }
-
-  SessionManagerIndirectSocket() : daemon_{std::make_shared<PrefetcherDaemon>()} {
-    auto params = daemon_->StartSocketViaFork();
-    if (!params) {
-      LOG(FATAL) << "Failed to fork+exec iorap.prefetcherd";
-    }
-  }
-
-  virtual ~SessionManagerIndirectSocket() {
-    Command cmd{};
-    cmd.choice = CommandChoice::kExit;
-
-    if (!daemon_->SendCommand(cmd)) {
-      LOG(FATAL) << "Failed to nicely exit iorap.prefetcherd";
-    }
-  }
-
-  virtual void Dump(std::ostream& os, bool multiline) const override {
-    Command cmd{};
-    cmd.choice = CommandChoice::kDumpEverything;
-
-    if (!daemon_->SendCommand(cmd)) {
-      LOG(ERROR) << "Failed to transmit kDumpEverything to iorap.prefetcherd";
-    }
-  }
-
-
- private:
-  // No lifetime cycle: PrefetcherDaemon only has a SessionManagerDirect in it.
-  std::shared_ptr<PrefetcherDaemon> daemon_;
-};
-
-std::unique_ptr<SessionManager> SessionManager::CreateManager(SessionKind kind) {
-  LOG(VERBOSE) << "SessionManager::CreateManager kind=" << kind;
-
-  switch (kind) {
-    case SessionKind::kInProcessDirect: {
-      SessionManager* ptr = new SessionManagerDirect();
-      return std::unique_ptr<SessionManager>{ptr};
-    }
-    case SessionKind::kOutOfProcessIpc: {
-      SessionManager* ptr = new SessionManagerIndirect();
-      return std::unique_ptr<SessionManager>{ptr};
-    }
-    case SessionKind::kOutOfProcessSocket: {
-      SessionManager* ptr = new SessionManagerIndirectSocket();
-      return std::unique_ptr<SessionManager>{ptr};
-    }
-    default: {
-      LOG(FATAL) << "Invalid session kind: " << static_cast<int>(kind);
-      break;
-    }
-  }
-}
-
-}  // namespace prefetcher
-}  // namespace iorap
diff --git a/src/prefetcher/session_manager.h b/src/prefetcher/session_manager.h
deleted file mode 100644
index 45120d5..0000000
--- a/src/prefetcher/session_manager.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef PREFETCHER_SESSION_MANAGER_H_
-#define PREFETCHER_SESSION_MANAGER_H_
-
-#include <optional>
-#include <ostream>
-#include <memory>
-
-namespace iorap {
-namespace prefetcher {
-
-class Session;
-
-enum class SessionKind : uint32_t {
-  kInProcessDirect,
-  kOutOfProcessIpc,
-  kOutOfProcessSocket,
-};
-
-inline std::ostream& operator<<(std::ostream& os, SessionKind kind) {
-  if (kind == SessionKind::kInProcessDirect) {
-    os << "kInProcessDirect";
-  } else if (kind == SessionKind::kOutOfProcessIpc) {
-    os << "kOutOfProcessIpc";
-  } else if (kind == SessionKind::kOutOfProcessSocket) {
-    os << "kOutOfProcessSocket";
-  } else {
-    os << "(invalid)";
-  }
-  return os;
-}
-
-class SessionManager {
- public:
-  static std::unique_ptr<SessionManager> CreateManager(SessionKind kind);
-
-  // Create a new session. The description is used by Dump.
-  // Manager maintains a strong ref to this session, so DestroySession must also
-  // be called prior to all refs dropping to 0.
-  virtual std::shared_ptr<Session> CreateSession(size_t session_id,
-                                                 std::string description) = 0;
-
-  // Create a new session. The description is used by Dump.
-  // Manager maintains a strong ref to this session, so DestroySession must also
-  // be called prior to all refs dropping to 0.
-  virtual std::shared_ptr<Session> CreateSession(size_t session_id,
-                                                 std::string description,
-                                                 std::optional<int> fd) {
-    return CreateSession(session_id, description);
-  }
-
-  // Look up an existing session that was already created.
-  // Returns null if there is no such session.
-  virtual std::shared_ptr<Session> FindSession(size_t session_id) const = 0;
-
-  // Drop all manager references to an existing session.
-  // Returns false if the session does not exist already.
-  virtual bool DestroySession(size_t session_id) = 0;
-
-  // Multi-line detailed dump, e.g. for dumpsys.
-  // Single-line summary dump, e.g. for logcat.
-  virtual void Dump(std::ostream& os, bool multiline) const = 0;
-
-  // Note: session lifetime is tied to manager. The manager has strong pointers to sessions.
-  virtual ~SessionManager() {}
-
- protected:
-  SessionManager();
-};
-
-// Single-line summary dump of Session.
-std::ostream& operator<<(std::ostream&os, const SessionManager& session);
-
-}  // namespace prefetcher
-}  // namespace iorap
-
-#endif
-
diff --git a/src/prefetcher/task_id.h b/src/prefetcher/task_id.h
deleted file mode 100644
index dc26954..0000000
--- a/src/prefetcher/task_id.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef PREFETCHER_TASK_ID_H_
-#define PREFETCHER_TASK_ID_H_
-
-#include <ostream>
-#include <string>
-
-namespace iorap {
-namespace prefetcher {
-
-struct TaskId {
-  size_t id;  // Unique monotonically increasing ID.
-  std::string path;  // File path to the trace file.
-
-  friend std::ostream& operator<<(std::ostream& os, const TaskId& task_id) {
-    os << "TaskId { id: " << task_id.id << ", path: " << task_id.path << "}";
-    return os;
-  }
-
-};
-
-}  // namespace prefetcher
-}  // namespace iorap
-
-#endif
-
diff --git a/src/serialize/TraceFile.proto b/src/serialize/TraceFile.proto
deleted file mode 100644
index fc72d0d..0000000
--- a/src/serialize/TraceFile.proto
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-syntax = "proto2";  // use required fields, which aren't in proto3.
-
-package iorap.serialize.proto;  // C++ namespace iorap::serialize::proto
-option java_package = "com.google.android.iorap";
-option optimize_for = LITE_RUNTIME;
-
-// TODO: should these fields be 'packed' for "smaller encoding" ?
-
-message TraceFile {
-  required TraceFileIndex index = 1;
-  required TraceFileList list = 2;
-}
-
-message TraceFileIndex {
-  repeated TraceFileIndexEntry entries = 1;
-}
-
-message TraceFileIndexEntry {
-  required int64 id = 1;
-  required string file_name = 2;
-}
-
-message TraceFileList {
-  repeated TraceFileEntry entries = 1;
-}
-
-message TraceFileEntry {
-  required int64 index_id = 1;
-  required int64 file_offset = 2;
-  required int64 file_length = 3;
-}
-
-// XX: use nested messages?
\ No newline at end of file
diff --git a/src/serialize/arena_ptr.h b/src/serialize/arena_ptr.h
deleted file mode 100644
index d8bea26..0000000
--- a/src/serialize/arena_ptr.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SERIALIZE_ARENA_PTR_H_
-#define SERIALIZE_ARENA_PTR_H_
-
-#include <google/protobuf/arena.h>
-#include <memory>
-
-namespace iorap {
-namespace serialize {
-
-/**
- * @file
- *
- * Helpers for protobuf arena allocators. We use smart pointers
- * with an arena embedded inside of them to avoid caring about the
- * arena in other parts of libiorap.
- */
-
-// Arena-managed objects must not be deleted manually.
-// When the Arena goes out of scope, it cleans everything up itself.
-template <typename T>
-void DoNotDelete(T*) {}
-
-template <typename T, typename Base = std::unique_ptr<T, decltype(&DoNotDelete<T>)>>
-struct ArenaPtr : public Base {
-  template <typename... Args>
-  static ArenaPtr<T> Make(Args&& ... args) {
-    ArenaPtr<T> arena_ptr(nullptr);
-    arena_ptr.reset(google::protobuf::Arena::Create<T>(arena_ptr.arena_.get(),
-                                                       std::forward<Args>(args)...));
-    return arena_ptr;
-  }
-
-  ArenaPtr(std::nullptr_t) : Base(nullptr, &DoNotDelete<T>) {}  // NOLINT explicit.
-
- private:
-  // Use a unique_ptr because Arena doesn't support move semantics.
-  std::unique_ptr<google::protobuf::Arena> arena_{new google::protobuf::Arena{}};
-};
-
-template <typename T, typename Base = std::shared_ptr<T>>
-struct ArenaSharedPtr : public Base {
-  template <typename... Args>
-  static ArenaSharedPtr<T> Make(Args&& ... args) {
-    ArenaSharedPtr<T> arena_ptr(nullptr, &DoNotDelete<T>);
-    arena_ptr.reset(google::protobuf::Arena::Create<T>(arena_ptr.arena_.get(),
-                                                       std::forward<Args>(args)...));
-    return arena_ptr;
-  }
-
-  ArenaSharedPtr() = default;
-  template <typename Deleter>
-  ArenaSharedPtr(std::nullptr_t, Deleter d) : Base(nullptr, d) {}  // NOLINT explicit.
-
- private:
-  std::shared_ptr<google::protobuf::Arena> arena_{new google::protobuf::Arena{}};
-};
-
-}  // namespace serialize
-}  // namespace iorap
-
-#endif
-
diff --git a/src/serialize/protobuf_io.cc b/src/serialize/protobuf_io.cc
deleted file mode 100644
index 1b6420f..0000000
--- a/src/serialize/protobuf_io.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "protobuf_io.h"
-
-#include "common/trace.h"
-#include "serialize/arena_ptr.h"
-
-#include <android-base/chrono_utils.h>
-#include <android-base/logging.h>
-#include <android-base/unique_fd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <utils/Trace.h>
-
-#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
-#include "system/iorap/src/serialize/TraceFile.pb.h"
-
-namespace iorap {
-namespace serialize {
-
-ArenaPtr<proto::TraceFile> ProtobufIO::Open(std::string file_path) {
-  // TODO: file a bug about this.
-  // Note: can't use {} here, clang think it's narrowing from long->int.
-  android::base::unique_fd fd(TEMP_FAILURE_RETRY(::open(file_path.c_str(), O_RDONLY)));
-  if (fd.get() < 0) {
-    PLOG(DEBUG) << "ProtobufIO: open failed: " << file_path;
-    return nullptr;
-  }
-
-  return Open(fd.get(), file_path.c_str());
-}
-
-ArenaPtr<proto::TraceFile> ProtobufIO::Open(int fd, const char* file_path) {
-
-  ScopedFormatTrace atrace_protobuf_io_open(ATRACE_TAG_ACTIVITY_MANAGER,
-                                            "ProtobufIO::Open %s",
-                                            file_path);
-  android::base::Timer timer{};
-
-  struct stat buf;
-  if (fstat(fd, /*out*/&buf) < 0) {
-    PLOG(ERROR) << "ProtobufIO: open error, fstat failed: " << file_path;
-    return nullptr;
-  }
-  // XX: off64_t for stat::st_size ?
-
-  // Using the mmap appears to be the only way to do zero-copy with protobuf lite.
-  void* data = mmap(/*addr*/nullptr,
-                    buf.st_size,
-                    PROT_READ, MAP_SHARED | MAP_POPULATE,
-                    fd,
-                    /*offset*/0);
-  if (data == nullptr) {
-    PLOG(ERROR) << "ProtobufIO: open error, mmap failed: " << file_path;
-    return nullptr;
-  }
-
-  ArenaPtr<proto::TraceFile> protobuf_trace_file = ArenaPtr<proto::TraceFile>::Make();
-  if (protobuf_trace_file == nullptr) {
-    LOG(ERROR) << "ProtobufIO: open error, failed to create arena: " << file_path;
-    return nullptr;
-  }
-
-  google::protobuf::io::ArrayInputStream protobuf_input_stream{data, static_cast<int>(buf.st_size)};
-  if (!protobuf_trace_file->ParseFromZeroCopyStream(/*in*/&protobuf_input_stream)) {
-    // XX: Does protobuf on android already have the right LogHandler ?
-    LOG(ERROR) << "ProtobufIO: open error, protobuf parsing failed: " << file_path;
-    return nullptr;
-  }
-
-  if (munmap(data, buf.st_size) < 0) {
-    PLOG(WARNING) << "ProtobufIO: open problem, munmap failed, possibly memory leak? "
-                  << file_path;
-  }
-
-  LOG(VERBOSE) << "ProtobufIO: open succeeded: " << file_path << ", duration: " << timer;
-  return protobuf_trace_file;
-}
-
-iorap::expected<size_t /*bytes written*/, int /*errno*/> ProtobufIO::WriteFully(
-    const ::google::protobuf::MessageLite& message,
-    std::string_view file_path) {
-
-  std::string str{file_path};
-  android::base::unique_fd fd(TEMP_FAILURE_RETRY(
-      ::open(str.c_str(),
-             O_CREAT | O_TRUNC | O_RDWR,
-             S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)));  // ugo: rw-rw----
-  if (fd.get() < 0) {
-    int err = errno;
-    PLOG(ERROR) << "ProtobufIO: open failed: " << file_path;
-    return unexpected{err};
-  }
-
-  return WriteFully(message, fd.get(), file_path);
-}
-
-iorap::expected<size_t /*bytes written*/, int /*errno*/> ProtobufIO::WriteFully(
-    const ::google::protobuf::MessageLite& message,
-    int fd,
-    std::string_view file_path) {
-
-  int byte_size = message.ByteSize();
-  if (byte_size < 0) {
-    DCHECK(false) << "Invalid protobuf size: " << byte_size;
-    LOG(ERROR) << "ProtobufIO: Invalid protobuf size: " << byte_size;
-    return unexpected{EDOM};
-  }
-  size_t serialized_size = static_cast<size_t>(byte_size);
-
-  // Change the file to be exactly the length of the protobuf.
-  if (ftruncate(fd, static_cast<off_t>(serialized_size)) < 0) {
-    int err = errno;
-    PLOG(ERROR) << "ProtobufIO: ftruncate (size=" << serialized_size << ") failed";
-    return unexpected{err};
-  }
-
-  // Using the mmap appears to be the only way to do zero-copy with protobuf lite.
-  void* data = mmap(/*addr*/nullptr,
-                    serialized_size,
-                    PROT_WRITE,
-                    MAP_SHARED,
-                    fd,
-                    /*offset*/0);
-  if (data == nullptr) {
-    int err = errno;
-    PLOG(ERROR) << "ProtobufIO: mmap failed: " << file_path;
-    return unexpected{err};
-  }
-
-  // Zero-copy write from protobuf to file via memory-map.
-  ::google::protobuf::io::ArrayOutputStream output_stream{data, byte_size};
-  if (!message.SerializeToZeroCopyStream(/*inout*/&output_stream)) {
-    // This should never happen since we pre-allocated the file and memory map to be large
-    // enough to store the full protobuf.
-    DCHECK(false) << "ProtobufIO:: SerializeToZeroCopyStream failed despite precalculating size";
-    LOG(ERROR) << "ProtobufIO: SerializeToZeroCopyStream failed";
-    return unexpected{EXFULL};
-  }
-
-  // Guarantee that changes are written back prior to munmap.
-  if (msync(data, static_cast<size_t>(serialized_size), MS_SYNC) < 0) {
-    int err = errno;
-    PLOG(ERROR) << "ProtobufIO: msync failed";
-    return unexpected{err};
-  }
-
-  if (munmap(data, serialized_size) < 0) {
-    PLOG(WARNING) << "ProtobufIO: munmap failed, possibly memory leak? "
-                  << file_path;
-  }
-
-  return serialized_size;
-}
-
-}  // namespace serialize
-}  // namespace iorap
-
diff --git a/src/serialize/protobuf_io.h b/src/serialize/protobuf_io.h
deleted file mode 100644
index 1092fd7..0000000
--- a/src/serialize/protobuf_io.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SERIALIZE_PROTOBUF_IO_H_
-#define SERIALIZE_PROTOBUF_IO_H_
-
-#include "common/expected.h"
-#include "serialize/arena_ptr.h"
-#include "system/iorap/src/serialize/TraceFile.pb.h"
-
-#include <string>
-#include <string_view>
-
-namespace iorap {
-namespace serialize {
-
-// XX: either the namespace should be called pb|proto[buf]
-// or we should hide the protobuf-ness from the names and call this class "IO" , "Reader", etc?
-// although an obvious name might be the "OpenFactory" or "ProtobufFacade" that reads too much
-// like a bad joke.
-
-// Helpers to read a TraceFile protobuf from a file [descriptor].
-class ProtobufIO {
- public:
-  // XX: proto::TraceFile seems annoying, maybe just serialize::TraceFile ?
-
-  // Open the protobuf associated at the filepath. Returns null on failure.
-  static ArenaPtr<proto::TraceFile> Open(std::string file_path);
-  // Open the protobuf from the file descriptor. Returns null on failure.
-  static ArenaPtr<proto::TraceFile> Open(int fd, const char* file_path = "<unknown>");
-
-  // Save the protobuf by overwriting the file at file_path.
-  // The file state is indeterminate at failure.
-  // Returns # of bytes written out on success, otherwise the errno value.
-  static iorap::expected<size_t /*bytes written*/, int /*errno*/> WriteFully(
-      const ::google::protobuf::MessageLite& message,
-      std::string_view file_path);
-  // Save the protobuf by truncating the file already open at 'fd'.
-  // The file state is indeterminate at failure.
-  // Returns # of bytes written out on success, otherwise the errno value.
-  static iorap::expected<size_t /*bytes written*/, int /*errno*/> WriteFully(
-      const ::google::protobuf::MessageLite& message,
-      int fd,
-      std::string_view file_path = "<unknown>");
-
-  ProtobufIO() = delete;
-};
-
-}  // namespace serialize
-}  // namespace iorap
-
-#endif
-