Merge "Add IPsec tunnel migration feature flag"
diff --git a/Android.bp b/Android.bp
index 615a7a8..3992f82 100644
--- a/Android.bp
+++ b/Android.bp
@@ -56,7 +56,8 @@
 
 cc_library_headers {
     name: "libandroid_sensor_headers",
-    vendor: true,
+    vendor_available: true,
+    host_supported: true,
     export_include_dirs: ["include_sensor"],
 }
 
diff --git a/TEST_MAPPING b/TEST_MAPPING
index f54f132..e66bca0 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -28,9 +28,6 @@
           "include-filter": "*CropLatchingTest.*"
         },
         {
-          "include-filter": "*ChildLayerTest.*"
-        },
-        {
           "include-filter": "*ScreenCaptureTest.*"
         },
         {
@@ -56,9 +53,6 @@
         },
         {
           "include-filter": "*RefreshRateOverlayTest.*"
-        },
-        {
-          "exclude-filter": "*ChildLayerTest#ChildrenSurviveParentDestruction"
         }
       ]
     },
diff --git a/aidl/gui/android/view/Surface.aidl b/aidl/gui/android/view/Surface.aidl
index 7e89220..bb3faaf 100644
--- a/aidl/gui/android/view/Surface.aidl
+++ b/aidl/gui/android/view/Surface.aidl
@@ -17,4 +17,4 @@
 
 package android.view;
 
-parcelable Surface cpp_header "gui/view/Surface.h";
+@JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable Surface cpp_header "gui/view/Surface.h" ndk_header "android/native_window_aidl.h";
diff --git a/cmds/atrace/README.md b/cmds/atrace/README.md
new file mode 100644
index 0000000..faa43b2
--- /dev/null
+++ b/cmds/atrace/README.md
@@ -0,0 +1,48 @@
+# Atrace categories
+
+The atrace command (and the perfetto configuration) allow listing **categories**
+to select subsets of events to be traced.
+
+Each category can include some userspace events and some ftrace events.
+
+## Vendor categories
+
+It's possible to extend exiting categories (or to define new categories) from
+the /vendor partition in order to add hardware specific ftrace events.
+
+Since android 14, if the file `/vendor/etc/atrace/atrace_categories.txt`, atrace
+and perfetto will consider the categories and ftrace events listed there.
+
+The file contains a list of categories, and for each category (on the following
+lines, indented with one or more spaces of time), a list of ftrace events that
+should be enabled when the category is enabled.
+
+Each ftrace event should be a subdirectory in `/sys/kernel/tracing/events/` and
+should be of the form `group/event`. Listing a whole group is not supported,
+each event needs to be listed explicitly.
+
+It is not an error if an ftrace event is listed in the file, but not present on
+the tracing file system.
+
+Example:
+
+```
+gfx
+ mali/gpu_power_state
+ mali/mali_pm_status
+thermal_tj
+ thermal_exynos/thermal_cpu_pressure
+ thermal_exynos/thermal_exynos_arm_update
+```
+
+The file lists two categories (`gfx` and `thermal_tj`). When the `gfx` category
+is enabled, atrace (or perfetto) will enable
+`/sys/kernel/tracing/events/mali/gpu_power_state` and
+`/sys/kernel/tracing/events/mali/mali_pm_status`. When the `thermal_tj` category
+is enabled, atrace (or perfetto) will enable
+`/sys/kernel/tracing/events/thermal_exynos/thermal_cpu_pressure` and
+`/sys/kernel/tracing/events/thermal_exynos/thermal_exynos_arm_update`.
+
+Since android 14, if the file `/vendor/etc/atrace/atrace_categories.txt` exists
+on the file system, perfetto and atrace do not query the android.hardware.atrace
+HAL (which is deprecated).
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 48d48ac..8105626 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -49,6 +49,7 @@
 #include <android-base/file.h>
 #include <android-base/macros.h>
 #include <android-base/properties.h>
+#include <android-base/strings.h>
 #include <android-base/stringprintf.h>
 
 using namespace android;
@@ -62,7 +63,7 @@
 
 using std::string;
 
-#define MAX_SYS_FILES 12
+#define MAX_SYS_FILES 13
 
 const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
 const char* k_userInitiatedTraceProperty = "debug.atrace.user_initiated";
@@ -73,7 +74,9 @@
 const char* k_pdxServiceCategory = "pdx";
 const char* k_coreServicesProp = "ro.atrace.core.services";
 
-typedef enum { OPT, REQ } requiredness  ;
+const char* kVendorCategoriesPath = "/vendor/etc/atrace/atrace_categories.txt";
+
+typedef enum { OPT, REQ } requiredness;
 
 struct TracingCategory {
     // The name identifying the category.
@@ -189,6 +192,8 @@
         { OPT,      "events/f2fs/f2fs_sync_file_exit/enable" },
         { OPT,      "events/f2fs/f2fs_write_begin/enable" },
         { OPT,      "events/f2fs/f2fs_write_end/enable" },
+        { OPT,      "events/f2fs/f2fs_iostat/enable" },
+        { OPT,      "events/f2fs/f2fs_iostat_latency/enable" },
         { OPT,      "events/ext4/ext4_da_write_begin/enable" },
         { OPT,      "events/ext4/ext4_da_write_end/enable" },
         { OPT,      "events/ext4/ext4_sync_file_enter/enable" },
@@ -253,7 +258,20 @@
     } },
 };
 
-struct TracingVendorCategory {
+// A category in the vendor categories file.
+struct TracingVendorFileCategory {
+    // The name identifying the category.
+    std::string name;
+
+    // If the category is enabled through command.
+    bool enabled = false;
+
+    // Paths to the ftrace enable files (relative to g_traceFolder).
+    std::vector<std::string> ftrace_enable_paths;
+};
+
+// A category in the vendor HIDL HAL.
+struct TracingVendorHalCategory {
     // The name identifying the category.
     std::string name;
 
@@ -263,11 +281,8 @@
     // If the category is enabled through command.
     bool enabled;
 
-    TracingVendorCategory(string &&name, string &&description, bool enabled)
-            : name(std::move(name))
-            , description(std::move(description))
-            , enabled(enabled)
-    {}
+    TracingVendorHalCategory(string&& name, string&& description, bool enabled)
+          : name(std::move(name)), description(std::move(description)), enabled(enabled) {}
 };
 
 /* Command line options */
@@ -287,8 +302,9 @@
 static bool g_traceAborted = false;
 static bool g_categoryEnables[arraysize(k_categories)] = {};
 static std::string g_traceFolder;
+static std::vector<TracingVendorFileCategory> g_vendorFileCategories;
 static sp<IAtraceDevice> g_atraceHal;
-static std::vector<TracingVendorCategory> g_vendorCategories;
+static std::vector<TracingVendorHalCategory> g_vendorHalCategories;
 
 /* Sys file paths */
 static const char* k_traceClockPath =
@@ -645,6 +661,13 @@
             }
         }
     }
+    for (const TracingVendorFileCategory& c : g_vendorFileCategories) {
+        for (const std::string& path : c.ftrace_enable_paths) {
+            if (fileIsWritable(path.c_str())) {
+                ok &= setKernelOptionEnable(path.c_str(), false);
+            }
+        }
+    }
     return ok;
 }
 
@@ -724,7 +747,13 @@
 static bool setCategoryEnable(const char* name)
 {
     bool vendor_found = false;
-    for (auto &c : g_vendorCategories) {
+    for (auto& c : g_vendorFileCategories) {
+        if (strcmp(name, c.name.c_str()) == 0) {
+            c.enabled = true;
+            vendor_found = true;
+        }
+    }
+    for (auto& c : g_vendorHalCategories) {
         if (strcmp(name, c.name.c_str()) == 0) {
             c.enabled = true;
             vendor_found = true;
@@ -870,6 +899,16 @@
         }
     }
 
+    for (const TracingVendorFileCategory& c : g_vendorFileCategories) {
+        if (c.enabled) {
+            for (const std::string& path : c.ftrace_enable_paths) {
+                if (fileIsWritable(path.c_str())) {
+                    ok &= setKernelOptionEnable(path.c_str(), true);
+                }
+            }
+        }
+    }
+
     return ok;
 }
 
@@ -1055,7 +1094,10 @@
             printf("  %10s - %s\n", c.name, c.longname);
         }
     }
-    for (const auto &c : g_vendorCategories) {
+    for (const auto& c : g_vendorFileCategories) {
+        printf("  %10s - (VENDOR)\n", c.name.c_str());
+    }
+    for (const auto& c : g_vendorHalCategories) {
         printf("  %10s - %s (HAL)\n", c.name.c_str(), c.description.c_str());
     }
 }
@@ -1114,8 +1156,38 @@
     return true;
 }
 
-void initVendorCategories()
-{
+void initVendorCategoriesFromFile() {
+    std::ifstream is(kVendorCategoriesPath);
+    for (std::string line; std::getline(is, line);) {
+        if (line.empty()) {
+            continue;
+        }
+        if (android::base::StartsWith(line, ' ') || android::base::StartsWith(line, '\t')) {
+            if (g_vendorFileCategories.empty()) {
+                fprintf(stderr, "Malformed vendor categories file\n");
+                exit(1);
+                return;
+            }
+            std::string_view path = std::string_view(line).substr(1);
+            while (android::base::StartsWith(path, ' ') || android::base::StartsWith(path, '\t')) {
+                path.remove_prefix(1);
+            }
+            if (path.empty()) {
+                continue;
+            }
+            std::string enable_path = "events/";
+            enable_path += path;
+            enable_path += "/enable";
+            g_vendorFileCategories.back().ftrace_enable_paths.push_back(std::move(enable_path));
+        } else {
+            TracingVendorFileCategory cat;
+            cat.name = line;
+            g_vendorFileCategories.push_back(std::move(cat));
+        }
+    }
+}
+
+void initVendorCategoriesFromHal() {
     g_atraceHal = IAtraceDevice::getService();
 
     if (g_atraceHal == nullptr) {
@@ -1123,27 +1195,34 @@
         return;
     }
 
-    Return<void> ret = g_atraceHal->listCategories(
-        [](const auto& list) {
-            g_vendorCategories.reserve(list.size());
-            for (const auto& category : list) {
-                g_vendorCategories.emplace_back(category.name, category.description, false);
-            }
-        });
+    Return<void> ret = g_atraceHal->listCategories([](const auto& list) {
+        g_vendorHalCategories.reserve(list.size());
+        for (const auto& category : list) {
+            g_vendorHalCategories.emplace_back(category.name, category.description, false);
+        }
+    });
     if (!ret.isOk()) {
         fprintf(stderr, "calling atrace HAL failed: %s\n", ret.description().c_str());
     }
 }
 
-static bool setUpVendorTracing()
-{
+void initVendorCategories() {
+    // If kVendorCategoriesPath exists on the filesystem, do not use the HAL.
+    if (access(kVendorCategoriesPath, F_OK) != -1) {
+        initVendorCategoriesFromFile();
+    } else {
+        initVendorCategoriesFromHal();
+    }
+}
+
+static bool setUpVendorTracingWithHal() {
     if (g_atraceHal == nullptr) {
         // No atrace HAL
         return true;
     }
 
     std::vector<hidl_string> categories;
-    for (const auto &c : g_vendorCategories) {
+    for (const auto& c : g_vendorHalCategories) {
         if (c.enabled) {
             categories.emplace_back(c.name);
         }
@@ -1164,15 +1243,14 @@
     return true;
 }
 
-static bool cleanUpVendorTracing()
-{
+static bool cleanUpVendorTracingWithHal() {
     if (g_atraceHal == nullptr) {
         // No atrace HAL
         return true;
     }
 
-    if (!g_vendorCategories.size()) {
-        // No vendor categories
+    if (!g_vendorHalCategories.size()) {
+        // No vendor HAL categories
         return true;
     }
 
@@ -1326,7 +1404,7 @@
 
     if (ok && traceStart && !onlyUserspace) {
         ok &= setUpKernelTracing();
-        ok &= setUpVendorTracing();
+        ok &= setUpVendorTracingWithHal();
         ok &= startTrace();
     }
 
@@ -1397,7 +1475,7 @@
     if (traceStop) {
         cleanUpUserspaceTracing();
         if (!onlyUserspace) {
-            cleanUpVendorTracing();
+            cleanUpVendorTracingWithHal();
             cleanUpKernelTracing();
         }
     }
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index a60972b..a62bd01 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -126,6 +126,7 @@
     ],
     required: [
         "atrace",
+        "bugreport_procdump",
         "dmabuf_dump",
         "ip",
         "iptables",
diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp
index 3091f6b..6f7fea3 100644
--- a/cmds/dumpstate/DumpstateInternal.cpp
+++ b/cmds/dumpstate/DumpstateInternal.cpp
@@ -162,17 +162,16 @@
         return 0;
     }
     bool newline = false;
+    int poll_timeout_ms = 30 * 1000;
     while (true) {
-        uint64_t start_time = Nanotime();
         pollfd fds[] = { { .fd = fd, .events = POLLIN } };
-        int ret = TEMP_FAILURE_RETRY(poll(fds, arraysize(fds), 30 * 1000));
+        int ret = TEMP_FAILURE_RETRY(poll(fds, arraysize(fds), poll_timeout_ms));
         if (ret == -1) {
             dprintf(out_fd, "*** %s: poll failed: %s\n", path, strerror(errno));
             newline = true;
             break;
-        } else if (ret == 0) {
-            uint64_t elapsed = Nanotime() - start_time;
-            dprintf(out_fd, "*** %s: Timed out after %.3fs\n", path, (float)elapsed / NANOS_PER_SEC);
+        } else if (ret == 0 && poll_timeout_ms != 0) {
+            dprintf(out_fd, "*** %s: Timed out after %ds\n", path, poll_timeout_ms / 1000 );
             newline = true;
             break;
         } else {
@@ -189,6 +188,7 @@
                 break;
             }
         }
+        poll_timeout_ms = 0;
     }
 
     if (!newline) dprintf(out_fd, "\n");
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 6e9747f..12de33f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -170,6 +170,7 @@
 #define RECOVERY_DIR "/cache/recovery"
 #define RECOVERY_DATA_DIR "/data/misc/recovery"
 #define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
+#define UPDATE_ENGINE_PREF_DIR "/data/misc/update_engine/prefs"
 #define LOGPERSIST_DATA_DIR "/data/misc/logd"
 #define PREREBOOT_DATA_DIR "/data/misc/prereboot"
 #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
@@ -193,6 +194,8 @@
 static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
 static const std::string ANR_DIR = "/data/anr/";
 static const std::string ANR_FILE_PREFIX = "anr_";
+static const std::string SHUTDOWN_CHECKPOINTS_DIR = "/data/system/shutdown-checkpoints/";
+static const std::string SHUTDOWN_CHECKPOINTS_FILE_PREFIX = "checkpoints-";
 
 // TODO: temporary variables and functions used during C++ refactoring
 
@@ -234,6 +237,7 @@
 // task and the log title of the duration report.
 static const std::string DUMP_TRACES_TASK = "DUMP TRACES";
 static const std::string DUMP_INCIDENT_REPORT_TASK = "INCIDENT REPORT";
+static const std::string DUMP_NETSTATS_PROTO_TASK = "DUMP NETSTATS PROTO";
 static const std::string DUMP_HALS_TASK = "DUMP HALS";
 static const std::string DUMP_BOARD_TASK = "dumpstate_board()";
 static const std::string DUMP_CHECKINS_TASK = "DUMP CHECKINS";
@@ -1041,6 +1045,26 @@
     }
 }
 
+static void DumpNetstatsProto() {
+    const std::string path = ds.bugreport_internal_dir_ + "/tmp_netstats_proto";
+    auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
+                O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+    if (fd < 0) {
+        MYLOGE("Could not open %s to dump netstats proto.\n", path.c_str());
+        return;
+    }
+    RunCommandToFd(fd, "", {"dumpsys", "netstats", "--proto"},
+            CommandOptions::WithTimeout(120).Build());
+    bool empty = 0 == lseek(fd, 0, SEEK_END);
+    if (!empty) {
+        ds.EnqueueAddZipEntryAndCleanupIfNeeded(kProtoPath + "netstats" + kProtoExt,
+                path);
+    } else {
+        unlink(path.c_str());
+    }
+}
+
 static void MaybeAddSystemTraceToZip() {
     // This function copies into the .zip the system trace that was snapshotted
     // by the early call to MaybeSnapshotSystemTrace(), if any background
@@ -1087,6 +1111,16 @@
     RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
 }
 
+static void DumpShutdownCheckpoints() {
+    const bool shutdown_checkpoints_dumped = AddDumps(
+        ds.shutdown_checkpoints_.begin(), ds.shutdown_checkpoints_.end(),
+        "SHUTDOWN CHECKPOINTS", false /* add_to_zip */);
+    if (!shutdown_checkpoints_dumped) {
+        printf("*** NO SHUTDOWN CHECKPOINTS to dump in %s\n\n",
+            SHUTDOWN_CHECKPOINTS_DIR.c_str());
+    }
+}
+
 static void DumpDynamicPartitionInfo() {
     if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
         return;
@@ -1576,7 +1610,8 @@
     DurationReporter duration_reporter("DUMPSTATE");
 
     // Enqueue slow functions into the thread pool, if the parallel run is enabled.
-    std::future<std::string> dump_hals, dump_incident_report, dump_board, dump_checkins;
+    std::future<std::string> dump_hals, dump_incident_report, dump_board, dump_checkins,
+            dump_netstats_report;
     if (ds.dump_pool_) {
         // Pool was shutdown in DumpstateDefaultAfterCritical method in order to
         // drop root user. Restarts it with two threads for the parallel run.
@@ -1585,6 +1620,8 @@
         dump_hals = ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
         dump_incident_report = ds.dump_pool_->enqueueTask(
             DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
+        dump_netstats_report = ds.dump_pool_->enqueueTask(
+            DUMP_NETSTATS_PROTO_TASK, &DumpNetstatsProto);
         dump_board = ds.dump_pool_->enqueueTaskWithFd(
             DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
         dump_checkins = ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
@@ -1600,7 +1637,8 @@
     RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
                             "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
 
-    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "BUGREPORT_PROCDUMP", {"bugreport_procdump"},
+                                         CommandOptions::AS_ROOT);
 
     RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpVisibleWindowViews);
 
@@ -1617,9 +1655,6 @@
     RunCommand("PROCESSES AND THREADS",
                {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
 
-    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
-                                         CommandOptions::AS_ROOT);
-
     if (ds.dump_pool_) {
         WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_hals));
     } else {
@@ -1649,8 +1684,6 @@
 
     RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
 
-    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
-
     for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
     for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
 
@@ -1680,6 +1713,8 @@
 
     DoKmsg();
 
+    DumpShutdownCheckpoints();
+
     DumpIpAddrAndRules();
 
     dump_route_tables();
@@ -1783,6 +1818,13 @@
     dump_frozen_cgroupfs();
 
     if (ds.dump_pool_) {
+        WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_netstats_report));
+    } else {
+        RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_NETSTATS_PROTO_TASK,
+                DumpNetstatsProto);
+    }
+
+    if (ds.dump_pool_) {
         WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_incident_report));
     } else {
         RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_INCIDENT_REPORT_TASK,
@@ -1827,11 +1869,14 @@
     if (!PropertiesHelper::IsDryRun()) {
         ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX);
         ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX);
+        ds.shutdown_checkpoints_ = GetDumpFds(
+            SHUTDOWN_CHECKPOINTS_DIR, SHUTDOWN_CHECKPOINTS_FILE_PREFIX);
     }
 
     ds.AddDir(RECOVERY_DIR, true);
     ds.AddDir(RECOVERY_DATA_DIR, true);
     ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
+    ds.AddDir(UPDATE_ENGINE_PREF_DIR, true);
     ds.AddDir(LOGPERSIST_DATA_DIR, false);
     if (!PropertiesHelper::IsUserBuild()) {
         ds.AddDir(PROFILE_DATA_DIR_CUR, true);
@@ -2878,6 +2923,7 @@
     }
     tombstone_data_.clear();
     anr_data_.clear();
+    shutdown_checkpoints_.clear();
 
     // Instead of shutdown the pool, we delete temporary files directly since
     // shutdown blocking the call.
@@ -3161,6 +3207,7 @@
 
     tombstone_data_.clear();
     anr_data_.clear();
+    shutdown_checkpoints_.clear();
 
     return (consent_callback_ != nullptr &&
             consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
@@ -3891,15 +3938,6 @@
     return;
 }
 
-void do_showmap(int pid, const char *name) {
-    char title[255];
-    char arg[255];
-
-    snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
-    snprintf(arg, sizeof(arg), "%d", pid);
-    RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
-}
-
 int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
     DurationReporter duration_reporter(title);
 
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index ee6b1ae..7ffe80e 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -499,6 +499,9 @@
     // List of open ANR dump files.
     std::vector<DumpData> anr_data_;
 
+    // List of open shutdown checkpoint files.
+    std::vector<DumpData> shutdown_checkpoints_;
+
     // A thread pool to execute dump tasks simultaneously if the parallel run is enabled.
     std::unique_ptr<android::os::dumpstate::DumpPool> dump_pool_;
 
@@ -619,9 +622,6 @@
 /* Displays a processes times */
 void show_showtime(int pid, const char *name);
 
-/* Runs "showmap" for a process */
-void do_showmap(int pid, const char *name);
-
 /* Gets the dmesg output for the kernel */
 void do_dmesg();
 
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index f0c19b9..b8e5ce1 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -60,6 +60,7 @@
     MOCK_METHOD1(isDeclared, bool(const String16&));
     MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&));
     MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&));
+    MOCK_METHOD1(getUpdatableNames, Vector<String16>(const String16&));
     MOCK_METHOD1(getConnectionInfo, std::optional<ConnectionInfo>(const String16&));
     MOCK_METHOD2(registerForNotifications, status_t(const String16&,
                                              const sp<LocalRegistrationCallback>&));
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index faf67fd..bb6639e 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -99,6 +99,8 @@
 
 static constexpr const char* kDataMirrorCePath = "/data_mirror/data_ce";
 static constexpr const char* kDataMirrorDePath = "/data_mirror/data_de";
+static constexpr const char* kMiscMirrorCePath = "/data_mirror/misc_ce";
+static constexpr const char* kMiscMirrorDePath = "/data_mirror/misc_de";
 
 static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
 
@@ -499,10 +501,6 @@
 }
 
 static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
-    if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
-        return true;
-    }
-
     int32_t uid = multiuser_get_uid(userId, appId);
     int shared_app_gid = multiuser_get_shared_gid(userId, appId);
     if (shared_app_gid == -1) {
@@ -3558,16 +3556,28 @@
 
     std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
     if (fs_prepare_dir(mirrorVolCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
-        return error("Failed to create CE mirror");
+        return error("Failed to create CE data mirror");
     }
 
     std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
     if (fs_prepare_dir(mirrorVolDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
-        return error("Failed to create DE mirror");
+        return error("Failed to create DE data mirror");
+    }
+
+    std::string mirrorVolMiscCePath(StringPrintf("%s/%s", kMiscMirrorCePath, uuid_));
+    if (fs_prepare_dir(mirrorVolMiscCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+        return error("Failed to create CE misc mirror");
+    }
+
+    std::string mirrorVolMiscDePath(StringPrintf("%s/%s", kMiscMirrorDePath, uuid_));
+    if (fs_prepare_dir(mirrorVolMiscDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+        return error("Failed to create DE misc mirror");
     }
 
     auto cePath = StringPrintf("%s/user", create_data_path(uuid_).c_str());
     auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str());
+    auto miscCePath = StringPrintf("%s/misc_ce", create_data_path(uuid_).c_str());
+    auto miscDePath = StringPrintf("%s/misc_de", create_data_path(uuid_).c_str());
 
     if (access(cePath.c_str(), F_OK) != 0) {
         return error("Cannot access CE path: " + cePath);
@@ -3575,6 +3585,12 @@
     if (access(dePath.c_str(), F_OK) != 0) {
         return error("Cannot access DE path: " + dePath);
     }
+    if (access(miscCePath.c_str(), F_OK) != 0) {
+        return error("Cannot access misc CE path: " + cePath);
+    }
+    if (access(miscDePath.c_str(), F_OK) != 0) {
+        return error("Cannot access misc DE path: " + dePath);
+    }
 
     struct stat ceStat, mirrorCeStat;
     if (stat(cePath.c_str(), &ceStat) != 0) {
@@ -3602,6 +3618,21 @@
             MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
         return error("Failed to mount " + mirrorVolDePath);
     }
+
+    // Mount misc CE mirror
+    if (TEMP_FAILURE_RETRY(mount(miscCePath.c_str(), mirrorVolMiscCePath.c_str(), NULL,
+                                 MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC,
+                                 nullptr)) == -1) {
+        return error("Failed to mount " + mirrorVolMiscCePath);
+    }
+
+    // Mount misc DE mirror
+    if (TEMP_FAILURE_RETRY(mount(miscDePath.c_str(), mirrorVolMiscDePath.c_str(), NULL,
+                                 MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC,
+                                 nullptr)) == -1) {
+        return error("Failed to mount " + mirrorVolMiscDePath);
+    }
+
     return ok();
 }
 
@@ -3624,6 +3655,8 @@
 
     std::string mirrorCeVolPath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
     std::string mirrorDeVolPath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
+    std::string mirrorMiscCeVolPath(StringPrintf("%s/%s", kMiscMirrorCePath, uuid_));
+    std::string mirrorMiscDeVolPath(StringPrintf("%s/%s", kMiscMirrorDePath, uuid_));
 
     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
 
@@ -3648,6 +3681,29 @@
     if (delete_dir_contents_and_dir(mirrorDeVolPath, true) != 0) {
         res = error("Failed to delete " + mirrorDeVolPath);
     }
+
+    // Unmount misc CE storage
+    if (TEMP_FAILURE_RETRY(umount(mirrorMiscCeVolPath.c_str())) != 0) {
+        if (errno != ENOENT) {
+            res = error(StringPrintf("Failed to umount %s %s", mirrorMiscCeVolPath.c_str(),
+                                     strerror(errno)));
+        }
+    }
+    if (delete_dir_contents_and_dir(mirrorMiscCeVolPath, true) != 0) {
+        res = error("Failed to delete " + mirrorMiscCeVolPath);
+    }
+
+    // Unmount misc DE storage
+    if (TEMP_FAILURE_RETRY(umount(mirrorMiscDeVolPath.c_str())) != 0) {
+        if (errno != ENOENT) {
+            res = error(StringPrintf("Failed to umount %s %s", mirrorMiscDeVolPath.c_str(),
+                                     strerror(errno)));
+        }
+    }
+    if (delete_dir_contents_and_dir(mirrorMiscDeVolPath, true) != 0) {
+        res = error("Failed to delete " + mirrorMiscDeVolPath);
+    }
+
     return res;
 }
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index ebb7891..34ea759 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1956,7 +1956,7 @@
                       join_fds(context_input_fds), swap_fd.get(), instruction_set, compiler_filter,
                       debuggable, boot_complete, for_restore, target_sdk_version,
                       enable_hidden_api_checks, generate_compact_dex, use_jitzygote_image,
-                      compilation_reason);
+                      background_job_compile, compilation_reason);
 
     bool cancelled = false;
     pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled);
diff --git a/cmds/installd/otapreopt.rc b/cmds/installd/otapreopt.rc
index 059ae75..0bad0c5 100644
--- a/cmds/installd/otapreopt.rc
+++ b/cmds/installd/otapreopt.rc
@@ -5,4 +5,4 @@
     # The dalvik-cache was not moved itself, so as to restrict the rights of otapreopt_slot.
     # But now the relabeling is annoying as there is no force option available here. So
     # explicitly list all the ISAs we know.
-    restorecon_recursive /data/dalvik-cache/arm /data/dalvik-cache/arm64 /data/dalvik-cache/mips /data/dalvik-cache/mips64 /data/dalvik-cache/x86 /data/dalvik-cache/x86_64
+    restorecon_recursive /data/dalvik-cache/arm /data/dalvik-cache/arm64 /data/dalvik-cache/riscv64 /data/dalvik-cache/x86 /data/dalvik-cache/x86_64
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
index 51c4589..4221a3a 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -81,6 +81,7 @@
                             bool enable_hidden_api_checks,
                             bool generate_compact_dex,
                             bool use_jitzygote,
+                            bool background_job_compile,
                             const char* compilation_reason) {
     PrepareBootImageFlags(use_jitzygote);
 
@@ -92,7 +93,8 @@
                                debuggable, target_sdk_version, enable_hidden_api_checks,
                                generate_compact_dex, compilation_reason);
 
-    PrepareCompilerRuntimeAndPerfConfigFlags(post_bootcomplete, for_restore);
+    PrepareCompilerRuntimeAndPerfConfigFlags(post_bootcomplete, for_restore,
+                                             background_job_compile);
 
     const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
     std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
@@ -296,7 +298,8 @@
 }
 
 void RunDex2Oat::PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete,
-                                                          bool for_restore) {
+                                                          bool for_restore,
+                                                          bool background_job_compile) {
     // CPU set
     {
         std::string cpu_set_format = "--cpu-set=%s";
@@ -306,7 +309,12 @@
                            "dalvik.vm.restore-dex2oat-cpu-set",
                            "dalvik.vm.dex2oat-cpu-set",
                            cpu_set_format)
-                   : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format))
+                   : (background_job_compile
+                      ? MapPropertyToArgWithBackup(
+                              "dalvik.vm.background-dex2oat-cpu-set",
+                              "dalvik.vm.dex2oat-cpu-set",
+                              cpu_set_format)
+                      : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format)))
                 : MapPropertyToArg("dalvik.vm.boot-dex2oat-cpu-set", cpu_set_format);
         AddArg(dex2oat_cpu_set_arg);
     }
@@ -320,7 +328,12 @@
                            "dalvik.vm.restore-dex2oat-threads",
                            "dalvik.vm.dex2oat-threads",
                            threads_format)
-                   : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format))
+                   : (background_job_compile
+                      ? MapPropertyToArgWithBackup(
+                              "dalvik.vm.background-dex2oat-threads",
+                              "dalvik.vm.dex2oat-threads",
+                              threads_format)
+                      : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format)))
                 : MapPropertyToArg("dalvik.vm.boot-dex2oat-threads", threads_format);
         AddArg(dex2oat_threads_arg);
     }
diff --git a/cmds/installd/run_dex2oat.h b/cmds/installd/run_dex2oat.h
index 559244f..c13e1f1 100644
--- a/cmds/installd/run_dex2oat.h
+++ b/cmds/installd/run_dex2oat.h
@@ -51,6 +51,7 @@
                     bool enable_hidden_api_checks,
                     bool generate_compact_dex,
                     bool use_jitzygote,
+                    bool background_job_compile,
                     const char* compilation_reason);
 
     void Exec(int exit_code);
@@ -76,7 +77,9 @@
                                     bool enable_hidden_api_checks,
                                     bool generate_compact_dex,
                                     const char* compilation_reason);
-    void PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete, bool for_restore);
+    void PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete,
+                                                  bool for_restore,
+                                                  bool background_job_compile);
 
     virtual std::string GetProperty(const std::string& key, const std::string& default_value);
     virtual bool GetBoolProperty(const std::string& key, bool default_value);
diff --git a/cmds/installd/run_dex2oat_test.cpp b/cmds/installd/run_dex2oat_test.cpp
index 2a8135a..304ba7b 100644
--- a/cmds/installd/run_dex2oat_test.cpp
+++ b/cmds/installd/run_dex2oat_test.cpp
@@ -115,6 +115,7 @@
         bool enable_hidden_api_checks = false;
         bool generate_compact_dex = true;
         bool use_jitzygote = false;
+        bool background_job_compile = false;
         const char* compilation_reason = nullptr;
     };
 
@@ -259,6 +260,7 @@
                           args->enable_hidden_api_checks,
                           args->generate_compact_dex,
                           args->use_jitzygote,
+                          args->background_job_compile,
                           args->compilation_reason);
         runner.Exec(/*exit_code=*/ 0);
     }
@@ -375,6 +377,30 @@
     VerifyExpectedFlags();
 }
 
+TEST_F(RunDex2OatTest, CpuSetPostBootCompleteBackground) {
+    setSystemProperty("dalvik.vm.background-dex2oat-cpu-set", "1,3");
+    setSystemProperty("dalvik.vm.dex2oat-cpu-set", "1,2");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->post_bootcomplete = true;
+    args->background_job_compile = true;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--cpu-set", "=1,3");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, CpuSetPostBootCompleteBackground_Backup) {
+    setSystemProperty("dalvik.vm.background-dex2oat-cpu-set", "");
+    setSystemProperty("dalvik.vm.dex2oat-cpu-set", "1,2");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->post_bootcomplete = true;
+    args->background_job_compile = true;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--cpu-set", "=1,2");
+    VerifyExpectedFlags();
+}
+
 TEST_F(RunDex2OatTest, CpuSetPostBootCompleteForRestore) {
     setSystemProperty("dalvik.vm.restore-dex2oat-cpu-set", "1,2");
     setSystemProperty("dalvik.vm.dex2oat-cpu-set", "2,3");
@@ -481,6 +507,30 @@
     VerifyExpectedFlags();
 }
 
+TEST_F(RunDex2OatTest, ThreadsPostBootCompleteBackground) {
+    setSystemProperty("dalvik.vm.background-dex2oat-threads", "2");
+    setSystemProperty("dalvik.vm.dex2oat-threads", "3");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->post_bootcomplete = true;
+    args->background_job_compile = true;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("-j", "2");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, ThreadsPostBootCompleteBackground_Backup) {
+    setSystemProperty("dalvik.vm.background-dex2oat-threads", "");
+    setSystemProperty("dalvik.vm.dex2oat-threads", "3");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->post_bootcomplete = true;
+    args->background_job_compile = true;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("-j", "3");
+    VerifyExpectedFlags();
+}
+
 TEST_F(RunDex2OatTest, ThreadsPostBootCompleteForRestore) {
     setSystemProperty("dalvik.vm.restore-dex2oat-threads", "4");
     setSystemProperty("dalvik.vm.dex2oat-threads", "5");
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 6ef41e3..3b589dc 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -23,6 +23,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/macros.h>
 #include <android-base/properties.h>
 #include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
@@ -52,22 +53,7 @@
 
 constexpr int kTimeoutMs = 60000;
 
-// TODO(calin): try to dedup this code.
-#if defined(__arm__)
-static const std::string kRuntimeIsa = "arm";
-#elif defined(__aarch64__)
-static const std::string kRuntimeIsa = "arm64";
-#elif defined(__mips__) && !defined(__LP64__)
-static const std::string kRuntimeIsa = "mips";
-#elif defined(__mips__) && defined(__LP64__)
-static const std::string kRuntimeIsa = "mips64";
-#elif defined(__i386__)
-static const std::string kRuntimeIsa = "x86";
-#elif defined(__x86_64__)
-static const std::string kRuntimeIsa = "x86_64";
-#else
-static const std::string kRuntimeIsa = "none";
-#endif
+static const std::string kRuntimeIsa = ABI_STRING;
 
 int get_property(const char *key, char *value, const char *default_value) {
     return property_get(key, value, default_value);
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index fd879c6..1386660 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -48,14 +48,6 @@
 }
 
 cc_binary {
-    name: "servicemanager.microdroid",
-    defaults: ["servicemanager_defaults"],
-    init_rc: ["servicemanager.microdroid.rc"],
-    srcs: ["main.cpp"],
-    bootstrap: true,
-}
-
-cc_binary {
     name: "servicemanager.recovery",
     stem: "servicemanager",
     recovery: true,
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 3681d5b..cc038ae 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -136,12 +136,33 @@
             updatableViaApex = manifestInstance.updatableViaApex();
             return false; // break (libvintf uses opposite convention)
         });
+        if (updatableViaApex.has_value()) return true; // break (found match)
         return false; // continue
     });
 
     return updatableViaApex;
 }
 
+static std::vector<std::string> getVintfUpdatableInstances(const std::string& apexName) {
+    std::vector<std::string> instances;
+
+    forEachManifest([&](const ManifestWithDescription& mwd) {
+        mwd.manifest->forEachInstance([&](const auto& manifestInstance) {
+            if (manifestInstance.format() == vintf::HalFormat::AIDL &&
+                manifestInstance.updatableViaApex().has_value() &&
+                manifestInstance.updatableViaApex().value() == apexName) {
+                std::string aname = manifestInstance.package() + "." +
+                        manifestInstance.interface() + "/" + manifestInstance.instance();
+                instances.push_back(aname);
+            }
+            return true; // continue (libvintf uses opposite convention)
+        });
+        return false; // continue
+    });
+
+    return instances;
+}
+
 static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& name) {
     AidlName aname;
     if (!AidlName::fill(name, &aname)) return std::nullopt;
@@ -512,6 +533,30 @@
     return Status::ok();
 }
 
+Status ServiceManager::getUpdatableNames([[maybe_unused]] const std::string& apexName,
+                                         std::vector<std::string>* outReturn) {
+    auto ctx = mAccess->getCallingContext();
+
+    std::vector<std::string> apexUpdatableInstances;
+#ifndef VENDORSERVICEMANAGER
+    apexUpdatableInstances = getVintfUpdatableInstances(apexName);
+#endif
+
+    outReturn->clear();
+
+    for (const std::string& instance : apexUpdatableInstances) {
+        if (mAccess->canFind(ctx, instance)) {
+            outReturn->push_back(instance);
+        }
+    }
+
+    if (outReturn->size() == 0 && apexUpdatableInstances.size() != 0) {
+        return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denial");
+    }
+
+    return Status::ok();
+}
+
 Status ServiceManager::getConnectionInfo(const std::string& name,
                                          std::optional<ConnectionInfo>* outReturn) {
     auto ctx = mAccess->getCallingContext();
@@ -568,7 +613,8 @@
 }
 
 void ServiceManager::tryStartService(const std::string& name) {
-    ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service",
+    ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service. (if it's not "
+          "configured to be a lazy service, it may be stuck starting or still starting).",
           name.c_str());
 
     std::thread([=] {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 07b79f8..b24c11c 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -49,6 +49,8 @@
     binder::Status getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) override;
     binder::Status updatableViaApex(const std::string& name,
                                     std::optional<std::string>* outReturn) override;
+    binder::Status getUpdatableNames(const std::string& apexName,
+                                     std::vector<std::string>* outReturn) override;
     binder::Status getConnectionInfo(const std::string& name,
                                      std::optional<ConnectionInfo>* outReturn) override;
     binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service,
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index a831d1b..c1a04dd 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -111,9 +111,7 @@
 };
 
 int main(int argc, char** argv) {
-#ifdef __ANDROID_RECOVERY__
     android::base::InitLogging(argv, android::base::KernelLogger);
-#endif
 
     if (argc > 2) {
         LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
diff --git a/cmds/servicemanager/servicemanager.microdroid.rc b/cmds/servicemanager/servicemanager.microdroid.rc
deleted file mode 100644
index c516043..0000000
--- a/cmds/servicemanager/servicemanager.microdroid.rc
+++ /dev/null
@@ -1,9 +0,0 @@
-service servicemanager /system/bin/servicemanager.microdroid
-    class core
-    user system
-    group system readproc
-    critical
-    onrestart setprop servicemanager.ready false
-    onrestart restart apexd
-    task_profiles ServiceCapacityLow
-    shutdown critical
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index 6b35265..3bd6db5 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -3,6 +3,7 @@
     user system
     group system readproc
     critical
+    file /dev/kmsg w
     onrestart setprop servicemanager.ready false
     onrestart restart apexd
     onrestart restart audioserver
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
index 5d5a75e..0fd8d8e 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
+#include <android-base/properties.h>
+#include <android-base/strings.h>
 #include <android/os/BnServiceCallback.h>
 #include <binder/Binder.h>
-#include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 #include <cutils/android_filesystem_config.h>
-#include <gtest/gtest.h>
 #include <gmock/gmock.h>
+#include <gtest/gtest.h>
 
 #include "Access.h"
 #include "ServiceManager.h"
@@ -75,6 +77,11 @@
     return sm;
 }
 
+static bool isCuttlefish() {
+    return android::base::StartsWith(android::base::GetProperty("ro.product.vendor.device", ""),
+                                     "vsoc_");
+}
+
 TEST(AddService, HappyHappy) {
     auto sm = getPermissiveServiceManager();
     EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
@@ -306,6 +313,49 @@
     EXPECT_THAT(out, ElementsAre("sa"));
 }
 
+TEST(Vintf, UpdatableViaApex) {
+    if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+
+    auto sm = getPermissiveServiceManager();
+    std::optional<std::string> updatableViaApex;
+    EXPECT_TRUE(sm->updatableViaApex("android.hardware.camera.provider.ICameraProvider/internal/0",
+                                     &updatableViaApex)
+                        .isOk());
+    EXPECT_EQ(std::make_optional<std::string>("com.google.emulated.camera.provider.hal"),
+              updatableViaApex);
+}
+
+TEST(Vintf, UpdatableViaApex_InvalidNameReturnsNullOpt) {
+    if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+
+    auto sm = getPermissiveServiceManager();
+    std::optional<std::string> updatableViaApex;
+    EXPECT_TRUE(sm->updatableViaApex("android.hardware.camera.provider.ICameraProvider",
+                                     &updatableViaApex)
+                        .isOk()); // missing instance name
+    EXPECT_EQ(std::nullopt, updatableViaApex);
+}
+
+TEST(Vintf, GetUpdatableNames) {
+    if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+
+    auto sm = getPermissiveServiceManager();
+    std::vector<std::string> names;
+    EXPECT_TRUE(sm->getUpdatableNames("com.google.emulated.camera.provider.hal", &names).isOk());
+    EXPECT_EQ(std::vector<
+                      std::string>{"android.hardware.camera.provider.ICameraProvider/internal/0"},
+              names);
+}
+
+TEST(Vintf, GetUpdatableNames_InvalidApexNameReturnsEmpty) {
+    if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+
+    auto sm = getPermissiveServiceManager();
+    std::vector<std::string> names;
+    EXPECT_TRUE(sm->getUpdatableNames("non.existing.apex.name", &names).isOk());
+    EXPECT_EQ(std::vector<std::string>{}, names);
+}
+
 class CallbackHistorian : public BnServiceCallback {
     Status onRegistration(const std::string& name, const sp<IBinder>& binder) override {
         registrations.push_back(name);
diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc
index c9305a1..80af1d1 100644
--- a/cmds/servicemanager/vndservicemanager.rc
+++ b/cmds/servicemanager/vndservicemanager.rc
@@ -2,6 +2,7 @@
     class core
     user system
     group system readproc
+    file /dev/kmsg w
     task_profiles ServiceCapacityLow
     onrestart class_restart main
     onrestart class_restart hal
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 63aa7ff..cd8e63d 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -16,6 +16,28 @@
 
 /**
  * @addtogroup Choreographer
+ *
+ * Choreographer coordinates the timing of frame rendering. This is the C version of the
+ * android.view.Choreographer object in Java.
+ *
+ * As of API level 33, apps can follow proper frame pacing and even choose a future frame to render.
+ * The API is used as follows:
+ * 1. The app posts an {@link AChoreographer_vsyncCallback} to Choreographer to run on the next
+ * frame.
+ * 2. The callback is called when it is the time to start the frame with an {@link
+ * AChoreographerFrameCallbackData} payload: information about multiple possible frame
+ * timelines.
+ * 3. Apps can choose a frame timeline from the {@link
+ * AChoreographerFrameCallbackData} payload, depending on the frame deadline they can meet when
+ * rendering the frame and their desired presentation time, and subsequently
+ * {@link ASurfaceTransaction_setFrameTimeline notify SurfaceFlinger}
+ * of the choice. Alternatively, for apps that do not choose a frame timeline, their frame would be
+ * presented at the earliest possible timeline.
+ *   - The preferred frame timeline is the default frame
+ * timeline that the platform scheduled for the app, based on device configuration.
+ * 4. SurfaceFlinger attempts to follow the chosen frame timeline, by not applying transactions or
+ * latching buffers before the desired presentation time.
+ *
  * @{
  */
 
@@ -47,7 +69,8 @@
 
 struct AChoreographerFrameCallbackData;
 /**
- * Opaque type that provides access to an AChoreographerFrameCallbackData object.
+ * Opaque type that provides access to an AChoreographerFrameCallbackData object, which contains
+ * various methods to extract frame information.
  */
 typedef struct AChoreographerFrameCallbackData AChoreographerFrameCallbackData;
 
@@ -73,8 +96,9 @@
 
 /**
  * Prototype of the function that is called when a new frame is being rendered.
- * It's passed the frame data that should not outlive the callback, as well as the data pointer
- * provided by the application that registered a callback.
+ * It is called with \c callbackData describing multiple frame timelines, as well as the \c data
+ * pointer provided by the application that registered a callback. The \c callbackData does not
+ * outlive the callback.
  */
 typedef void (*AChoreographer_vsyncCallback)(
         const AChoreographerFrameCallbackData* callbackData, void* data);
@@ -110,7 +134,7 @@
         __DEPRECATED_IN(29);
 
 /**
- * Power a callback to be run on the next frame.  The data pointer provided will
+ * Post a callback to be run on the next frame.  The data pointer provided will
  * be passed to the callback function when it's called.
  *
  * Available since API level 29.
@@ -131,8 +155,10 @@
                                                uint32_t delayMillis) __INTRODUCED_IN(29);
 
 /**
- * Posts a callback to run on the next frame. The data pointer provided will
+ * Posts a callback to be run on the next frame. The data pointer provided will
  * be passed to the callback function when it's called.
+ *
+ * Available since API level 33.
  */
 void AChoreographer_postVsyncCallback(AChoreographer* choreographer,
                                         AChoreographer_vsyncCallback callback, void* data)
@@ -189,7 +215,10 @@
         __INTRODUCED_IN(30);
 
 /**
- * The time in nanoseconds when the frame started being rendered.
+ * The time in nanoseconds at which the frame started being rendered.
+ *
+ * Note that this time should \b not be used to advance animation clocks.
+ * Instead, see AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos().
  */
 int64_t AChoreographerFrameCallbackData_getFrameTimeNanos(
         const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
@@ -201,25 +230,38 @@
         const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
 
 /**
- * Get index of the platform-preferred FrameTimeline.
+ * Gets the index of the platform-preferred frame timeline.
+ * The preferred frame timeline is the default
+ * by which the platform scheduled the app, based on the device configuration.
  */
 size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
         const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
 
 /**
- * The vsync ID token used to map Choreographer data.
+ * Gets the token used by the platform to identify the frame timeline at the given \c index.
+ *
+ * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See
+ * AChoreographerFrameCallbackData_getFrameTimelinesLength()
  */
 AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
         const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
 
 /**
- * The time in nanoseconds which the frame at given index is expected to be presented.
+ * Gets the time in nanoseconds at which the frame described at the given \c index is expected to
+ * be presented. This time should be used to advance any animation clocks.
+ *
+ * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See
+ * AChoreographerFrameCallbackData_getFrameTimelinesLength()
  */
 int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(
         const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
 
 /**
- * The time in nanoseconds which the frame at given index needs to be ready by.
+ * Gets the time in nanoseconds at which the frame described at the given \c index needs to be
+ * ready by in order to be presented on time.
+ *
+ * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See
+ * AChoreographerFrameCallbackData_getFrameTimelinesLength()
  */
 int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(
         const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
diff --git a/include/android/sensor.h b/include/android/sensor.h
index eef69f4..ba81bc8 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -596,12 +596,15 @@
     float accuracy;
 } AHeadingEvent;
 
+// LINT.IfChange
 /**
  * Information that describes a sensor event, refer to
  * <a href="/reference/android/hardware/SensorEvent">SensorEvent</a> for additional
  * documentation.
+ *
+ * NOTE: changes to this struct has to be backward compatible and reflected in
+ * sensors_event_t
  */
-/* NOTE: changes to this struct has to be backward compatible */
 typedef struct ASensorEvent {
     int32_t version; /* sizeof(struct ASensorEvent) */
     int32_t sensor;  /** The sensor that generates this event */
@@ -646,6 +649,7 @@
     uint32_t flags;
     int32_t reserved1[3];
 } ASensorEvent;
+// LINT.ThenChange (hardware/libhardware/include/hardware/sensors.h)
 
 struct ASensorManager;
 /**
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 9a36ecb..6223ef7 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -597,20 +597,20 @@
                                                __INTRODUCED_IN(31);
 
 /**
- * Sets the frame timeline to use in Surface Flinger.
+ * Sets the frame timeline to use in SurfaceFlinger.
  *
- * A frame timeline should be chosen based on what frame deadline the application
- * can meet when rendering the frame and the application's desired present time.
- * By setting a frame timeline, Surface Flinger tries to present the frame at the corresponding
- * expected present time.
+ * A frame timeline should be chosen based on the frame deadline the application
+ * can meet when rendering the frame and the application's desired presentation time.
+ * By setting a frame timeline, SurfaceFlinger tries to present the frame at the corresponding
+ * expected presentation time.
  *
  * To receive frame timelines, a callback must be posted to Choreographer using
- * AChoreographer_postExtendedFrameCallback(). The \a vsnycId can then be extracted from the
+ * AChoreographer_postVsyncCallback(). The \c vsyncId can then be extracted from the
  * callback payload using AChoreographerFrameCallbackData_getFrameTimelineVsyncId().
  *
- * \param vsyncId The vsync ID received from AChoreographer, setting the frame's present target to
- * the corresponding expected present time and deadline from the frame to be rendered. A stale or
- * invalid value will be ignored.
+ * \param vsyncId The vsync ID received from AChoreographer, setting the frame's presentation target
+ * to the corresponding expected presentation time and deadline from the frame to be rendered. A
+ * stale or invalid value will be ignored.
  */
 void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* transaction,
                                           AVsyncId vsyncId) __INTRODUCED_IN(33);
diff --git a/include/input/Input.h b/include/input/Input.h
index e7d68fc..7ea2970 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -297,6 +297,8 @@
  */
 const char* motionClassificationToString(MotionClassification classification);
 
+const char* motionToolTypeToString(int32_t toolType);
+
 /**
  * Portion of FrameMetrics timeline of interest to input code.
  */
diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h
index 0a75278..55f730b 100644
--- a/include/input/PrintTools.h
+++ b/include/input/PrintTools.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <map>
+#include <optional>
 #include <set>
 #include <string>
 
@@ -28,6 +29,15 @@
 }
 
 /**
+ * Convert an optional type to string.
+ */
+template <typename T>
+std::string toString(const std::optional<T>& optional,
+                     std::string (*toString)(const T&) = constToString) {
+    return optional ? toString(*optional) : "<not set>";
+}
+
+/**
  * Convert a set of integral types to string.
  */
 template <typename T>
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 76e3e66..5e539f2 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -49,6 +49,9 @@
         "com.android.media",
         "com.android.media.swcodec",
     ],
+    llndk: {
+        llndk_headers: true,
+    },
 }
 
 cc_library_static {
diff --git a/libs/arect/include/android/rect.h b/libs/arect/include/android/rect.h
index b36728e..d52861a 100644
--- a/libs/arect/include/android/rect.h
+++ b/libs/arect/include/android/rect.h
@@ -57,7 +57,7 @@
 } ARect;
 
 #ifdef __cplusplus
-};
+}
 #endif
 
 #endif // ANDROID_RECT_H
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index df965ab..28369d6 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -161,7 +161,7 @@
     ],
 
     header_libs: [
-        "libandroid_runtime_vm_headers",
+        "jni_headers",
     ],
 
     export_header_lib_headers: [
@@ -315,7 +315,7 @@
         },
         recovery: {
             exclude_header_libs: [
-                "libandroid_runtime_vm_headers",
+                "jni_headers",
             ],
         },
     },
@@ -490,9 +490,6 @@
         java: {
             enabled: false,
         },
-        cpp: {
-            gen_trace: false,
-        },
     },
 }
 
@@ -504,6 +501,7 @@
         "libbase",
         "libbinder",
         "libbinder_ndk",
+        "libcutils_sockets",
         "liblog",
         "libutils",
     ],
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 54d2445..1c470a1 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -47,6 +47,8 @@
 binder_proxy_limit_callback BpBinder::sLimitCallback;
 bool BpBinder::sBinderProxyThrottleCreate = false;
 
+static StaticString16 kDescriptorUninit(u"<uninit descriptor>");
+
 // Arbitrarily high value that probably distinguishes a bad behaving app
 uint32_t BpBinder::sBinderProxyCountHighWatermark = 2500;
 // Another arbitrary value a binder count needs to drop below before another callback will be called
@@ -211,6 +213,7 @@
         mAlive(true),
         mObitsSent(false),
         mObituaries(nullptr),
+        mDescriptorCache(kDescriptorUninit),
         mTrackedUid(-1) {
     extendObjectLifetime(OBJECT_LIFETIME_WEAK);
 }
@@ -258,12 +261,12 @@
 
 bool BpBinder::isDescriptorCached() const {
     Mutex::Autolock _l(mLock);
-    return mDescriptorCache.size() ? true : false;
+    return mDescriptorCache.string() != kDescriptorUninit.string();
 }
 
 const String16& BpBinder::getInterfaceDescriptor() const
 {
-    if (isDescriptorCached() == false) {
+    if (!isDescriptorCached()) {
         sp<BpBinder> thiz = sp<BpBinder>::fromExisting(const_cast<BpBinder*>(this));
 
         Parcel data;
@@ -276,8 +279,7 @@
             Mutex::Autolock _l(mLock);
             // mDescriptorCache could have been assigned while the lock was
             // released.
-            if (mDescriptorCache.size() == 0)
-                mDescriptorCache = res;
+            if (mDescriptorCache.string() == kDescriptorUninit.string()) mDescriptorCache = res;
         }
     }
 
@@ -369,10 +371,7 @@
         if (data.dataSize() > LOG_TRANSACTIONS_OVER_SIZE) {
             Mutex::Autolock _l(mLock);
             ALOGW("Large outgoing transaction of %zu bytes, interface descriptor %s, code %d",
-                  data.dataSize(),
-                  mDescriptorCache.size() ? String8(mDescriptorCache).c_str()
-                                          : "<uncached descriptor>",
-                  code);
+                  data.dataSize(), String8(mDescriptorCache).c_str(), code);
         }
 
         if (status == DEAD_OBJECT) mAlive = 0;
@@ -647,7 +646,7 @@
     if(obits != nullptr) {
         if (!obits->isEmpty()) {
             ALOGI("onLastStrongRef automatically unlinking death recipients: %s",
-                  mDescriptorCache.size() ? String8(mDescriptorCache).c_str() : "<uncached descriptor>");
+                  String8(mDescriptorCache).c_str());
         }
 
         if (ipc) ipc->clearDeathNotification(binderHandle(), this);
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 11c8e5d..6d64e1e 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -45,11 +45,11 @@
 
 #define IF_LOG_TRANSACTIONS() if (false)
 #define IF_LOG_COMMANDS() if (false)
-#define LOG_REMOTEREFS(...) 
+#define LOG_REMOTEREFS(...)
 #define IF_LOG_REMOTEREFS() if (false)
 
-#define LOG_THREADPOOL(...) 
-#define LOG_ONEWAY(...) 
+#define LOG_THREADPOOL(...)
+#define LOG_ONEWAY(...)
 
 #else
 
@@ -132,12 +132,21 @@
     } else {
         out << "\ttarget.ptr=" << btd->target.ptr;
     }
-    out << "\t (cookie " << btd->cookie << ")"
-        << "\n"
+    out << "\t (cookie " << btd->cookie << ")\n"
         << "\tcode=" << TypeCode(btd->code) << ", flags=" << (void*)(uint64_t)btd->flags << "\n"
-        << "\tdata=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size << " bytes)"
-        << "\n"
-        << "\toffsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size << " bytes)";
+        << "\tdata=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size << " bytes)\n"
+        << "\toffsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size << " bytes)\n";
+    return btd + 1;
+}
+
+static const void* printBinderTransactionDataSecCtx(std::ostream& out, const void* data) {
+    const binder_transaction_data_secctx* btd = (const binder_transaction_data_secctx*)data;
+
+    printBinderTransactionData(out, &btd->transaction_data);
+
+    char* secctx = (char*)btd->secctx;
+    out << "\tsecctx=" << secctx << "\n";
+
     return btd+1;
 }
 
@@ -156,6 +165,11 @@
     out << "\t" << kReturnStrings[cmdIndex];
 
     switch (code) {
+        case BR_TRANSACTION_SEC_CTX: {
+            out << ": ";
+            cmd = (const int32_t*)printBinderTransactionDataSecCtx(out, cmd);
+        } break;
+
         case BR_TRANSACTION:
         case BR_REPLY: {
             out << ": ";
@@ -394,14 +408,92 @@
     // context, so we don't abort
 }
 
+constexpr uint32_t encodeExplicitIdentity(bool hasExplicitIdentity, pid_t callingPid) {
+    uint32_t as_unsigned = static_cast<uint32_t>(callingPid);
+    if (hasExplicitIdentity) {
+        return as_unsigned | (1 << 30);
+    } else {
+        return as_unsigned & ~(1 << 30);
+    }
+}
+
+constexpr int64_t packCallingIdentity(bool hasExplicitIdentity, uid_t callingUid,
+                                      pid_t callingPid) {
+    // Calling PID is a 32-bit signed integer, but doesn't consume the entire 32 bit space.
+    // To future-proof this and because we have extra capacity, we decided to also support -1,
+    // since this constant is used to represent invalid UID in other places of the system.
+    // Thus, we pack hasExplicitIdentity into the 2nd bit from the left.  This allows us to
+    // preserve the (left-most) bit for the sign while also encoding the value of
+    // hasExplicitIdentity.
+    //               32b     |        1b         |         1b            |        30b
+    // token = [ calling uid | calling pid(sign) | has explicit identity | calling pid(rest) ]
+    uint64_t token = (static_cast<uint64_t>(callingUid) << 32) |
+            encodeExplicitIdentity(hasExplicitIdentity, callingPid);
+    return static_cast<int64_t>(token);
+}
+
+constexpr bool unpackHasExplicitIdentity(int64_t token) {
+    return static_cast<int32_t>(token) & (1 << 30);
+}
+
+constexpr uid_t unpackCallingUid(int64_t token) {
+    return static_cast<uid_t>(token >> 32);
+}
+
+constexpr pid_t unpackCallingPid(int64_t token) {
+    int32_t encodedPid = static_cast<int32_t>(token);
+    if (encodedPid & (1 << 31)) {
+        return encodedPid | (1 << 30);
+    } else {
+        return encodedPid & ~(1 << 30);
+    }
+}
+
+static_assert(unpackHasExplicitIdentity(packCallingIdentity(true, 1000, 9999)) == true,
+              "pack true hasExplicit");
+
+static_assert(unpackCallingUid(packCallingIdentity(true, 1000, 9999)) == 1000, "pack true uid");
+
+static_assert(unpackCallingPid(packCallingIdentity(true, 1000, 9999)) == 9999, "pack true pid");
+
+static_assert(unpackHasExplicitIdentity(packCallingIdentity(false, 1000, 9999)) == false,
+              "pack false hasExplicit");
+
+static_assert(unpackCallingUid(packCallingIdentity(false, 1000, 9999)) == 1000, "pack false uid");
+
+static_assert(unpackCallingPid(packCallingIdentity(false, 1000, 9999)) == 9999, "pack false pid");
+
+static_assert(unpackHasExplicitIdentity(packCallingIdentity(true, 1000, -1)) == true,
+              "pack true (negative) hasExplicit");
+
+static_assert(unpackCallingUid(packCallingIdentity(true, 1000, -1)) == 1000,
+              "pack true (negative) uid");
+
+static_assert(unpackCallingPid(packCallingIdentity(true, 1000, -1)) == -1,
+              "pack true (negative) pid");
+
+static_assert(unpackHasExplicitIdentity(packCallingIdentity(false, 1000, -1)) == false,
+              "pack false (negative) hasExplicit");
+
+static_assert(unpackCallingUid(packCallingIdentity(false, 1000, -1)) == 1000,
+              "pack false (negative) uid");
+
+static_assert(unpackCallingPid(packCallingIdentity(false, 1000, -1)) == -1,
+              "pack false (negative) pid");
+
 int64_t IPCThreadState::clearCallingIdentity()
 {
     // ignore mCallingSid for legacy reasons
-    int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
+    int64_t token = packCallingIdentity(mHasExplicitIdentity, mCallingUid, mCallingPid);
     clearCaller();
+    mHasExplicitIdentity = true;
     return token;
 }
 
+bool IPCThreadState::hasExplicitIdentity() {
+    return mHasExplicitIdentity;
+}
+
 void IPCThreadState::setStrictModePolicy(int32_t policy)
 {
     mStrictModePolicy = policy;
@@ -474,9 +566,10 @@
 
 void IPCThreadState::restoreCallingIdentity(int64_t token)
 {
-    mCallingUid = (int)(token>>32);
+    mCallingUid = unpackCallingUid(token);
     mCallingSid = nullptr;  // not enough data to restore
-    mCallingPid = (int)token;
+    mCallingPid = unpackCallingPid(token);
+    mHasExplicitIdentity = unpackHasExplicitIdentity(token);
 }
 
 void IPCThreadState::clearCaller()
@@ -889,6 +982,7 @@
         mCallRestriction(mProcess->mCallRestriction) {
     pthread_setspecific(gTLS, this);
     clearCaller();
+    mHasExplicitIdentity = false;
     mIn.setDataCapacity(256);
     mOut.setDataCapacity(256);
 }
@@ -937,6 +1031,10 @@
             if (!reply && !acquireResult) goto finish;
             break;
 
+        case BR_TRANSACTION_PENDING_FROZEN:
+            ALOGW("Sending oneway calls to frozen process.");
+            goto finish;
+
         case BR_DEAD_REPLY:
             err = DEAD_OBJECT;
             goto finish;
@@ -1279,6 +1377,7 @@
             const pid_t origPid = mCallingPid;
             const char* origSid = mCallingSid;
             const uid_t origUid = mCallingUid;
+            const bool origHasExplicitIdentity = mHasExplicitIdentity;
             const int32_t origStrictModePolicy = mStrictModePolicy;
             const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
             const int32_t origWorkSource = mWorkSource;
@@ -1292,6 +1391,7 @@
             mCallingPid = tr.sender_pid;
             mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx);
             mCallingUid = tr.sender_euid;
+            mHasExplicitIdentity = false;
             mLastTransactionBinderFlags = tr.flags;
 
             // ALOGI(">>>> TRANSACT from pid %d sid %s uid %d\n", mCallingPid,
@@ -1367,6 +1467,7 @@
             mCallingPid = origPid;
             mCallingSid = origSid;
             mCallingUid = origUid;
+            mHasExplicitIdentity = origHasExplicitIdentity;
             mStrictModePolicy = origStrictModePolicy;
             mLastTransactionBinderFlags = origTransactionBinderFlags;
             mWorkSource = origWorkSource;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 05db774..2408307 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -81,6 +81,7 @@
     bool isDeclared(const String16& name) override;
     Vector<String16> getDeclaredInstances(const String16& interface) override;
     std::optional<String16> updatableViaApex(const String16& name) override;
+    Vector<String16> getUpdatableNames(const String16& apexName) override;
     std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override;
     class RegistrationWaiter : public android::os::BnServiceCallback {
     public:
@@ -443,7 +444,7 @@
     bool declared;
     if (Status status = mTheRealServiceManager->isDeclared(String8(name).c_str(), &declared);
         !status.isOk()) {
-        ALOGW("Failed to get isDeclard for %s: %s", String8(name).c_str(),
+        ALOGW("Failed to get isDeclared for %s: %s", String8(name).c_str(),
               status.toString8().c_str());
         return false;
     }
@@ -479,6 +480,23 @@
     return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt;
 }
 
+Vector<String16> ServiceManagerShim::getUpdatableNames(const String16& apexName) {
+    std::vector<std::string> out;
+    if (Status status = mTheRealServiceManager->getUpdatableNames(String8(apexName).c_str(), &out);
+        !status.isOk()) {
+        ALOGW("Failed to getUpdatableNames for %s: %s", String8(apexName).c_str(),
+              status.toString8().c_str());
+        return {};
+    }
+
+    Vector<String16> res;
+    res.setCapacity(out.size());
+    for (const std::string& instance : out) {
+        res.push(String16(instance.c_str()));
+    }
+    return res;
+}
+
 std::optional<IServiceManager::ConnectionInfo> ServiceManagerShim::getConnectionInfo(
         const String16& name) {
     std::optional<os::ConnectionInfo> connectionInfo;
diff --git a/libs/binder/OS.cpp b/libs/binder/OS.cpp
index 77e401f..ce60e33 100644
--- a/libs/binder/OS.cpp
+++ b/libs/binder/OS.cpp
@@ -67,7 +67,7 @@
     return RpcTransportCtxFactoryRaw::make();
 }
 
-int sendMessageOnSocket(
+ssize_t sendMessageOnSocket(
         const RpcTransportFd& socket, iovec* iovs, int niovs,
         const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
     if (ancillaryFds != nullptr && !ancillaryFds->empty()) {
@@ -112,7 +112,7 @@
     return TEMP_FAILURE_RETRY(sendmsg(socket.fd.get(), &msg, MSG_NOSIGNAL));
 }
 
-int receiveMessageFromSocket(
+ssize_t receiveMessageFromSocket(
         const RpcTransportFd& socket, iovec* iovs, int niovs,
         std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
     if (ancillaryFds != nullptr) {
diff --git a/libs/binder/OS.h b/libs/binder/OS.h
index 0d38968..fecae31 100644
--- a/libs/binder/OS.h
+++ b/libs/binder/OS.h
@@ -33,11 +33,11 @@
 
 std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory();
 
-int sendMessageOnSocket(
+ssize_t sendMessageOnSocket(
         const RpcTransportFd& socket, iovec* iovs, int niovs,
         const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds);
 
-int receiveMessageFromSocket(
+ssize_t receiveMessageFromSocket(
         const RpcTransportFd& socket, iovec* iovs, int niovs,
         std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds);
 
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 07d0a65..44ff62b 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -614,11 +614,14 @@
                 if (status_t status = readInt32(&fdIndex); status != OK) {
                     return status;
                 }
-                const auto& oldFd = otherRpcFields->mFds->at(fdIndex);
+                int oldFd = toRawFd(otherRpcFields->mFds->at(fdIndex));
                 // To match kernel binder behavior, we always dup, even if the
                 // FD was unowned in the source parcel.
-                rpcFields->mFds->emplace_back(
-                        base::unique_fd(fcntl(toRawFd(oldFd), F_DUPFD_CLOEXEC, 0)));
+                int newFd = -1;
+                if (status_t status = dupFileDescriptor(oldFd, &newFd); status != OK) {
+                    ALOGW("Failed to duplicate file descriptor %d: %s", oldFd, strerror(-status));
+                }
+                rpcFields->mFds->emplace_back(base::unique_fd(newFd));
                 // Fixup the index in the data.
                 mDataPos = newDataPos + 4;
                 if (status_t status = writeInt32(rpcFields->mFds->size() - 1); status != OK) {
@@ -966,7 +969,15 @@
     }
 }
 
+void Parcel::setEnforceNoDataAvail(bool enforceNoDataAvail) {
+    mEnforceNoDataAvail = enforceNoDataAvail;
+}
+
 binder::Status Parcel::enforceNoDataAvail() const {
+    if (!mEnforceNoDataAvail) {
+        return binder::Status::ok();
+    }
+
     const auto n = dataAvail();
     if (n == 0) {
         return binder::Status::ok();
@@ -1464,7 +1475,7 @@
 #ifdef BINDER_WITH_KERNEL_IPC
     flat_binder_object obj;
     obj.hdr.type = BINDER_TYPE_FD;
-    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+    obj.flags = 0;
     obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
     obj.handle = fd;
     obj.cookie = takeOwnership ? 1 : 0;
@@ -3077,6 +3088,7 @@
     mAllowFds = true;
     mDeallocZero = false;
     mOwner = nullptr;
+    mEnforceNoDataAvail = true;
 }
 
 void Parcel::scanForFds() const {
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 1f311ac..254dda8 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -439,6 +439,10 @@
     return mCurrentThreads;
 }
 
+bool ProcessState::isThreadPoolStarted() const {
+    return mThreadPoolStarted;
+}
+
 #define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
 bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) {
     static const char* const names[] = {
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 83d0de7..0d06e9e 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -50,7 +50,8 @@
 
 RpcServer::RpcServer(std::unique_ptr<RpcTransportCtx> ctx) : mCtx(std::move(ctx)) {}
 RpcServer::~RpcServer() {
-    (void)shutdown();
+    RpcMutexUniqueLock _l(mLock);
+    LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Must call shutdown() before destructor");
 }
 
 sp<RpcServer> RpcServer::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
@@ -70,11 +71,8 @@
     return setupSocketServer(UnixSocketAddress(path));
 }
 
-status_t RpcServer::setupVsockServer(unsigned int port) {
-    // realizing value w/ this type at compile time to avoid ubsan abort
-    constexpr unsigned int kAnyCid = VMADDR_CID_ANY;
-
-    return setupSocketServer(VsockSocketAddress(kAnyCid, port));
+status_t RpcServer::setupVsockServer(unsigned int bindCid, unsigned int port) {
+    return setupSocketServer(VsockSocketAddress(bindCid, port));
 }
 
 status_t RpcServer::setupInetServer(const char* address, unsigned int port,
@@ -157,6 +155,12 @@
     mRootObjectFactory = std::move(makeObject);
 }
 
+void RpcServer::setConnectionFilter(std::function<bool(const void*, size_t)>&& filter) {
+    RpcMutexLockGuard _l(mLock);
+    LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Already joined");
+    mConnectionFilter = std::move(filter);
+}
+
 sp<IBinder> RpcServer::getRootObject() {
     RpcMutexLockGuard _l(mLock);
     bool hasWeak = mRootObjectWeak.unsafe_get();
@@ -200,11 +204,15 @@
     iovec iov{&zero, sizeof(zero)};
     std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds;
 
-    if (receiveMessageFromSocket(server.mServer, &iov, 1, &fds) < 0) {
+    ssize_t num_bytes = receiveMessageFromSocket(server.mServer, &iov, 1, &fds);
+    if (num_bytes < 0) {
         int savedErrno = errno;
         ALOGE("Failed recvmsg: %s", strerror(savedErrno));
         return -savedErrno;
     }
+    if (num_bytes == 0) {
+        return DEAD_OBJECT;
+    }
     if (fds.size() != 1) {
         ALOGE("Expected exactly one fd from recvmsg, got %zu", fds.size());
         return -EINVAL;
@@ -239,16 +247,25 @@
         socklen_t addrLen = addr.size();
 
         RpcTransportFd clientSocket;
-        if (mAcceptFn(*this, &clientSocket) != OK) {
-            continue;
+        if ((status = mAcceptFn(*this, &clientSocket)) != OK) {
+            if (status == DEAD_OBJECT)
+                break;
+            else
+                continue;
         }
+
+        LOG_RPC_DETAIL("accept on fd %d yields fd %d", mServer.fd.get(), clientSocket.fd.get());
+
         if (getpeername(clientSocket.fd.get(), reinterpret_cast<sockaddr*>(addr.data()),
                         &addrLen)) {
             ALOGE("Could not getpeername socket: %s", strerror(errno));
             continue;
         }
 
-        LOG_RPC_DETAIL("accept on fd %d yields fd %d", mServer.fd.get(), clientSocket.fd.get());
+        if (mConnectionFilter != nullptr && !mConnectionFilter(addr.data(), addrLen)) {
+            ALOGE("Dropped client connection fd %d", clientSocket.fd.get());
+            continue;
+        }
 
         {
             RpcMutexLockGuard _l(mLock);
@@ -531,33 +548,35 @@
     LOG_RPC_DETAIL("Setting up socket server %s", addr.toString().c_str());
     LOG_ALWAYS_FATAL_IF(hasServer(), "Each RpcServer can only have one server.");
 
-    RpcTransportFd transportFd(unique_fd(TEMP_FAILURE_RETRY(
-            socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0))));
-    if (!transportFd.fd.ok()) {
+    unique_fd socket_fd(TEMP_FAILURE_RETRY(
+            socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
+    if (!socket_fd.ok()) {
         int savedErrno = errno;
         ALOGE("Could not create socket: %s", strerror(savedErrno));
         return -savedErrno;
     }
-
-    if (0 != TEMP_FAILURE_RETRY(bind(transportFd.fd.get(), addr.addr(), addr.addrSize()))) {
+    if (0 != TEMP_FAILURE_RETRY(bind(socket_fd.get(), addr.addr(), addr.addrSize()))) {
         int savedErrno = errno;
         ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
         return -savedErrno;
     }
 
+    return setupRawSocketServer(std::move(socket_fd));
+}
+
+status_t RpcServer::setupRawSocketServer(unique_fd socket_fd) {
+    LOG_ALWAYS_FATAL_IF(!socket_fd.ok(), "Socket must be setup to listen.");
+
     // Right now, we create all threads at once, making accept4 slow. To avoid hanging the client,
     // the backlog is increased to a large number.
     // TODO(b/189955605): Once we create threads dynamically & lazily, the backlog can be reduced
     //  to 1.
-    if (0 != TEMP_FAILURE_RETRY(listen(transportFd.fd.get(), 50 /*backlog*/))) {
+    if (0 != TEMP_FAILURE_RETRY(listen(socket_fd.get(), 50 /*backlog*/))) {
         int savedErrno = errno;
-        ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+        ALOGE("Could not listen initialized Unix socket: %s", strerror(savedErrno));
         return -savedErrno;
     }
-
-    LOG_RPC_DETAIL("Successfully setup socket server %s", addr.toString().c_str());
-
-    if (status_t status = setupExternalServer(std::move(transportFd.fd)); status != OK) {
+    if (status_t status = setupExternalServer(std::move(socket_fd)); status != OK) {
         ALOGE("Another thread has set up server while calling setupSocketServer. Race?");
         return status;
     }
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 7d6bcfc..ce6ef2b 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -46,8 +46,8 @@
 #include "Utils.h"
 
 #if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
-#include <android_runtime/vm.h>
 #include <jni.h>
+extern "C" JavaVM* AndroidRuntimeGetJavaVM();
 #endif
 
 namespace android {
@@ -408,10 +408,11 @@
                             "Unable to detach thread. No JavaVM, but it was present before!");
 
         LOG_RPC_DETAIL("Detaching current thread from JVM");
-        if (vm->DetachCurrentThread() != JNI_OK) {
+        int ret = vm->DetachCurrentThread();
+        if (ret == JNI_OK) {
             mAttached = false;
         } else {
-            ALOGW("Unable to detach current thread from JVM");
+            ALOGW("Unable to detach current thread from JVM (%d)", ret);
         }
     }
 
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 1912d14..cd067bf 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -61,7 +61,8 @@
             override {
         bool sentFds = false;
         auto send = [&](iovec* iovs, int niovs) -> ssize_t {
-            int ret = sendMessageOnSocket(mSocket, iovs, niovs, sentFds ? nullptr : ancillaryFds);
+            ssize_t ret =
+                    sendMessageOnSocket(mSocket, iovs, niovs, sentFds ? nullptr : ancillaryFds);
             sentFds |= ret > 0;
             return ret;
         };
diff --git a/libs/binder/RpcTransportTipcAndroid.cpp b/libs/binder/RpcTransportTipcAndroid.cpp
index 453279c..8b3ddfb 100644
--- a/libs/binder/RpcTransportTipcAndroid.cpp
+++ b/libs/binder/RpcTransportTipcAndroid.cpp
@@ -63,12 +63,14 @@
         if (pfd.revents & POLLERR) {
             return DEAD_OBJECT;
         }
+        if (pfd.revents & POLLIN) {
+            // Copied from FdTrigger.cpp: Even though POLLHUP may also be set,
+            // treat it as a success condition to ensure data is drained.
+            return OK;
+        }
         if (pfd.revents & POLLHUP) {
             return DEAD_OBJECT;
         }
-        if (pfd.revents & POLLIN) {
-            return OK;
-        }
 
         return WOULD_BLOCK;
     }
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 5880c0a..0fb1615 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -114,6 +114,12 @@
     @nullable @utf8InCpp String updatableViaApex(@utf8InCpp String name);
 
     /**
+     * Returns all instances which are updatable via the APEX. Instance names are fully qualified
+     * like `pack.age.IFoo/default`.
+     */
+    @utf8InCpp String[] getUpdatableNames(@utf8InCpp String apexName);
+
+    /**
      * If connection info is available for the given instance, returns the ConnectionInfo
      */
     @nullable ConnectionInfo getConnectionInfo(@utf8InCpp String name);
diff --git a/libs/binder/binder_module.h b/libs/binder/binder_module.h
index 793795e..eef07ae 100644
--- a/libs/binder/binder_module.h
+++ b/libs/binder/binder_module.h
@@ -100,4 +100,9 @@
 #define BINDER_ENABLE_ONEWAY_SPAM_DETECTION _IOW('b', 16, __u32)
 #endif // BINDER_ENABLE_ONEWAY_SPAM_DETECTION
 
+#ifndef BR_TRANSACTION_PENDING_FROZEN
+// Temporary definition of BR_TRANSACTION_PENDING_FROZEN until UAPI binder.h includes it.
+#define BR_TRANSACTION_PENDING_FROZEN _IO('r', 20)
+#endif // BR_TRANSACTION_PENDING_FROZEN
+
 #endif // _BINDER_MODULE_H_
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index c01e92f..d261c21 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -139,12 +139,15 @@
             int64_t             clearCallingIdentity();
             // Restores PID/UID (not SID)
             void                restoreCallingIdentity(int64_t token);
+            bool hasExplicitIdentity();
 
+            // For main functions - dangerous for libraries to use
             status_t            setupPolling(int* fd);
             status_t            handlePolledCommands();
             void                flushCommands();
             bool                flushIfNeeded();
 
+            // For main functions - dangerous for libraries to use
             void                joinThreadPool(bool isMain = true);
             
             // Stop the local process.
@@ -241,6 +244,7 @@
             bool                mPropagateWorkSource;
             bool                mIsLooper;
             bool mIsFlushing;
+            bool mHasExplicitIdentity;
             int32_t             mStrictModePolicy;
             int32_t             mLastTransactionBinderFlags;
             CallRestriction     mCallRestriction;
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 413c97f..2af512e 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -67,7 +67,8 @@
      * a system property, or in the case of services in the VINTF manifest, it can be checked
      * with isDeclared).
      */
-    virtual sp<IBinder>         getService( const String16& name) const = 0;
+    [[deprecated("this polls for 5s, prefer waitForService or checkService")]]
+    virtual sp<IBinder> getService(const String16& name) const = 0;
 
     /**
      * Retrieve an existing service, non-blocking.
@@ -115,6 +116,12 @@
     virtual std::optional<String16> updatableViaApex(const String16& name) = 0;
 
     /**
+     * Returns all instances which are updatable via the APEX. Instance names are fully qualified
+     * like `pack.age.IFoo/default`.
+     */
+    virtual Vector<String16> getUpdatableNames(const String16& apexName) = 0;
+
+    /**
      * If this instance has declared remote connection information, returns
      * the ConnectionInfo.
      */
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 6de6ce8..f730acb 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -150,6 +150,9 @@
     // Returns Status(EX_BAD_PARCELABLE) when the Parcel is not consumed.
     binder::Status enforceNoDataAvail() const;
 
+    // This Api is used by fuzzers to skip dataAvail checks.
+    void setEnforceNoDataAvail(bool enforceNoDataAvail);
+
     void                freeData();
 
     size_t              objectsCount() const;
@@ -1329,6 +1332,9 @@
     // data to be overridden with zero when deallocated
     mutable bool        mDeallocZero;
 
+    // Set this to false to skip dataAvail checks.
+    bool mEnforceNoDataAvail;
+
     release_func        mOwner;
 
     size_t mReserved;
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 9679a5f..bad8cb1 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -50,6 +50,7 @@
 
     sp<IBinder> getContextObject(const sp<IBinder>& caller);
 
+    // For main functions - dangerous for libraries to use
     void startThreadPool();
 
     bool becomeContextManager();
@@ -57,8 +58,10 @@
     sp<IBinder> getStrongProxyForHandle(int32_t handle);
     void expungeHandle(int32_t handle, IBinder* binder);
 
+    // TODO: deprecate.
     void spawnPooledThread(bool isMain);
 
+    // For main functions - dangerous for libraries to use
     status_t setThreadPoolMaxThreadCount(size_t maxThreads);
     status_t enableOnewaySpamDetection(bool enable);
     void giveThreadPoolName();
@@ -94,6 +97,11 @@
      */
     size_t getThreadPoolMaxTotalThreadCount() const;
 
+    /**
+     * Check to see if the thread pool has started.
+     */
+    bool isThreadPoolStarted() const;
+
     enum class DriverFeature {
         ONEWAY_SPAM_DETECTION,
         EXTENDED_ERROR,
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 81ae26a3..25193a3 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -71,9 +71,19 @@
     [[nodiscard]] status_t setupUnixDomainServer(const char* path);
 
     /**
-     * Creates an RPC server at the current port.
+     * Sets up an RPC server with a raw socket file descriptor.
+     * The socket should be created and bound to a socket address already, e.g.
+     * the socket can be created in init.rc.
+     *
+     * This method is used in the libbinder_rpc_unstable API
+     * RunInitUnixDomainRpcServer().
      */
-    [[nodiscard]] status_t setupVsockServer(unsigned int port);
+    [[nodiscard]] status_t setupRawSocketServer(base::unique_fd socket_fd);
+
+    /**
+     * Creates an RPC server binding to the given CID at the given port.
+     */
+    [[nodiscard]] status_t setupVsockServer(unsigned int bindCid, unsigned int port);
 
     /**
      * Creates an RPC server at the current port using IPv4.
@@ -161,6 +171,16 @@
     sp<IBinder> getRootObject();
 
     /**
+     * Set optional filter of incoming connections based on the peer's address.
+     *
+     * Takes one argument: a callable that is invoked on each accept()-ed
+     * connection and returns false if the connection should be dropped.
+     * See the description of setPerSessionRootObject() for details about
+     * the callable's arguments.
+     */
+    void setConnectionFilter(std::function<bool(const void*, size_t)>&& filter);
+
+    /**
      * See RpcTransportCtx::getCertificate
      */
     std::vector<uint8_t> getCertificate(RpcCertificateFormat);
@@ -243,6 +263,7 @@
     sp<IBinder> mRootObject;
     wp<IBinder> mRootObjectWeak;
     std::function<sp<IBinder>(const void*, size_t)> mRootObjectFactory;
+    std::function<bool(const void*, size_t)> mConnectionFilter;
     std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions;
     std::unique_ptr<FdTrigger> mShutdownTrigger;
     RpcConditionVariable mShutdownCv;
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index 5baa4d7..3ebbed6 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -17,38 +17,108 @@
 #pragma once
 
 #include <sys/socket.h>
+#include <stdint.h>
 
 extern "C" {
 
 struct AIBinder;
+struct ARpcServer;
+struct ARpcSession;
+
+enum class ARpcSession_FileDescriptorTransportMode {
+    None,
+    Unix,
+    Trusty,
+};
 
 // Starts an RPC server on a given port and a given root IBinder object.
-// This function sets up the server and joins before returning.
-bool RunRpcServer(AIBinder* service, unsigned int port);
+// The server will only accept connections from the given CID.
+// Set `cid` to VMADDR_CID_ANY to accept connections from any client.
+// Set `cid` to VMADDR_CID_LOCAL to only bind to the local vsock interface.
+// Returns an opaque handle to the running server instance, or null if the server
+// could not be started.
+[[nodiscard]] ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid,
+                                              unsigned int port);
 
-// Starts an RPC server on a given port and a given root IBinder object.
-// This function sets up the server, calls readyCallback with a given param, and
-// then joins before returning.
-bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
-                          void* param);
+// Starts a Unix domain RPC server with a given init-managed Unix domain `name`
+// and a given root IBinder object.
+// The socket should be created in init.rc with the same `name`.
+// Returns an opaque handle to the running server instance, or null if the server
+// could not be started.
+[[nodiscard]] ARpcServer* ARpcServer_newInitUnixDomain(AIBinder* service, const char* name);
 
-// Starts an RPC server on a given port and a given root IBinder factory.
-// RunRpcServerWithFactory acts like RunRpcServerCallback, but instead of
-// assigning single root IBinder object to all connections, factory is called
-// whenever a client connects, making it possible to assign unique IBinder
-// object to each client.
-bool RunRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
-                          void* factoryContext, unsigned int port);
+// Starts an RPC server that bootstraps sessions using an existing Unix domain
+// socket pair, with a given root IBinder object.
+// Callers should create a pair of SOCK_STREAM Unix domain sockets, pass one to
+// this function and the other to UnixDomainBootstrapClient(). Multiple client
+// session can be created from the client end of the pair.
+// Does not take ownership of `service`.
+// Returns an opaque handle to the running server instance, or null if the server
+// could not be started.
+[[nodiscard]] ARpcServer* ARpcServer_newUnixDomainBootstrap(AIBinder* service, int bootstrapFd);
 
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
+// Sets the list of supported file descriptor transport modes of this RPC server.
+void ARpcServer_setSupportedFileDescriptorTransportModes(
+        ARpcServer* handle,
+        const ARpcSession_FileDescriptorTransportMode modes[],
+        size_t modes_len);
 
-// Connect to an RPC server with preconnected file descriptors.
+// Runs ARpcServer_join() in a background thread. Immediately returns.
+void ARpcServer_start(ARpcServer* server);
+
+// Joins the thread of a running RpcServer instance. At any given point, there
+// can only be one thread calling ARpcServer_join().
+// If a client needs to actively terminate join, call ARpcServer_shutdown() in
+// a separate thread.
+void ARpcServer_join(ARpcServer* server);
+
+// Shuts down any running ARpcServer_join().
+[[nodiscard]] bool ARpcServer_shutdown(ARpcServer* server);
+
+// Frees the ARpcServer handle and drops the reference count on the underlying
+// RpcServer instance. The handle must not be reused afterwards.
+// This automatically calls ARpcServer_shutdown().
+void ARpcServer_free(ARpcServer* server);
+
+// Allocates a new RpcSession object and returns an opaque handle to it.
+[[nodiscard]] ARpcSession* ARpcSession_new();
+
+// Connects to an RPC server over vsock at a given CID on a given port.
+// Returns the root Binder object of the server.
+AIBinder* ARpcSession_setupVsockClient(ARpcSession* session, unsigned int cid,
+                                       unsigned int port);
+
+// Connects to an RPC server over a Unix Domain Socket of the given name.
+// The final Unix Domain Socket path name is /dev/socket/`name`.
+// Returns the root Binder object of the server.
+AIBinder* ARpcSession_setupUnixDomainClient(ARpcSession* session, const char* name);
+
+// Connects to an RPC server over the given bootstrap Unix domain socket.
+// Does NOT take ownership of `bootstrapFd`.
+AIBinder* ARpcSession_setupUnixDomainBootstrapClient(ARpcSession* session,
+                                                     int bootstrapFd);
+
+// Connects to an RPC server with preconnected file descriptors.
 //
 // requestFd should connect to the server and return a valid file descriptor, or
 // -1 if connection fails.
 //
 // param will be passed to requestFd. Callers can use param to pass contexts to
 // the requestFd function.
-AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param);
+AIBinder* ARpcSession_setupPreconnectedClient(ARpcSession* session,
+                                              int (*requestFd)(void* param),
+                                              void* param);
 
+// Sets the file descriptor transport mode for this session.
+void ARpcSession_setFileDescriptorTransportMode(ARpcSession* session,
+                                                ARpcSession_FileDescriptorTransportMode mode);
+
+// Sets the maximum number of incoming threads.
+void ARpcSession_setMaxIncomingThreads(ARpcSession* session, size_t threads);
+
+// Sets the maximum number of outgoing threads.
+void ARpcSession_setMaxOutgoingThreads(ARpcSession* session, size_t threads);
+
+// Decrements the refcount of the underlying RpcSession object.
+void ARpcSession_free(ARpcSession* session);
 }
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index a3d42b7..78dae4b 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -14,68 +14,171 @@
  * limitations under the License.
  */
 
+#include <binder_rpc_unstable.hpp>
+
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 #include <android/binder_libbinder.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
+#include <cutils/sockets.h>
 #include <linux/vm_sockets.h>
 
 using android::OK;
 using android::RpcServer;
 using android::RpcSession;
+using android::sp;
 using android::status_t;
 using android::statusToString;
 using android::base::unique_fd;
 
+// Opaque handle for RpcServer.
+struct ARpcServer {};
+
+// Opaque handle for RpcSession.
+struct ARpcSession {};
+
+template <typename A, typename T>
+static A* createObjectHandle(sp<T>& server) {
+    auto ref = server.get();
+    ref->incStrong(ref);
+    return reinterpret_cast<A*>(ref);
+}
+
+template <typename T, typename A>
+static void freeObjectHandle(A* handle) {
+    LOG_ALWAYS_FATAL_IF(handle == nullptr, "Handle cannot be null");
+    auto ref = reinterpret_cast<T*>(handle);
+    ref->decStrong(ref);
+}
+
+template <typename T, typename A>
+static sp<T> handleToStrongPointer(A* handle) {
+    LOG_ALWAYS_FATAL_IF(handle == nullptr, "Handle cannot be null");
+    auto ref = reinterpret_cast<T*>(handle);
+    return sp<T>::fromExisting(ref);
+}
+
+RpcSession::FileDescriptorTransportMode toTransportMode(
+        ARpcSession_FileDescriptorTransportMode mode) {
+    switch (mode) {
+        case ARpcSession_FileDescriptorTransportMode::None:
+            return RpcSession::FileDescriptorTransportMode::NONE;
+        case ARpcSession_FileDescriptorTransportMode::Unix:
+            return RpcSession::FileDescriptorTransportMode::UNIX;
+        case ARpcSession_FileDescriptorTransportMode::Trusty:
+            return RpcSession::FileDescriptorTransportMode::TRUSTY;
+        default:
+            return RpcSession::FileDescriptorTransportMode::NONE;
+    }
+}
+
 extern "C" {
 
-bool RunRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
-                             void* factoryContext, unsigned int port) {
+ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid, unsigned int port) {
     auto server = RpcServer::make();
-    if (status_t status = server->setupVsockServer(port); status != OK) {
-        LOG(ERROR) << "Failed to set up vsock server with port " << port
-                   << " error: " << statusToString(status).c_str();
-        return false;
+
+    unsigned int bindCid = VMADDR_CID_ANY; // bind to the remote interface
+    if (cid == VMADDR_CID_LOCAL) {
+        bindCid = VMADDR_CID_LOCAL; // bind to the local interface
+        cid = VMADDR_CID_ANY;       // no need for a connection filter
     }
-    server->setPerSessionRootObject([=](const void* addr, size_t addrlen) {
-        LOG_ALWAYS_FATAL_IF(addrlen < sizeof(sockaddr_vm), "sockaddr is truncated");
-        const sockaddr_vm* vaddr = reinterpret_cast<const sockaddr_vm*>(addr);
-        LOG_ALWAYS_FATAL_IF(vaddr->svm_family != AF_VSOCK, "address is not a vsock");
-        return AIBinder_toPlatformBinder(factory(vaddr->svm_cid, factoryContext));
-    });
 
-    server->join();
-
-    // Shutdown any open sessions since server failed.
-    (void)server->shutdown();
-    return true;
-}
-
-bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
-                          void* param) {
-    auto server = RpcServer::make();
-    if (status_t status = server->setupVsockServer(port); status != OK) {
+    if (status_t status = server->setupVsockServer(bindCid, port); status != OK) {
         LOG(ERROR) << "Failed to set up vsock server with port " << port
                    << " error: " << statusToString(status).c_str();
-        return false;
+        return nullptr;
+    }
+    if (cid != VMADDR_CID_ANY) {
+        server->setConnectionFilter([=](const void* addr, size_t addrlen) {
+            LOG_ALWAYS_FATAL_IF(addrlen < sizeof(sockaddr_vm), "sockaddr is truncated");
+            const sockaddr_vm* vaddr = reinterpret_cast<const sockaddr_vm*>(addr);
+            LOG_ALWAYS_FATAL_IF(vaddr->svm_family != AF_VSOCK, "address is not a vsock");
+            if (cid != vaddr->svm_cid) {
+                LOG(ERROR) << "Rejected vsock connection from CID " << vaddr->svm_cid;
+                return false;
+            }
+            return true;
+        });
     }
     server->setRootObject(AIBinder_toPlatformBinder(service));
-
-    if (readyCallback) readyCallback(param);
-    server->join();
-
-    // Shutdown any open sessions since server failed.
-    (void)server->shutdown();
-    return true;
+    return createObjectHandle<ARpcServer>(server);
 }
 
-bool RunRpcServer(AIBinder* service, unsigned int port) {
-    return RunRpcServerCallback(service, port, nullptr, nullptr);
+ARpcServer* ARpcServer_newInitUnixDomain(AIBinder* service, const char* name) {
+    auto server = RpcServer::make();
+    auto fd = unique_fd(android_get_control_socket(name));
+    if (!fd.ok()) {
+        LOG(ERROR) << "Failed to get fd for the socket:" << name;
+        return nullptr;
+    }
+    if (status_t status = server->setupRawSocketServer(std::move(fd)); status != OK) {
+        LOG(ERROR) << "Failed to set up Unix Domain RPC server with name " << name
+                   << " error: " << statusToString(status).c_str();
+        return nullptr;
+    }
+    server->setRootObject(AIBinder_toPlatformBinder(service));
+    return createObjectHandle<ARpcServer>(server);
 }
 
-AIBinder* RpcClient(unsigned int cid, unsigned int port) {
+ARpcServer* ARpcServer_newUnixDomainBootstrap(AIBinder* service, int bootstrapFd) {
+    auto server = RpcServer::make();
+    auto fd = unique_fd(bootstrapFd);
+    if (!fd.ok()) {
+        LOG(ERROR) << "Invalid bootstrap fd " << bootstrapFd;
+        return nullptr;
+    }
+    if (status_t status = server->setupUnixDomainSocketBootstrapServer(std::move(fd));
+        status != OK) {
+        LOG(ERROR) << "Failed to set up Unix Domain RPC server with bootstrap fd " << bootstrapFd
+                   << " error: " << statusToString(status).c_str();
+        return nullptr;
+    }
+    server->setRootObject(AIBinder_toPlatformBinder(service));
+    return createObjectHandle<ARpcServer>(server);
+}
+
+void ARpcServer_setSupportedFileDescriptorTransportModes(
+        ARpcServer* handle, const ARpcSession_FileDescriptorTransportMode modes[],
+        size_t modes_len) {
+    auto server = handleToStrongPointer<RpcServer>(handle);
+    std::vector<RpcSession::FileDescriptorTransportMode> modevec;
+    for (size_t i = 0; i < modes_len; i++) {
+        modevec.push_back(toTransportMode(modes[i]));
+    }
+    server->setSupportedFileDescriptorTransportModes(modevec);
+}
+
+void ARpcServer_start(ARpcServer* handle) {
+    handleToStrongPointer<RpcServer>(handle)->start();
+}
+
+void ARpcServer_join(ARpcServer* handle) {
+    handleToStrongPointer<RpcServer>(handle)->join();
+}
+
+bool ARpcServer_shutdown(ARpcServer* handle) {
+    return handleToStrongPointer<RpcServer>(handle)->shutdown();
+}
+
+void ARpcServer_free(ARpcServer* handle) {
+    // Ignore the result of ARpcServer_shutdown - either it had been called
+    // earlier, or the RpcServer destructor will panic.
+    (void)ARpcServer_shutdown(handle);
+    freeObjectHandle<RpcServer>(handle);
+}
+
+ARpcSession* ARpcSession_new() {
     auto session = RpcSession::make();
+    return createObjectHandle<ARpcSession>(session);
+}
+
+void ARpcSession_free(ARpcSession* handle) {
+    freeObjectHandle<RpcSession>(handle);
+}
+
+AIBinder* ARpcSession_setupVsockClient(ARpcSession* handle, unsigned int cid, unsigned int port) {
+    auto session = handleToStrongPointer<RpcSession>(handle);
     if (status_t status = session->setupVsockClient(cid, port); status != OK) {
         LOG(ERROR) << "Failed to set up vsock client with CID " << cid << " and port " << port
                    << " error: " << statusToString(status).c_str();
@@ -84,8 +187,37 @@
     return AIBinder_fromPlatformBinder(session->getRootObject());
 }
 
-AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param) {
-    auto session = RpcSession::make();
+AIBinder* ARpcSession_setupUnixDomainClient(ARpcSession* handle, const char* name) {
+    std::string pathname(name);
+    pathname = ANDROID_SOCKET_DIR "/" + pathname;
+    auto session = handleToStrongPointer<RpcSession>(handle);
+    if (status_t status = session->setupUnixDomainClient(pathname.c_str()); status != OK) {
+        LOG(ERROR) << "Failed to set up Unix Domain RPC client with path: " << pathname
+                   << " error: " << statusToString(status).c_str();
+        return nullptr;
+    }
+    return AIBinder_fromPlatformBinder(session->getRootObject());
+}
+
+AIBinder* ARpcSession_setupUnixDomainBootstrapClient(ARpcSession* handle, int bootstrapFd) {
+    auto session = handleToStrongPointer<RpcSession>(handle);
+    auto fd = unique_fd(dup(bootstrapFd));
+    if (!fd.ok()) {
+        LOG(ERROR) << "Invalid bootstrap fd " << bootstrapFd;
+        return nullptr;
+    }
+    if (status_t status = session->setupUnixDomainSocketBootstrapClient(std::move(fd));
+        status != OK) {
+        LOG(ERROR) << "Failed to set up Unix Domain RPC client with bootstrap fd: " << bootstrapFd
+                   << " error: " << statusToString(status).c_str();
+        return nullptr;
+    }
+    return AIBinder_fromPlatformBinder(session->getRootObject());
+}
+
+AIBinder* ARpcSession_setupPreconnectedClient(ARpcSession* handle, int (*requestFd)(void* param),
+                                              void* param) {
+    auto session = handleToStrongPointer<RpcSession>(handle);
     auto request = [=] { return unique_fd{requestFd(param)}; };
     if (status_t status = session->setupPreconnectedClient(unique_fd{}, request); status != OK) {
         LOG(ERROR) << "Failed to set up vsock client. error: " << statusToString(status).c_str();
@@ -93,4 +225,20 @@
     }
     return AIBinder_fromPlatformBinder(session->getRootObject());
 }
+
+void ARpcSession_setFileDescriptorTransportMode(ARpcSession* handle,
+                                                ARpcSession_FileDescriptorTransportMode mode) {
+    auto session = handleToStrongPointer<RpcSession>(handle);
+    session->setFileDescriptorTransportMode(toTransportMode(mode));
+}
+
+void ARpcSession_setMaxIncomingThreads(ARpcSession* handle, size_t threads) {
+    auto session = handleToStrongPointer<RpcSession>(handle);
+    session->setMaxIncomingThreads(threads);
+}
+
+void ARpcSession_setMaxOutgoingThreads(ARpcSession* handle, size_t threads) {
+    auto session = handleToStrongPointer<RpcSession>(handle);
+    session->setMaxOutgoingThreads(threads);
+}
 }
diff --git a/libs/binder/libbinder_rpc_unstable.map.txt b/libs/binder/libbinder_rpc_unstable.map.txt
index e856569..1bc2416 100644
--- a/libs/binder/libbinder_rpc_unstable.map.txt
+++ b/libs/binder/libbinder_rpc_unstable.map.txt
@@ -1,8 +1,13 @@
 LIBBINDER_RPC_UNSTABLE_SHIM { # platform-only
   global:
-    RunRpcServer;
-    RunRpcServerCallback;
-    RpcClient;
+    ARpcServer_free;
+    ARpcServer_join;
+    ARpcServer_newInitUnixDomain;
+    ARpcServer_newVsock;
+    ARpcServer_shutdown;
+    ARpcServer_start;
+    VsockRpcClient;
+    UnixDomainRpcClient;
     RpcPreconnectedClient;
   local:
     *;
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 28d1f16..d0de7b9 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -75,12 +75,48 @@
 AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {}
 AIBinder::~AIBinder() {}
 
-std::optional<bool> AIBinder::associateClassInternal(const AIBinder_Class* clazz,
-                                                     const String16& newDescriptor, bool set) {
+// b/175635923 libcxx causes "implicit-conversion" with a string with invalid char
+static std::string SanitizeString(const String16& str) {
+    std::string sanitized{String8(str)};
+    for (auto& c : sanitized) {
+        if (!isprint(c)) {
+            c = '?';
+        }
+    }
+    return sanitized;
+}
+
+bool AIBinder::associateClass(const AIBinder_Class* clazz) {
+    if (clazz == nullptr) return false;
+
+    // If mClazz is non-null, this must have been called and cached
+    // already. So, we can safely call this first. Due to the implementation
+    // of getInterfaceDescriptor (at time of writing), two simultaneous calls
+    // may lead to extra binder transactions, but this is expected to be
+    // exceedingly rare. Once we have a binder, when we get it again later,
+    // we won't make another binder transaction here.
+    const String16& descriptor = getBinder()->getInterfaceDescriptor();
+    const String16& newDescriptor = clazz->getInterfaceDescriptor();
+
     std::lock_guard<std::mutex> lock(mClazzMutex);
     if (mClazz == clazz) return true;
 
-    if (mClazz != nullptr) {
+    // If this is an ABpBinder, the first class object becomes the canonical one. The implication
+    // of this is that no API can require a proxy information to get information on how to behave.
+    // from the class itself - which should only store the interface descriptor. The functionality
+    // should be implemented by adding AIBinder_* APIs to set values on binders themselves, by
+    // setting things on AIBinder_Class which get transferred along with the binder, so that they
+    // can be read along with the BpBinder, or by modifying APIs directly (e.g. an option in
+    // onTransact).
+    //
+    // While this check is required to support linkernamespaces, one downside of it is that
+    // you may parcel code to communicate between things in the same process. However, comms
+    // between linkernamespaces like this already happen for cross-language calls like Java<->C++
+    // or Rust<->Java, and there are good stability guarantees here. This interacts with
+    // binder Stability checks exactly like any other in-process call. The stability is known
+    // to the IBinder object, so that it doesn't matter if a class object comes from
+    // a different stability level.
+    if (mClazz != nullptr && !asABpBinder()) {
         const String16& currentDescriptor = mClazz->getInterfaceDescriptor();
         if (newDescriptor == currentDescriptor) {
             LOG(ERROR) << __func__ << ": Class descriptors '" << currentDescriptor
@@ -97,37 +133,10 @@
         return false;
     }
 
-    if (set) {
-        // if this is a local object, it's not one known to libbinder_ndk
-        mClazz = clazz;
-        return true;
-    }
-
-    return {};
-}
-
-// b/175635923 libcxx causes "implicit-conversion" with a string with invalid char
-static std::string SanitizeString(const String16& str) {
-    std::string sanitized{String8(str)};
-    for (auto& c : sanitized) {
-        if (!isprint(c)) {
-            c = '?';
-        }
-    }
-    return sanitized;
-}
-
-bool AIBinder::associateClass(const AIBinder_Class* clazz) {
-    if (clazz == nullptr) return false;
-
-    const String16& newDescriptor = clazz->getInterfaceDescriptor();
-
-    auto result = associateClassInternal(clazz, newDescriptor, false);
-    if (result.has_value()) return *result;
-
-    CHECK(asABpBinder() != nullptr);  // ABBinder always has a descriptor
-
-    const String16& descriptor = getBinder()->getInterfaceDescriptor();
+    // This will always be an O(n) comparison, but it's expected to be extremely rare.
+    // since it's an error condition. Do the comparison after we take the lock and
+    // check the pointer equality fast path. By always taking the lock, it's also
+    // more flake-proof. However, the check is not dependent on the lock.
     if (descriptor != newDescriptor) {
         if (getBinder()->isBinderAlive()) {
             LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor
@@ -141,7 +150,14 @@
         return false;
     }
 
-    return associateClassInternal(clazz, newDescriptor, true).value();
+    // A local binder being set for the first time OR
+    // ignoring a proxy binder which is set multiple time, by considering the first
+    // associated class as the canonical one.
+    if (mClazz == nullptr) {
+        mClazz = clazz;
+    }
+
+    return true;
 }
 
 ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData)
@@ -325,6 +341,10 @@
     return lhs->binder < rhs->binder;
 }
 
+// WARNING: When multiple classes exist with the same interface descriptor in different
+// linkernamespaces, the first one to be associated with mClazz becomes the canonical one
+// and the only requirement on this is that the interface descriptors match. If this
+// is an ABpBinder, no other state can be referenced from mClazz.
 AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
                                AIBinder_Class_onDestroy onDestroy,
                                AIBinder_Class_onTransact onTransact)
@@ -632,6 +652,10 @@
     (*in)->get()->markForBinder(binder->getBinder());
 
     status_t status = android::OK;
+
+    // note - this is the only read of a value in clazz, and it comes with a warning
+    // on the API itself. Do not copy this design. Instead, attach data in a new
+    // version of the prepareTransaction function.
     if (clazz->writeHeader) {
         status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor());
     }
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index d7098e8..67bb092 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -53,12 +53,14 @@
     }
 
    private:
-    std::optional<bool> associateClassInternal(const AIBinder_Class* clazz,
-                                               const ::android::String16& newDescriptor, bool set);
-
     // AIBinder instance is instance of this class for a local object. In order to transact on a
     // remote object, this also must be set for simplicity (although right now, only the
     // interfaceDescriptor from it is used).
+    //
+    // WARNING: When multiple classes exist with the same interface descriptor in different
+    // linkernamespaces, the first one to be associated with mClazz becomes the canonical one
+    // and the only requirement on this is that the interface descriptors match. If this
+    // is an ABpBinder, no other state can be referenced from mClazz.
     const AIBinder_Class* mClazz;
     std::mutex mClazzMutex;
 };
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index fccc0af..d6937c2 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -30,11 +30,11 @@
 #include <android/binder_internal_logging.h>
 #include <android/binder_parcel.h>
 #include <android/binder_status.h>
-
 #include <assert.h>
-
 #include <unistd.h>
+
 #include <cstddef>
+#include <iostream>
 #include <string>
 
 namespace ndk {
@@ -270,14 +270,19 @@
     std::string getDescription() const {
 #ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
         if (__builtin_available(android 30, *)) {
-#else
-        if (__ANDROID_API__ >= 30) {
 #endif
+
+#if defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 30
             const char* cStr = AStatus_getDescription(get());
             std::string ret = cStr;
             AStatus_deleteDescription(cStr);
             return ret;
+#endif
+
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
         }
+#endif
+
         binder_exception_t exception = getExceptionCode();
         std::string desc = std::to_string(exception);
         if (exception == EX_SERVICE_SPECIFIC) {
@@ -315,6 +320,11 @@
     }
 };
 
+static inline std::ostream& operator<<(std::ostream& os, const ScopedAStatus& status) {
+    return os << status.getDescription();
+    return os;
+}
+
 /**
  * Convenience wrapper. See AIBinder_DeathRecipient.
  */
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 78bcb43..9949de2 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -196,6 +196,10 @@
 
     bool isRemote() override final { return false; }
 
+    static std::string makeServiceName(std::string_view instance) {
+        return INTERFACE::descriptor + ("/" + std::string(instance));
+    }
+
    protected:
     /**
      * This function should only be called by asBinder. Otherwise, there is a possibility of
@@ -291,7 +295,10 @@
 binder_status_t ICInterface::ICInterfaceData::onDump(AIBinder* binder, int fd, const char** args,
                                                      uint32_t numArgs) {
     std::shared_ptr<ICInterface> interface = getInterface(binder);
-    return interface->dump(fd, args, numArgs);
+    if (interface != nullptr) {
+        return interface->dump(fd, args, numArgs);
+    }
+    return STATUS_DEAD_OBJECT;
 }
 
 #ifdef HAS_BINDER_SHELL_COMMAND
@@ -299,7 +306,10 @@
                                                                  int err, const char** argv,
                                                                  uint32_t argc) {
     std::shared_ptr<ICInterface> interface = getInterface(binder);
-    return interface->handleShellCommand(in, out, err, argv, argc);
+    if (interface != nullptr) {
+        return interface->handleShellCommand(in, out, err, argv, argc);
+    }
+    return STATUS_DEAD_OBJECT;
 }
 #endif
 
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index c1f2620..caee471 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -41,68 +41,34 @@
         if (_status != STATUS_OK) return _status; \
     } while (false)
 
+// AParcelableHolder has been introduced in 31.
+#if __ANDROID_API__ >= 31
 class AParcelableHolder {
    public:
     AParcelableHolder() = delete;
     explicit AParcelableHolder(parcelable_stability_t stability)
         : mParcel(AParcel_create()), mStability(stability) {}
 
-#if __ANDROID_API__ >= 31
     AParcelableHolder(const AParcelableHolder& other)
         : mParcel(AParcel_create()), mStability(other.mStability) {
-        // AParcelableHolder has been introduced in 31.
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            AParcel_appendFrom(other.mParcel.get(), this->mParcel.get(), 0,
-                               AParcel_getDataSize(other.mParcel.get()));
-        } else {
-            syslog(LOG_ERR,
-                   "sdk_version not compatible, AParcelableHolder need sdk_version >= 31!");
-        }
+        AParcel_appendFrom(other.mParcel.get(), this->mParcel.get(), 0,
+                           AParcel_getDataSize(other.mParcel.get()));
     }
-#endif
 
     AParcelableHolder(AParcelableHolder&& other) = default;
     virtual ~AParcelableHolder() = default;
 
     binder_status_t writeToParcel(AParcel* parcel) const {
         RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            int32_t size = AParcel_getDataSize(this->mParcel.get());
-            RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
-        } else {
-            return STATUS_INVALID_OPERATION;
-        }
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            int32_t size = AParcel_getDataSize(this->mParcel.get());
-            RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
-        } else {
-            return STATUS_INVALID_OPERATION;
-        }
+        int32_t size = AParcel_getDataSize(this->mParcel.get());
+        RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
+        size = AParcel_getDataSize(this->mParcel.get());
+        RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
         return STATUS_OK;
     }
 
     binder_status_t readFromParcel(const AParcel* parcel) {
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            AParcel_reset(mParcel.get());
-        } else {
-            return STATUS_INVALID_OPERATION;
-        }
+        AParcel_reset(mParcel.get());
 
         parcelable_stability_t wireStability;
         RETURN_ON_FAILURE(AParcel_readInt32(parcel, &wireStability));
@@ -123,15 +89,7 @@
             return STATUS_BAD_VALUE;
         }
 
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
-        } else {
-            status = STATUS_INVALID_OPERATION;
-        }
+        status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
         if (status != STATUS_OK) {
             return status;
         }
@@ -143,15 +101,7 @@
         if (this->mStability > T::_aidl_stability) {
             return STATUS_BAD_VALUE;
         }
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            AParcel_reset(mParcel.get());
-        } else {
-            return STATUS_INVALID_OPERATION;
-        }
+        AParcel_reset(mParcel.get());
         AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
         p.writeToParcel(mParcel.get());
         return STATUS_OK;
@@ -161,17 +111,9 @@
     binder_status_t getParcelable(std::optional<T>* ret) const {
         const std::string parcelableDesc(T::descriptor);
         AParcel_setDataPosition(mParcel.get(), 0);
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            if (AParcel_getDataSize(mParcel.get()) == 0) {
-                *ret = std::nullopt;
-                return STATUS_OK;
-            }
-        } else {
-            return STATUS_INVALID_OPERATION;
+        if (AParcel_getDataSize(mParcel.get()) == 0) {
+            *ret = std::nullopt;
+            return STATUS_OK;
         }
         std::string parcelableDescInParcel;
         binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
@@ -188,18 +130,7 @@
         return STATUS_OK;
     }
 
-    void reset() {
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            AParcel_reset(mParcel.get());
-        } else {
-            syslog(LOG_ERR,
-                   "sdk_version not compatible, AParcelableHolder need sdk_version >= 31!");
-        }
-    }
+    void reset() { AParcel_reset(mParcel.get()); }
 
     inline bool operator!=(const AParcelableHolder& rhs) const { return this != &rhs; }
     inline bool operator<(const AParcelableHolder& rhs) const { return this < &rhs; }
@@ -207,34 +138,23 @@
     inline bool operator==(const AParcelableHolder& rhs) const { return this == &rhs; }
     inline bool operator>(const AParcelableHolder& rhs) const { return this > &rhs; }
     inline bool operator>=(const AParcelableHolder& rhs) const { return this >= &rhs; }
-#if __ANDROID_API__ >= 31
     inline AParcelableHolder& operator=(const AParcelableHolder& rhs) {
-        // AParcelableHolder has been introduced in 31.
-#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
-        if (__builtin_available(android 31, *)) {
-#else
-        if (__ANDROID_API__ >= 31) {
-#endif
-            this->reset();
-            if (this->mStability != rhs.mStability) {
-                syslog(LOG_ERR, "AParcelableHolder stability mismatch: this %d rhs %d!",
-                       this->mStability, rhs.mStability);
-                abort();
-            }
-            AParcel_appendFrom(rhs.mParcel.get(), this->mParcel.get(), 0,
-                               AParcel_getDataSize(rhs.mParcel.get()));
-        } else {
-            syslog(LOG_ERR,
-                   "sdk_version not compatible, AParcelableHolder need sdk_version >= 31!");
+        this->reset();
+        if (this->mStability != rhs.mStability) {
+            syslog(LOG_ERR, "AParcelableHolder stability mismatch: this %d rhs %d!",
+                   this->mStability, rhs.mStability);
+            abort();
         }
+        AParcel_appendFrom(rhs.mParcel.get(), this->mParcel.get(), 0,
+                           AParcel_getDataSize(rhs.mParcel.get()));
         return *this;
     }
-#endif
 
    private:
     mutable ndk::ScopedAParcel mParcel;
     parcelable_stability_t mStability;
 };
+#endif  // __ANDROID_API__ >= 31
 
 #undef RETURN_ON_FAILURE
 }  // namespace ndk
diff --git a/libs/binder/ndk/include_cpp/android/binder_to_string.h b/libs/binder/ndk/include_cpp/android/binder_to_string.h
index d7840ec..2a00736 100644
--- a/libs/binder/ndk/include_cpp/android/binder_to_string.h
+++ b/libs/binder/ndk/include_cpp/android/binder_to_string.h
@@ -136,8 +136,10 @@
     template <typename _U>
     static std::enable_if_t<
 #ifdef HAS_NDK_INTERFACE
-            std::is_base_of_v<::ndk::ICInterface, _U> ||
-                    std::is_same_v<::ndk::AParcelableHolder, _U>
+            std::is_base_of_v<::ndk::ICInterface, _U>
+#if __ANDROID_API__ >= 31
+                    || std::is_same_v<::ndk::AParcelableHolder, _U>
+#endif
 #else
             std::is_base_of_v<IInterface, _U> || std::is_same_v<IBinder, _U> ||
                     std::is_same_v<os::ParcelFileDescriptor, _U> ||
@@ -158,7 +160,7 @@
 template <typename _T>
 std::string ToString(const _T& t) {
     if constexpr (details::ToEmptyString<_T>::value) {
-        return "";
+        return "<unimplemented>";
     } else if constexpr (std::is_same_v<bool, _T>) {
         return t ? "true" : "false";
     } else if constexpr (std::is_same_v<char16_t, _T>) {
@@ -174,9 +176,11 @@
         return t;
 #ifdef HAS_NDK_INTERFACE
     } else if constexpr (std::is_same_v<::ndk::SpAIBinder, _T>) {
-        return (t.get() == nullptr) ? "(null)" : "";
+        std::stringstream ss;
+        ss << "binder:" << std::hex << t.get();
+        return ss.str();
     } else if constexpr (std::is_same_v<::ndk::ScopedFileDescriptor, _T>) {
-        return (t.get() == -1) ? "(null)" : "";
+        return "fd:" + std::to_string(t.get());
 #endif
 #ifdef HAS_STRING16
     } else if constexpr (std::is_same_v<String16, _T>) {
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 4163897..05677a8 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -229,6 +229,11 @@
  *
  * Available since API level 33.
  *
+ * WARNING: this API interacts badly with linkernamespaces. For correct behavior, you must
+ * use it on all instances of a class in the same process which share the same interface
+ * descriptor. In general, it is recommended you do not use this API, because it is disabling
+ * type safety.
+ *
  * \param clazz class to disable interface header on.
  */
 void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) __INTRODUCED_IN(33);
@@ -613,7 +618,8 @@
  *
  *  1. If the binder died, shortly after the call to onBinderDied.
  *  2. If the binder is explicitly unlinked with AIBinder_unlinkToDeath or
- *     AIBinder_DeathRecipient_delete.
+ *     AIBinder_DeathRecipient_delete, after any pending onBinderDied calls
+ *     finish.
  *  3. During or shortly after the AIBinder_linkToDeath call if it returns an error.
  *
  * It is guaranteed that the callback is called exactly once for each call to linkToDeath unless the
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index dfa8ea2..ad4188f 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -68,6 +68,7 @@
  *
  * \param instance identifier of the service used to lookup the service.
  */
+[[deprecated("this polls 5s, use AServiceManager_waitForService or AServiceManager_checkService")]]
 __attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance)
         __INTRODUCED_IN(29);
 
@@ -108,6 +109,67 @@
         __INTRODUCED_IN(31);
 
 /**
+ * Function to call when a service is registered. The instance is passed as well as
+ * ownership of the binder named 'registered'.
+ *
+ * WARNING: a lock is held when this method is called in order to prevent races with
+ * AServiceManager_NotificationRegistration_delete. Do not make synchronous binder calls when
+ * implementing this method to avoid deadlocks.
+ *
+ * \param instance instance name of service registered
+ * \param registered ownership-passed instance of service registered
+ * \param cookie data passed during registration for notifications
+ */
+typedef void (*AServiceManager_onRegister)(const char* instance, AIBinder* registered,
+                                           void* cookie);
+
+/**
+ * Represents a registration to servicemanager which can be cleared anytime.
+ */
+struct AServiceManager_NotificationRegistration;
+
+/**
+ * Get notifications when a service is registered. If the service is already registered,
+ * you will immediately get a notification.
+ *
+ * WARNING: it is strongly recommended to use AServiceManager_waitForService API instead.
+ * That API will wait synchronously, which is what you usually want in cases, including
+ * using some feature or during boot up. There is a history of bugs where waiting for
+ * notifications like this races with service startup. Also, when this API is used, a service
+ * bug will result in silent failure (rather than a debuggable deadlock). Furthermore, there
+ * is a history of this API being used to know when a service is up as a proxy for whethre
+ * that service should be started. This should only be used if you are intending to get
+ * ahold of the service as a client. For lazy services, whether a service is registered
+ * should not be used as a proxy for when it should be registered, which is only known
+ * by the real client.
+ *
+ * WARNING: if you use this API, you must also ensure that you check missing services are
+ * started and crash otherwise. If service failures are ignored, the system rots.
+ *
+ * \param instance name of service to wait for notifications about
+ * \param onRegister callback for when service is registered
+ * \param cookie data associated with this callback
+ *
+ * \return the token for this registration. Deleting this token will unregister.
+ */
+__attribute__((warn_unused_result)) AServiceManager_NotificationRegistration*
+AServiceManager_registerForServiceNotifications(const char* instance,
+                                                AServiceManager_onRegister onRegister, void* cookie)
+        __INTRODUCED_IN(34);
+
+/**
+ * Unregister for notifications and delete the object.
+ *
+ * After this method is called, the callback is guaranteed to no longer be invoked. This will block
+ * until any in-progress onRegister callbacks have completed. It is therefore safe to immediately
+ * destroy the void* cookie that was registered when this method returns.
+ *
+ * \param notification object to dismiss
+ */
+void AServiceManager_NotificationRegistration_delete(
+        AServiceManager_NotificationRegistration* notification) __INTRODUCED_IN(34);
+
+/**
  * Check if a service is declared (e.g. VINTF manifest).
  *
  * \param instance identifier of the service.
@@ -143,6 +205,17 @@
 bool AServiceManager_isUpdatableViaApex(const char* instance) __INTRODUCED_IN(31);
 
 /**
+ * Returns the APEX name if a service is declared as updatable via an APEX module.
+ *
+ * \param instance identifier of the service
+ * \param context to pass to callback
+ * \param callback taking the APEX name (e.g. 'com.android.foo') and context
+ */
+void AServiceManager_getUpdatableApexName(const char* instance, void* context,
+                                          void (*callback)(const char*, void*))
+        __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
  * Prevent lazy services without client from shutting down their process
  *
  * This should only be used if it is every eventually set to false. If a
diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
index f408fad..ffcad55 100644
--- a/libs/binder/ndk/include_platform/android/binder_process.h
+++ b/libs/binder/ndk/include_platform/android/binder_process.h
@@ -28,17 +28,33 @@
  *
  * When using this, it is expected that ABinderProcess_setupPolling and
  * ABinderProcess_handlePolledCommands are not used.
+ *
+ * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
+ * function should be responsible for configuring the threadpool for the entire application.
  */
 void ABinderProcess_startThreadPool();
 /**
  * This sets the maximum number of threads that can be started in the threadpool. By default, after
  * startThreadPool is called, this is 15. If it is called additional times, it will only prevent
  * the kernel from starting new threads and will not delete already existing threads.
+ *
+ * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
+ * function should be responsible for configuring the threadpool for the entire application.
  */
 bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads);
 /**
+ * Check if the threadpool has already been started.
+ * This tells whether someone in the process has called ABinderProcess_startThreadPool. Usually,
+ * you should use this in a library to abort if the threadpool is not started.
+ * Programs should configure binder threadpools once at the beginning.
+ */
+bool ABinderProcess_isThreadPoolStarted();
+/**
  * This adds the current thread to the threadpool. This may cause the threadpool to exceed the
  * maximum size.
+ *
+ * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
+ * function should be responsible for configuring the threadpool for the entire application.
  */
 void ABinderProcess_joinThreadPool();
 
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index 683a433..c1f62e5 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -50,6 +50,15 @@
  * requirements associated with that higher stability level. For instance, a
  * VINTF stability binder is required to be in the VINTF manifest. This API
  * can be called to use that same interface within the vendor partition.
+ *
+ * WARNING: you must hold on to a binder instance after this is set, while you
+ * are using it. If you get a binder (e.g. `...->asBinder().get()`), you must
+ * save this binder and then
+ * use it. For instance:
+ *
+ *     auto binder = ...->asBinder();
+ *     AIBinder_forceDowngradeToVendorStability(binder.get());
+ *     doSomething(binder);
  */
 void AIBinder_forceDowngradeToVendorStability(AIBinder* binder);
 
@@ -79,6 +88,15 @@
  * requirements associated with that higher stability level. For instance, a
  * VINTF stability binder is required to be in the VINTF manifest. This API
  * can be called to use that same interface within the system partition.
+ *
+ * WARNING: you must hold on to a binder instance after this is set, while you
+ * are using it. If you get a binder (e.g. `...->asBinder().get()`), you must
+ * save this binder and then
+ * use it. For instance:
+ *
+ *     auto binder = ...->asBinder();
+ *     AIBinder_forceDowngradeToSystemStability(binder.get());
+ *     doSomething(binder);
  */
 void AIBinder_forceDowngradeToSystemStability(AIBinder* binder);
 
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 259a736..54e4628 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -152,6 +152,14 @@
     AParcel_unmarshal;
 };
 
+LIBBINDER_NDK34 { # introduced=UpsideDownCake
+  global:
+    ABinderProcess_isThreadPoolStarted; # systemapi llndk
+    AServiceManager_getUpdatableApexName; # systemapi
+    AServiceManager_registerForServiceNotifications; # systemapi llndk
+    AServiceManager_NotificationRegistration_delete; # systemapi llndk
+};
+
 LIBBINDER_NDK_PLATFORM {
   global:
     AParcel_getAllowFds;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index c320e8d..8693022 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -129,7 +129,13 @@
     }
 
     T* array;
-    if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+    if (!allocator(arrayData, length, &array)) {
+        if (length < 0) {
+            return STATUS_UNEXPECTED_NULL;
+        } else {
+            return STATUS_NO_MEMORY;
+        }
+    }
 
     if (length <= 0) return STATUS_OK;
     if (array == nullptr) return STATUS_NO_MEMORY;
@@ -157,7 +163,13 @@
     }
 
     char16_t* array;
-    if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+    if (!allocator(arrayData, length, &array)) {
+        if (length < 0) {
+            return STATUS_UNEXPECTED_NULL;
+        } else {
+            return STATUS_NO_MEMORY;
+        }
+    }
 
     if (length <= 0) return STATUS_OK;
     if (array == nullptr) return STATUS_NO_MEMORY;
@@ -204,7 +216,13 @@
         return status;
     }
 
-    if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+    if (!allocator(arrayData, length)) {
+        if (length < 0) {
+            return STATUS_UNEXPECTED_NULL;
+        } else {
+            return STATUS_NO_MEMORY;
+        }
+    }
 
     if (length <= 0) return STATUS_OK;
 
diff --git a/libs/binder/ndk/process.cpp b/libs/binder/ndk/process.cpp
index ac582a4..bc6610e 100644
--- a/libs/binder/ndk/process.cpp
+++ b/libs/binder/ndk/process.cpp
@@ -31,6 +31,9 @@
 bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads) {
     return ProcessState::self()->setThreadPoolMaxThreadCount(numThreads) == 0;
 }
+bool ABinderProcess_isThreadPoolStarted() {
+    return ProcessState::self()->isThreadPoolStarted();
+}
 void ABinderProcess_joinThreadPool() {
     IPCThreadState::self()->joinThreadPool();
 }
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index 7649a26..e107c83 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -28,6 +28,7 @@
 using ::android::IServiceManager;
 using ::android::sp;
 using ::android::status_t;
+using ::android::statusToString;
 using ::android::String16;
 using ::android::String8;
 
@@ -86,6 +87,67 @@
     AIBinder_incStrong(ret.get());
     return ret.get();
 }
+typedef void (*AServiceManager_onRegister)(const char* instance, AIBinder* registered,
+                                           void* cookie);
+
+struct AServiceManager_NotificationRegistration
+    : public IServiceManager::LocalRegistrationCallback {
+    std::mutex m;
+    const char* instance = nullptr;
+    void* cookie = nullptr;
+    AServiceManager_onRegister onRegister = nullptr;
+
+    virtual void onServiceRegistration(const String16& smInstance, const sp<IBinder>& binder) {
+        std::lock_guard<std::mutex> l(m);
+        if (onRegister == nullptr) return;
+
+        CHECK_EQ(String8(smInstance), instance);
+
+        sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder);
+        AIBinder_incStrong(ret.get());
+
+        onRegister(instance, ret.get(), cookie);
+    }
+
+    void clear() {
+        std::lock_guard<std::mutex> l(m);
+        instance = nullptr;
+        cookie = nullptr;
+        onRegister = nullptr;
+    }
+};
+
+__attribute__((warn_unused_result)) AServiceManager_NotificationRegistration*
+AServiceManager_registerForServiceNotifications(const char* instance,
+                                                AServiceManager_onRegister onRegister,
+                                                void* cookie) {
+    CHECK_NE(instance, nullptr);
+    CHECK_NE(onRegister, nullptr) << instance;
+    // cookie can be nullptr
+
+    auto cb = sp<AServiceManager_NotificationRegistration>::make();
+    cb->instance = instance;
+    cb->onRegister = onRegister;
+    cb->cookie = cookie;
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    if (status_t res = sm->registerForNotifications(String16(instance), cb); res != STATUS_OK) {
+        LOG(ERROR) << "Failed to register for service notifications for " << instance << ": "
+                   << statusToString(res);
+        return nullptr;
+    }
+
+    cb->incStrong(nullptr);
+    return cb.get();
+}
+
+void AServiceManager_NotificationRegistration_delete(
+        AServiceManager_NotificationRegistration* notification) {
+    CHECK_NE(notification, nullptr);
+    notification->clear();
+    notification->decStrong(nullptr);
+}
+
 bool AServiceManager_isDeclared(const char* instance) {
     if (instance == nullptr) {
         return false;
@@ -113,6 +175,18 @@
     sp<IServiceManager> sm = defaultServiceManager();
     return sm->updatableViaApex(String16(instance)) != std::nullopt;
 }
+void AServiceManager_getUpdatableApexName(const char* instance, void* context,
+                                          void (*callback)(const char*, void*)) {
+    CHECK_NE(instance, nullptr);
+    // context may be nullptr
+    CHECK_NE(callback, nullptr);
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    std::optional<String16> updatableViaApex = sm->updatableViaApex(String16(instance));
+    if (updatableViaApex.has_value()) {
+        callback(String8(updatableViaApex.value()).c_str(), context);
+    }
+}
 void AServiceManager_forceLazyServicesPersist(bool persist) {
     auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
     serviceRegistrar.forcePersist(persist);
diff --git a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
index f3cd218..43b2cb8 100644
--- a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
+++ b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
@@ -106,7 +106,7 @@
         std::string outString;
         ScopedAStatus status = server->RepeatString("foo", &outString);
         EXPECT_EQ(STATUS_OK, AStatus_getExceptionCode(status.get()))
-                << serviceName << " " << status.getDescription();
+                << serviceName << " " << status;
         EXPECT_EQ("foo", outString) << serviceName;
     }
 }
diff --git a/libs/binder/ndk/tests/iface.cpp b/libs/binder/ndk/tests/iface.cpp
index 2afe5d2..76acff5 100644
--- a/libs/binder/ndk/tests/iface.cpp
+++ b/libs/binder/ndk/tests/iface.cpp
@@ -72,6 +72,11 @@
 AIBinder_Class* IFoo::kClass = AIBinder_Class_define(kIFooDescriptor, IFoo_Class_onCreate,
                                                      IFoo_Class_onDestroy, IFoo_Class_onTransact);
 
+// Defines the same class. Ordinarly, you would never want to do this, but it's done here
+// to simulate what would happen when multiple linker namespaces interact.
+AIBinder_Class* IFoo::kClassDupe = AIBinder_Class_define(
+        kIFooDescriptor, IFoo_Class_onCreate, IFoo_Class_onDestroy, IFoo_Class_onTransact);
+
 class BpFoo : public IFoo {
    public:
     explicit BpFoo(AIBinder* binder) : mBinder(binder) {}
diff --git a/libs/binder/ndk/tests/include/iface/iface.h b/libs/binder/ndk/tests/include/iface/iface.h
index 7408d0c..0a562f0 100644
--- a/libs/binder/ndk/tests/include/iface/iface.h
+++ b/libs/binder/ndk/tests/include/iface/iface.h
@@ -30,8 +30,13 @@
     static const char* kIFooDescriptor;
 
     static AIBinder_Class* kClass;
+    static AIBinder_Class* kClassDupe;
 
     // binder representing this interface with one reference count
+    // NOTE - this will create a new binder if it already exists. If you use
+    // getService for instance, you must pull outBinder. Don't use this without
+    // verifying isRemote or pointer equality. This is not a very good testing API - don't
+    // copy it - consider the AIDL-generated APIs instead.
     AIBinder* getBinder();
 
     // Takes ownership of IFoo
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 01b9472..5b2532a 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -33,13 +33,15 @@
 #include <binder/IResultReceiver.h>
 #include <binder/IServiceManager.h>
 #include <binder/IShellCallback.h>
-
 #include <sys/prctl.h>
+
 #include <chrono>
 #include <condition_variable>
 #include <iostream>
 #include <mutex>
+#include <optional>
 #include <thread>
+
 #include "android/binder_ibinder.h"
 
 using namespace android;
@@ -53,6 +55,18 @@
 constexpr unsigned int kShutdownWaitTime = 10;
 constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715;
 
+class MyTestFoo : public IFoo {
+    binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+        *out = 2 * in;
+        LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+        return STATUS_OK;
+    }
+    binder_status_t die() override {
+        ADD_FAILURE() << "die called on local instance";
+        return STATUS_OK;
+    }
+};
+
 class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
     ndk::ScopedAStatus repeatInt(int32_t in, int32_t* out) {
         *out = in;
@@ -252,12 +266,52 @@
     AIBinder_decStrong(binder);
 }
 
+struct ServiceData {
+    std::string instance;
+    ndk::SpAIBinder binder;
+
+    static void fillOnRegister(const char* instance, AIBinder* binder, void* cookie) {
+        ServiceData* d = reinterpret_cast<ServiceData*>(cookie);
+        d->instance = instance;
+        d->binder = ndk::SpAIBinder(binder);
+    }
+};
+
+TEST(NdkBinder, RegisterForServiceNotificationsNonExisting) {
+    ServiceData data;
+    auto* notif = AServiceManager_registerForServiceNotifications(
+            "DOES_NOT_EXIST", ServiceData::fillOnRegister, (void*)&data);
+    ASSERT_NE(notif, nullptr);
+
+    sleep(1);  // give us a chance to fail
+    AServiceManager_NotificationRegistration_delete(notif);
+
+    // checking after deleting to avoid needing a mutex over the data - otherwise
+    // in an environment w/ multiple threads, you would need to guard access
+    EXPECT_EQ(data.instance, "");
+    EXPECT_EQ(data.binder, nullptr);
+}
+
+TEST(NdkBinder, RegisterForServiceNotificationsExisting) {
+    ServiceData data;
+    auto* notif = AServiceManager_registerForServiceNotifications(
+            kExistingNonNdkService, ServiceData::fillOnRegister, (void*)&data);
+    ASSERT_NE(notif, nullptr);
+
+    sleep(1);  // give us a chance to fail
+    AServiceManager_NotificationRegistration_delete(notif);
+
+    // checking after deleting to avoid needing a mutex over the data - otherwise
+    // in an environment w/ multiple threads, you would need to guard access
+    EXPECT_EQ(data.instance, kExistingNonNdkService);
+    EXPECT_EQ(data.binder, ndk::SpAIBinder(AServiceManager_checkService(kExistingNonNdkService)));
+}
+
 TEST(NdkBinder, UnimplementedDump) {
-    sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
+    ndk::SpAIBinder binder;
+    sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName, binder.getR());
     ASSERT_NE(foo, nullptr);
-    AIBinder* binder = foo->getBinder();
-    EXPECT_EQ(OK, AIBinder_dump(binder, STDOUT_FILENO, nullptr, 0));
-    AIBinder_decStrong(binder);
+    EXPECT_EQ(OK, AIBinder_dump(binder.get(), STDOUT_FILENO, nullptr, 0));
 }
 
 TEST(NdkBinder, UnimplementedShell) {
@@ -281,6 +335,24 @@
     EXPECT_EQ(2, out);
 }
 
+TEST(NdkBinder, ReassociateBpBinderWithSameDescriptor) {
+    ndk::SpAIBinder binder;
+    sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName, binder.getR());
+
+    EXPECT_TRUE(AIBinder_isRemote(binder.get()));
+
+    EXPECT_TRUE(AIBinder_associateClass(binder.get(), IFoo::kClassDupe));
+}
+
+TEST(NdkBinder, CantHaveTwoLocalBinderClassesWithSameDescriptor) {
+    sp<IFoo> foo = sp<MyTestFoo>::make();
+    ndk::SpAIBinder binder(foo->getBinder());
+
+    EXPECT_FALSE(AIBinder_isRemote(binder.get()));
+
+    EXPECT_FALSE(AIBinder_associateClass(binder.get(), IFoo::kClassDupe));
+}
+
 TEST(NdkBinder, GetTestServiceStressTest) {
     // libbinder has some complicated logic to make sure only one instance of
     // ABpBinder is associated with each binder.
@@ -337,6 +409,16 @@
     EXPECT_EQ(isUpdatable, false);
 }
 
+TEST(NdkBinder, GetUpdatableViaApex) {
+    std::optional<std::string> updatableViaApex;
+    AServiceManager_getUpdatableApexName(
+            "android.hardware.light.ILights/default", &updatableViaApex,
+            [](const char* apexName, void* context) {
+                *static_cast<std::optional<std::string>*>(context) = apexName;
+            });
+    EXPECT_EQ(updatableViaApex, std::nullopt) << *updatableViaApex;
+}
+
 // This is too slow
 TEST(NdkBinder, CheckLazyServiceShutDown) {
     ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService));
@@ -492,18 +574,6 @@
     AIBinder_decStrong(binder);
 }
 
-class MyTestFoo : public IFoo {
-    binder_status_t doubleNumber(int32_t in, int32_t* out) override {
-        *out = 2 * in;
-        LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
-        return STATUS_OK;
-    }
-    binder_status_t die() override {
-        ADD_FAILURE() << "die called on local instance";
-        return STATUS_OK;
-    }
-};
-
 TEST(NdkBinder, SetInheritRt) {
     // functional test in binderLibTest
     sp<IFoo> foo = sp<MyTestFoo>::make();
@@ -544,7 +614,8 @@
     sp<IFoo> foo = new MyTestFoo;
     EXPECT_EQ(EX_NONE, foo->addService(kInstanceName));
 
-    sp<IFoo> getFoo = IFoo::getService(kInstanceName);
+    ndk::SpAIBinder binder;
+    sp<IFoo> getFoo = IFoo::getService(kInstanceName, binder.getR());
     EXPECT_EQ(foo.get(), getFoo.get());
 
     int32_t out;
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index a135796..afd414a 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -17,7 +17,6 @@
     rustlibs: [
         "libbinder_ndk_sys",
         "libdowncast_rs",
-        "liblazy_static",
         "liblibc",
     ],
     host_supported: true,
@@ -88,6 +87,7 @@
     min_sdk_version: "Tiramisu",
     lints: "none",
     clippy_lints: "none",
+    visibility: [":__subpackages__"],
 }
 
 rust_bindgen {
@@ -159,7 +159,6 @@
     rustlibs: [
         "libbinder_ndk_sys",
         "libdowncast_rs",
-        "liblazy_static",
         "liblibc",
     ],
 }
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 5ebc27f..afb73e9 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -19,7 +19,9 @@
         "libbinder_rpc_unstable_bindgen_sys",
         "libbinder_rs",
         "libdowncast_rs",
+        "libforeign_types",
         "liblibc",
+        "liblog_rust",
     ],
     apex_available: [
         "com.android.compos",
@@ -66,10 +68,13 @@
     visibility: [":__subpackages__"],
     source_stem: "bindings",
     bindgen_flags: [
+        "--size_t-is-usize",
         "--blocklist-type",
         "AIBinder",
         "--raw-line",
         "use binder_ndk_sys::AIBinder;",
+        "--rustified-enum",
+        "ARpcSession_FileDescriptorTransportMode",
     ],
     rustlibs: [
         "libbinder_ndk_sys",
diff --git a/libs/binder/rust/rpcbinder/src/client.rs b/libs/binder/rust/rpcbinder/src/client.rs
deleted file mode 100644
index 743800b..0000000
--- a/libs/binder/rust/rpcbinder/src/client.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-use binder::{unstable_api::new_spibinder, FromIBinder, SpIBinder, StatusCode, Strong};
-use std::os::{
-    raw::{c_int, c_void},
-    unix::io::RawFd,
-};
-
-/// Connects to an RPC Binder server over vsock.
-pub fn get_vsock_rpc_service(cid: u32, port: u32) -> Option<SpIBinder> {
-    // SAFETY: AIBinder returned by RpcClient has correct reference count, and the ownership can
-    // safely be taken by new_spibinder.
-    unsafe { new_spibinder(binder_rpc_unstable_bindgen::RpcClient(cid, port)) }
-}
-
-/// Connects to an RPC Binder server for a particular interface over vsock.
-pub fn get_vsock_rpc_interface<T: FromIBinder + ?Sized>(
-    cid: u32,
-    port: u32,
-) -> Result<Strong<T>, StatusCode> {
-    interface_cast(get_vsock_rpc_service(cid, port))
-}
-
-/// Connects to an RPC Binder server, using the given callback to get (and take ownership of)
-/// file descriptors already connected to it.
-pub fn get_preconnected_rpc_service(
-    mut request_fd: impl FnMut() -> Option<RawFd>,
-) -> Option<SpIBinder> {
-    // Double reference the factory because trait objects aren't FFI safe.
-    let mut request_fd_ref: RequestFd = &mut request_fd;
-    let param = &mut request_fd_ref as *mut RequestFd as *mut c_void;
-
-    // SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and the
-    // ownership can be safely taken by new_spibinder. RpcPreconnectedClient does not take ownership
-    // of param, only passing it to request_fd_wrapper.
-    unsafe {
-        new_spibinder(binder_rpc_unstable_bindgen::RpcPreconnectedClient(
-            Some(request_fd_wrapper),
-            param,
-        ))
-    }
-}
-
-type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>;
-
-unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
-    // SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
-    // BinderFdFactory reference, with param being a properly aligned non-null pointer to an
-    // initialized instance.
-    let request_fd_ptr = param as *mut RequestFd;
-    let request_fd = request_fd_ptr.as_mut().unwrap();
-    if let Some(fd) = request_fd() {
-        fd
-    } else {
-        -1
-    }
-}
-
-/// Connects to an RPC Binder server for a particular interface, using the given callback to get
-/// (and take ownership of) file descriptors already connected to it.
-pub fn get_preconnected_rpc_interface<T: FromIBinder + ?Sized>(
-    request_fd: impl FnMut() -> Option<RawFd>,
-) -> Result<Strong<T>, StatusCode> {
-    interface_cast(get_preconnected_rpc_service(request_fd))
-}
-
-fn interface_cast<T: FromIBinder + ?Sized>(
-    service: Option<SpIBinder>,
-) -> Result<Strong<T>, StatusCode> {
-    if let Some(service) = service {
-        FromIBinder::try_from(service)
-    } else {
-        Err(StatusCode::NAME_NOT_FOUND)
-    }
-}
diff --git a/libs/binder/rust/rpcbinder/src/lib.rs b/libs/binder/rust/rpcbinder/src/lib.rs
index a5eea61..a957385 100644
--- a/libs/binder/rust/rpcbinder/src/lib.rs
+++ b/libs/binder/rust/rpcbinder/src/lib.rs
@@ -16,11 +16,8 @@
 
 //! API for RPC Binder services.
 
-mod client;
 mod server;
+mod session;
 
-pub use client::{
-    get_preconnected_rpc_interface, get_preconnected_rpc_service, get_vsock_rpc_interface,
-    get_vsock_rpc_service,
-};
-pub use server::{run_rpc_server, run_rpc_server_with_factory};
+pub use server::{RpcServer, RpcServerRef};
+pub use session::{FileDescriptorTransportMode, RpcSession, RpcSessionRef};
diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs
index aeb23c6..761b306 100644
--- a/libs/binder/rust/rpcbinder/src/server.rs
+++ b/libs/binder/rust/rpcbinder/src/server.rs
@@ -14,111 +14,137 @@
  * limitations under the License.
  */
 
-use binder::{
-    unstable_api::{AIBinder, AsNative},
-    SpIBinder,
-};
-use std::{os::raw, ptr::null_mut};
+use crate::session::FileDescriptorTransportMode;
+use binder::{unstable_api::AsNative, SpIBinder};
+use binder_rpc_unstable_bindgen::ARpcServer;
+use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
+use std::ffi::CString;
+use std::io::{Error, ErrorKind};
+use std::os::unix::io::{IntoRawFd, OwnedFd};
 
-/// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
-/// port.
-///
-/// If and when the server is ready for connections (it is listening on the port), `on_ready` is
-/// called to allow appropriate action to be taken - e.g. to notify clients that they may now
-/// attempt to connect.
-///
-/// The current thread is joined to the binder thread pool to handle incoming messages.
-///
-/// Returns true if the server has shutdown normally, false if it failed in some way.
-pub fn run_rpc_server<F>(service: SpIBinder, port: u32, on_ready: F) -> bool
-where
-    F: FnOnce(),
-{
-    let mut ready_notifier = ReadyNotifier(Some(on_ready));
-    ready_notifier.run_server(service, port)
+foreign_type! {
+    type CType = binder_rpc_unstable_bindgen::ARpcServer;
+    fn drop = binder_rpc_unstable_bindgen::ARpcServer_free;
+
+    /// A type that represents a foreign instance of RpcServer.
+    #[derive(Debug)]
+    pub struct RpcServer;
+    /// A borrowed RpcServer.
+    pub struct RpcServerRef;
 }
 
-struct ReadyNotifier<F>(Option<F>)
-where
-    F: FnOnce();
+/// SAFETY - The opaque handle can be cloned freely.
+unsafe impl Send for RpcServer {}
+/// SAFETY - The underlying C++ RpcServer class is thread-safe.
+unsafe impl Sync for RpcServer {}
 
-impl<F> ReadyNotifier<F>
-where
-    F: FnOnce(),
-{
-    fn run_server(&mut self, mut service: SpIBinder, port: u32) -> bool {
+impl RpcServer {
+    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
+    /// vsock port. Only connections from the given CID are accepted.
+    ///
+    // Set `cid` to libc::VMADDR_CID_ANY to accept connections from any client.
+    // Set `cid` to libc::VMADDR_CID_LOCAL to only bind to the local vsock interface.
+    pub fn new_vsock(mut service: SpIBinder, cid: u32, port: u32) -> Result<RpcServer, Error> {
         let service = service.as_native_mut();
-        let param = self.as_void_ptr();
 
         // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
         // Plus the binder objects are threadsafe.
-        // RunRpcServerCallback does not retain a reference to `ready_callback` or `param`; it only
-        // uses them before it returns, which is during the lifetime of `self`.
         unsafe {
-            binder_rpc_unstable_bindgen::RunRpcServerCallback(
+            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newVsock(
+                service, cid, port,
+            ))
+        }
+    }
+
+    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
+    /// socket file name. The socket should be initialized in init.rc with the same name.
+    pub fn new_init_unix_domain(
+        mut service: SpIBinder,
+        socket_name: &str,
+    ) -> Result<RpcServer, Error> {
+        let socket_name = match CString::new(socket_name) {
+            Ok(s) => s,
+            Err(e) => {
+                log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
+                return Err(Error::from(ErrorKind::InvalidInput));
+            }
+        };
+        let service = service.as_native_mut();
+
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        unsafe {
+            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newInitUnixDomain(
                 service,
-                port,
-                Some(Self::ready_callback),
-                param,
+                socket_name.as_ptr(),
+            ))
+        }
+    }
+
+    /// Creates a binder RPC server that bootstraps sessions using an existing Unix domain socket
+    /// pair, with a given root IBinder object. Callers should create a pair of SOCK_STREAM Unix
+    /// domain sockets, pass one to the server and the other to the client. Multiple client session
+    /// can be created from the client end of the pair.
+    pub fn new_unix_domain_bootstrap(
+        mut service: SpIBinder,
+        bootstrap_fd: OwnedFd,
+    ) -> Result<RpcServer, Error> {
+        let service = service.as_native_mut();
+
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        // The server takes ownership of the bootstrap FD.
+        unsafe {
+            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newUnixDomainBootstrap(
+                service,
+                bootstrap_fd.into_raw_fd(),
+            ))
+        }
+    }
+
+    unsafe fn checked_from_ptr(ptr: *mut ARpcServer) -> Result<RpcServer, Error> {
+        if ptr.is_null() {
+            return Err(Error::new(ErrorKind::Other, "Failed to start server"));
+        }
+        Ok(RpcServer::from_ptr(ptr))
+    }
+}
+
+impl RpcServerRef {
+    /// Sets the list of file descriptor transport modes supported by this server.
+    pub fn set_supported_file_descriptor_transport_modes(
+        &self,
+        modes: &[FileDescriptorTransportMode],
+    ) {
+        // SAFETY - Does not keep the pointer after returning does, nor does it
+        // read past its boundary. Only passes the 'self' pointer as an opaque handle.
+        unsafe {
+            binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes(
+                self.as_ptr(),
+                modes.as_ptr(),
+                modes.len(),
             )
         }
     }
 
-    fn as_void_ptr(&mut self) -> *mut raw::c_void {
-        self as *mut _ as *mut raw::c_void
+    /// Starts a new background thread and calls join(). Returns immediately.
+    pub fn start(&self) {
+        unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) };
     }
 
-    unsafe extern "C" fn ready_callback(param: *mut raw::c_void) {
-        // SAFETY: This is only ever called by `RunRpcServerCallback`, within the lifetime of the
-        // `ReadyNotifier`, with `param` taking the value returned by `as_void_ptr` (so a properly
-        // aligned non-null pointer to an initialized instance).
-        let ready_notifier = param as *mut Self;
-        ready_notifier.as_mut().unwrap().notify()
+    /// Joins the RpcServer thread. The call blocks until the server terminates.
+    /// This must be called from exactly one thread.
+    pub fn join(&self) {
+        unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) };
     }
 
-    fn notify(&mut self) {
-        if let Some(on_ready) = self.0.take() {
-            on_ready();
+    /// Shuts down the running RpcServer. Can be called multiple times and from
+    /// multiple threads. Called automatically during drop().
+    pub fn shutdown(&self) -> Result<(), Error> {
+        if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } {
+            Ok(())
+        } else {
+            Err(Error::from(ErrorKind::UnexpectedEof))
         }
     }
 }
-
-type RpcServerFactoryRef<'a> = &'a mut (dyn FnMut(u32) -> Option<SpIBinder> + Send + Sync);
-
-/// Runs a binder RPC server, using the given factory function to construct a binder service
-/// implementation for each connection.
-///
-/// The current thread is joined to the binder thread pool to handle incoming messages.
-///
-/// Returns true if the server has shutdown normally, false if it failed in some way.
-pub fn run_rpc_server_with_factory(
-    port: u32,
-    mut factory: impl FnMut(u32) -> Option<SpIBinder> + Send + Sync,
-) -> bool {
-    // Double reference the factory because trait objects aren't FFI safe.
-    // NB: The type annotation is necessary to ensure that we have a `dyn` rather than an `impl`.
-    let mut factory_ref: RpcServerFactoryRef = &mut factory;
-    let context = &mut factory_ref as *mut RpcServerFactoryRef as *mut raw::c_void;
-
-    // SAFETY: `factory_wrapper` is only ever called by `RunRpcServerWithFactory`, with context
-    // taking the pointer value above (so a properly aligned non-null pointer to an initialized
-    // `RpcServerFactoryRef`), within the lifetime of `factory_ref` (i.e. no more calls will be made
-    // after `RunRpcServerWithFactory` returns).
-    unsafe {
-        binder_rpc_unstable_bindgen::RunRpcServerWithFactory(Some(factory_wrapper), context, port)
-    }
-}
-
-unsafe extern "C" fn factory_wrapper(cid: u32, context: *mut raw::c_void) -> *mut AIBinder {
-    // SAFETY: `context` was created from an `&mut RpcServerFactoryRef` by
-    // `run_rpc_server_with_factory`, and we are still within the lifetime of the value it is
-    // pointing to.
-    let factory_ptr = context as *mut RpcServerFactoryRef;
-    let factory = factory_ptr.as_mut().unwrap();
-
-    if let Some(mut service) = factory(cid) {
-        service.as_native_mut()
-    } else {
-        null_mut()
-    }
-}
diff --git a/libs/binder/rust/rpcbinder/src/session.rs b/libs/binder/rust/rpcbinder/src/session.rs
new file mode 100644
index 0000000..62fedb1
--- /dev/null
+++ b/libs/binder/rust/rpcbinder/src/session.rs
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use binder::unstable_api::new_spibinder;
+use binder::{FromIBinder, SpIBinder, StatusCode, Strong};
+use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
+use std::ffi::CString;
+use std::os::{
+    raw::{c_int, c_void},
+    unix::io::{AsRawFd, BorrowedFd, RawFd},
+};
+
+pub use binder_rpc_unstable_bindgen::ARpcSession_FileDescriptorTransportMode as FileDescriptorTransportMode;
+
+foreign_type! {
+    type CType = binder_rpc_unstable_bindgen::ARpcSession;
+    fn drop = binder_rpc_unstable_bindgen::ARpcSession_free;
+
+    /// A type that represents a foreign instance of RpcSession.
+    #[derive(Debug)]
+    pub struct RpcSession;
+    /// A borrowed RpcSession.
+    pub struct RpcSessionRef;
+}
+
+/// SAFETY - The opaque handle can be cloned freely.
+unsafe impl Send for RpcSession {}
+/// SAFETY - The underlying C++ RpcSession class is thread-safe.
+unsafe impl Sync for RpcSession {}
+
+impl RpcSession {
+    /// Allocates a new RpcSession object.
+    pub fn new() -> RpcSession {
+        // SAFETY - Takes ownership of the returned handle, which has correct refcount.
+        unsafe { RpcSession::from_ptr(binder_rpc_unstable_bindgen::ARpcSession_new()) }
+    }
+}
+
+impl Default for RpcSession {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl RpcSessionRef {
+    /// Sets the file descriptor transport mode for this session.
+    pub fn set_file_descriptor_transport_mode(&self, mode: FileDescriptorTransportMode) {
+        // SAFETY - Only passes the 'self' pointer as an opaque handle.
+        unsafe {
+            binder_rpc_unstable_bindgen::ARpcSession_setFileDescriptorTransportMode(
+                self.as_ptr(),
+                mode,
+            )
+        };
+    }
+
+    /// Sets the maximum number of incoming threads.
+    pub fn set_max_incoming_threads(&self, threads: usize) {
+        // SAFETY - Only passes the 'self' pointer as an opaque handle.
+        unsafe {
+            binder_rpc_unstable_bindgen::ARpcSession_setMaxIncomingThreads(self.as_ptr(), threads)
+        };
+    }
+
+    /// Sets the maximum number of outgoing threads.
+    pub fn set_max_outgoing_threads(&self, threads: usize) {
+        // SAFETY - Only passes the 'self' pointer as an opaque handle.
+        unsafe {
+            binder_rpc_unstable_bindgen::ARpcSession_setMaxOutgoingThreads(self.as_ptr(), threads)
+        };
+    }
+
+    /// Connects to an RPC Binder server over vsock for a particular interface.
+    pub fn setup_vsock_client<T: FromIBinder + ?Sized>(
+        &self,
+        cid: u32,
+        port: u32,
+    ) -> Result<Strong<T>, StatusCode> {
+        // SAFETY: AIBinder returned by ARpcSession_setupVsockClient has correct
+        // reference count, and the ownership can safely be taken by new_spibinder.
+        let service = unsafe {
+            new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupVsockClient(
+                self.as_ptr(),
+                cid,
+                port,
+            ))
+        };
+        Self::get_interface(service)
+    }
+
+    /// Connects to an RPC Binder server over a names Unix Domain Socket for
+    /// a particular interface.
+    pub fn setup_unix_domain_client<T: FromIBinder + ?Sized>(
+        &self,
+        socket_name: &str,
+    ) -> Result<Strong<T>, StatusCode> {
+        let socket_name = match CString::new(socket_name) {
+            Ok(s) => s,
+            Err(e) => {
+                log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
+                return Err(StatusCode::NAME_NOT_FOUND);
+            }
+        };
+
+        // SAFETY: AIBinder returned by ARpcSession_setupUnixDomainClient has correct
+        // reference count, and the ownership can safely be taken by new_spibinder.
+        let service = unsafe {
+            new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupUnixDomainClient(
+                self.as_ptr(),
+                socket_name.as_ptr(),
+            ))
+        };
+        Self::get_interface(service)
+    }
+
+    /// Connects to an RPC Binder server over a bootstrap Unix Domain Socket
+    /// for a particular interface.
+    pub fn setup_unix_domain_bootstrap_client<T: FromIBinder + ?Sized>(
+        &self,
+        bootstrap_fd: BorrowedFd,
+    ) -> Result<Strong<T>, StatusCode> {
+        // SAFETY: ARpcSession_setupUnixDomainBootstrapClient does not take
+        // ownership of bootstrap_fd. The returned AIBinder has correct
+        // reference count, and the ownership can safely be taken by new_spibinder.
+        let service = unsafe {
+            new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupUnixDomainBootstrapClient(
+                self.as_ptr(),
+                bootstrap_fd.as_raw_fd(),
+            ))
+        };
+        Self::get_interface(service)
+    }
+
+    /// Connects to an RPC Binder server, using the given callback to get (and
+    /// take ownership of) file descriptors already connected to it.
+    pub fn setup_preconnected_client<T: FromIBinder + ?Sized>(
+        &self,
+        mut request_fd: impl FnMut() -> Option<RawFd>,
+    ) -> Result<Strong<T>, StatusCode> {
+        // Double reference the factory because trait objects aren't FFI safe.
+        let mut request_fd_ref: RequestFd = &mut request_fd;
+        let param = &mut request_fd_ref as *mut RequestFd as *mut c_void;
+
+        // SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and the
+        // ownership can be safely taken by new_spibinder. RpcPreconnectedClient does not take ownership
+        // of param, only passing it to request_fd_wrapper.
+        let service = unsafe {
+            new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupPreconnectedClient(
+                self.as_ptr(),
+                Some(request_fd_wrapper),
+                param,
+            ))
+        };
+        Self::get_interface(service)
+    }
+
+    fn get_interface<T: FromIBinder + ?Sized>(
+        service: Option<SpIBinder>,
+    ) -> Result<Strong<T>, StatusCode> {
+        if let Some(service) = service {
+            FromIBinder::try_from(service)
+        } else {
+            Err(StatusCode::NAME_NOT_FOUND)
+        }
+    }
+}
+
+type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>;
+
+unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
+    // SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
+    // BinderFdFactory reference, with param being a properly aligned non-null pointer to an
+    // initialized instance.
+    let request_fd_ptr = param as *mut RequestFd;
+    let request_fd = request_fd_ptr.as_mut().unwrap();
+    request_fd().unwrap_or(-1)
+}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 195d9ac..a0e61d9 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -148,4 +148,5 @@
     pub use crate::binder::AsNative;
     pub use crate::proxy::unstable_api::new_spibinder;
     pub use crate::sys::AIBinder;
+    pub use crate::sys::AParcel;
 }
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index dee05d0..6f686fb 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -22,7 +22,6 @@
 use crate::proxy::SpIBinder;
 use crate::sys;
 
-use lazy_static::lazy_static;
 use std::convert::TryFrom;
 use std::ffi::{c_void, CStr, CString};
 use std::fs::File;
@@ -508,10 +507,8 @@
     _private: (),
 }
 
-lazy_static! {
-    // Count of how many LazyServiceGuard objects are in existence.
-    static ref GUARD_COUNT: Mutex<u64> = Mutex::new(0);
-}
+// Count of how many LazyServiceGuard objects are in existence.
+static GUARD_COUNT: Mutex<u64> = Mutex::new(0);
 
 impl LazyServiceGuard {
     /// Create a new LazyServiceGuard to prevent the service manager prematurely killing this
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 4e10fa9..ca2cedc 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -502,7 +502,7 @@
         let instances = binder::get_declared_instances("android.hardware.light.ILights")
             .expect("Could not get declared instances");
 
-        let expected_defaults = if has_lights { 1 } else { 0 };
+        let expected_defaults = usize::from(has_lights);
         assert_eq!(expected_defaults, instances.iter().filter(|i| i.as_str() == "default").count());
     }
 
diff --git a/libs/binder/rust/tests/parcel_fuzzer/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/Android.bp
new file mode 100644
index 0000000..df8a2af
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/Android.bp
@@ -0,0 +1,27 @@
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+rust_fuzz {
+    name: "parcel_fuzzer_rs",
+    srcs: [
+        "parcel_fuzzer.rs",
+    ],
+    rustlibs: [
+        "libarbitrary",
+        "libnum_traits",
+        "libbinder_rs",
+        "libbinder_random_parcel_rs",
+        "binderReadParcelIface-rust",
+    ],
+
+    fuzz_config: {
+        cc: [
+            "waghpawan@google.com",
+            "smoreland@google.com",
+        ],
+        // hotlist "AIDL fuzzers bugs" on buganizer
+        hotlists: ["4637097"],
+    },
+}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
new file mode 100644
index 0000000..c5c7719
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#![allow(missing_docs)]
+#![no_main]
+
+#[macro_use]
+extern crate libfuzzer_sys;
+
+mod read_utils;
+
+use crate::read_utils::READ_FUNCS;
+use binder::binder_impl::{
+    Binder, BorrowedParcel, IBinderInternal, Parcel, Stability, TransactionCode,
+};
+use binder::{
+    declare_binder_interface, BinderFeatures, Interface, Parcelable, ParcelableHolder, SpIBinder,
+    StatusCode,
+};
+use binder_random_parcel_rs::create_random_parcel;
+use libfuzzer_sys::arbitrary::Arbitrary;
+
+#[derive(Arbitrary, Debug)]
+enum ReadOperation {
+    SetDataPosition { pos: i32 },
+    GetDataSize,
+    ReadParcelableHolder { is_vintf: bool },
+    ReadBasicTypes { instructions: Vec<usize> },
+}
+
+#[derive(Arbitrary, Debug)]
+enum Operation<'a> {
+    Transact { code: u32, flag: u32, data: &'a [u8] },
+    Append { start: i32, len: i32, data1: &'a [u8], data2: &'a [u8], append_all: bool },
+    Read { read_operations: Vec<ReadOperation>, data: &'a [u8] },
+}
+
+/// Interface to fuzz transact with random parcel
+pub trait BinderTransactTest: Interface {}
+
+declare_binder_interface! {
+    BinderTransactTest["Binder_Transact_Test"] {
+        native: BnBinderTransactTest(on_transact),
+        proxy: BpBinderTransactTest,
+    }
+}
+
+impl BinderTransactTest for Binder<BnBinderTransactTest> {}
+
+impl BinderTransactTest for BpBinderTransactTest {}
+
+impl BinderTransactTest for () {}
+
+fn on_transact(
+    _service: &dyn BinderTransactTest,
+    _code: TransactionCode,
+    _parcel: &BorrowedParcel<'_>,
+    _reply: &mut BorrowedParcel<'_>,
+) -> Result<(), StatusCode> {
+    Err(StatusCode::UNKNOWN_ERROR)
+}
+
+fn do_transact(code: u32, data: &[u8], flag: u32) {
+    let p: Parcel = create_random_parcel(data);
+    let spibinder: Option<SpIBinder> =
+        Some(BnBinderTransactTest::new_binder((), BinderFeatures::default()).as_binder());
+    let _reply = spibinder.submit_transact(code, p, flag);
+}
+
+fn do_append_fuzz(start: i32, len: i32, data1: &[u8], data2: &[u8], append_all: bool) {
+    let mut p1 = create_random_parcel(data1);
+    let p2 = create_random_parcel(data2);
+
+    // Fuzz both append methods
+    if append_all {
+        match p1.append_all_from(&p2) {
+            Ok(result) => result,
+            Err(e) => {
+                println!("Error occurred while appending a parcel using append_all_from: {:?}", e)
+            }
+        }
+    } else {
+        match p1.append_from(&p2, start, len) {
+            Ok(result) => result,
+            Err(e) => {
+                println!("Error occurred while appending a parcel using append_from: {:?}", e)
+            }
+        }
+    };
+}
+
+fn do_read_fuzz(read_operations: Vec<ReadOperation>, data: &[u8]) {
+    let parcel = create_random_parcel(data);
+
+    for operation in read_operations {
+        match operation {
+            ReadOperation::SetDataPosition { pos } => {
+                unsafe {
+                    // Safety: Safe if pos is less than current size of the parcel.
+                    // It relies on C++ code for bound checks
+                    match parcel.set_data_position(pos) {
+                        Ok(result) => result,
+                        Err(e) => println!("error occurred while setting data position: {:?}", e),
+                    }
+                }
+            }
+
+            ReadOperation::GetDataSize => {
+                let data_size = parcel.get_data_size();
+                println!("data size from parcel: {:?}", data_size);
+            }
+
+            ReadOperation::ReadParcelableHolder { is_vintf } => {
+                let stability = if is_vintf { Stability::Vintf } else { Stability::Local };
+                let mut holder: ParcelableHolder = ParcelableHolder::new(stability);
+                match holder.read_from_parcel(parcel.borrowed_ref()) {
+                    Ok(result) => result,
+                    Err(err) => {
+                        println!("error occurred while reading from parcel: {:?}", err)
+                    }
+                }
+            }
+
+            ReadOperation::ReadBasicTypes { instructions } => {
+                for instruction in instructions.iter() {
+                    let read_index = instruction % READ_FUNCS.len();
+                    READ_FUNCS[read_index](parcel.borrowed_ref());
+                }
+            }
+        }
+    }
+}
+
+fuzz_target!(|operation: Operation| {
+    match operation {
+        Operation::Transact { code, flag, data } => {
+            do_transact(code, data, flag);
+        }
+
+        Operation::Append { start, len, data1, data2, append_all } => {
+            do_append_fuzz(start, len, data1, data2, append_all);
+        }
+
+        Operation::Read { read_operations, data } => {
+            do_read_fuzz(read_operations, data);
+        }
+    }
+});
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp
new file mode 100644
index 0000000..43a3094
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp
@@ -0,0 +1,52 @@
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+rust_bindgen {
+    name: "libbinder_random_parcel_bindgen",
+    crate_name: "binder_random_parcel_bindgen",
+    host_supported: true,
+    wrapper_src: "wrappers/RandomParcelWrapper.hpp",
+    source_stem: "bindings",
+    visibility: [":__subpackages__"],
+    bindgen_flags: [
+        "--size_t-is-usize",
+        "--allowlist-function",
+        "createRandomParcel",
+        "--allowlist-function",
+        "fuzzRustService",
+    ],
+    shared_libs: [
+        "libc++",
+        "libbinder_ndk",
+    ],
+    rustlibs: [
+        "libbinder_rs",
+    ],
+}
+
+rust_library {
+    name: "libbinder_random_parcel_rs",
+    crate_name: "binder_random_parcel_rs",
+    host_supported: true,
+    srcs: [
+        "src/lib.rs",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+        "libcutils",
+        "libc++",
+    ],
+    static_libs: [
+        "libbinder_create_parcel",
+        "libbinder_random_parcel",
+    ],
+    rustlibs: [
+        "libbinder_rs",
+        "libbinder_random_parcel_bindgen",
+    ],
+    lints: "none",
+    clippy_lints: "none",
+}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp
new file mode 100644
index 0000000..5cb406a
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp
@@ -0,0 +1,35 @@
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+aidl_interface {
+    name: "testServiceInterface",
+    srcs: ["ITestService.aidl"],
+    unstable: true,
+    backend: {
+        rust: {
+            enabled: true,
+        },
+    },
+}
+
+rust_fuzz {
+    name: "example_service_fuzzer",
+    srcs: [
+        "service_fuzzer.rs",
+    ],
+    rustlibs: [
+        "libbinder_rs",
+        "libbinder_random_parcel_rs",
+        "testServiceInterface-rust",
+    ],
+    fuzz_config: {
+        cc: [
+            "waghpawan@google.com",
+            "smoreland@google.com",
+        ],
+        // hotlist "AIDL fuzzers bugs" on buganizer
+        hotlists: ["4637097"],
+    },
+}
diff --git a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/ITestService.aidl
similarity index 89%
copy from libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
copy to libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/ITestService.aidl
index d62891b..8ce6558 100644
--- a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/ITestService.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-parcelable SingleDataParcelable{
-   int data;
+interface ITestService {
+    boolean repeatData(boolean token);
 }
\ No newline at end of file
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/service_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/service_fuzzer.rs
new file mode 100644
index 0000000..a427f28
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/service_fuzzer.rs
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#![allow(missing_docs)]
+#![no_main]
+#[macro_use]
+extern crate libfuzzer_sys;
+
+use binder::{self, BinderFeatures, Interface};
+use binder_random_parcel_rs::fuzz_service;
+use testServiceInterface::aidl::ITestService::{self, BnTestService};
+
+struct TestService;
+
+impl Interface for TestService {}
+
+impl ITestService::ITestService for TestService {
+    fn repeatData(&self, token: bool) -> binder::Result<bool> {
+        Ok(token)
+    }
+}
+
+fuzz_target!(|data: &[u8]| {
+    let service = BnTestService::new_binder(TestService, BinderFeatures::default());
+    fuzz_service(&mut service.as_binder(), data);
+});
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs
new file mode 100644
index 0000000..1bbd674
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use binder::binder_impl::Parcel;
+use binder::unstable_api::{AParcel, AsNative};
+use binder::SpIBinder;
+use binder_random_parcel_bindgen::{createRandomParcel, fuzzRustService};
+use std::os::raw::c_void;
+
+/// This API creates a random parcel to be used by fuzzers
+pub fn create_random_parcel(fuzzer_data: &[u8]) -> Parcel {
+    let mut parcel = Parcel::new();
+    let aparcel_ptr: *mut AParcel = parcel.as_native_mut();
+    let ptr = aparcel_ptr as *mut c_void;
+    unsafe {
+        // Safety: `Parcel::as_native_mut` and `slice::as_ptr` always
+        // return valid pointers.
+        createRandomParcel(ptr, fuzzer_data.as_ptr(), fuzzer_data.len());
+    }
+    parcel
+}
+
+/// This API automatically fuzzes provided service
+pub fn fuzz_service(binder: &mut SpIBinder, fuzzer_data: &[u8]) {
+    let ptr = binder.as_native_mut() as *mut c_void;
+    unsafe {
+        // Safety: `SpIBinder::as_native_mut` and `slice::as_ptr` always
+        // return valid pointers.
+        fuzzRustService(ptr, fuzzer_data.as_ptr(), fuzzer_data.len());
+    }
+}
diff --git a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
similarity index 64%
copy from libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
copy to libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
index fc2542b..831bd56 100644
--- a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp
@@ -13,12 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <cstdint>
+#include <cstddef>
 
-parcelable GenericDataParcelable {
-    int data;
-    float majorVersion;
-    float minorVersion;
-    IBinder binder;
-    ParcelFileDescriptor fileDescriptor;
-    int[] array;
+extern "C" {
+    // This API is used by rust to fill random parcel.
+    void createRandomParcel(void* aParcel, const uint8_t* data, size_t len);
+
+    // This API is used by fuzzers to automatically fuzz aidl services
+    void fuzzRustService(void* binder, const uint8_t* data, size_t len);
 }
\ No newline at end of file
diff --git a/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs
new file mode 100644
index 0000000..a2d48b6
--- /dev/null
+++ b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use binder::binder_impl::BorrowedParcel;
+use binder::{ParcelFileDescriptor, Parcelable, SpIBinder};
+use binderReadParcelIface::aidl::parcelables::EmptyParcelable::EmptyParcelable;
+use binderReadParcelIface::aidl::parcelables::GenericDataParcelable::GenericDataParcelable;
+use binderReadParcelIface::aidl::parcelables::SingleDataParcelable::SingleDataParcelable;
+
+macro_rules! read_parcel_interface {
+    ($data_type:ty) => {
+        |parcel: &BorrowedParcel<'_>| {
+            let _res = parcel.read::<$data_type>();
+        }
+    };
+}
+
+#[derive(Debug, Default)]
+pub struct SomeParcelable {
+    pub data: i32,
+}
+
+impl binder::Parcelable for SomeParcelable {
+    fn write_to_parcel(
+        &self,
+        parcel: &mut binder::binder_impl::BorrowedParcel,
+    ) -> std::result::Result<(), binder::StatusCode> {
+        parcel.sized_write(|subparcel| subparcel.write(&self.data))
+    }
+
+    fn read_from_parcel(
+        &mut self,
+        parcel: &binder::binder_impl::BorrowedParcel,
+    ) -> std::result::Result<(), binder::StatusCode> {
+        parcel.sized_read(|subparcel| match subparcel.read() {
+            Ok(result) => {
+                self.data = result;
+                Ok(())
+            }
+            Err(e) => Err(e),
+        })
+    }
+}
+
+binder::impl_deserialize_for_parcelable!(SomeParcelable);
+
+pub const READ_FUNCS: &[fn(&BorrowedParcel<'_>)] = &[
+    //read basic types
+    read_parcel_interface!(bool),
+    read_parcel_interface!(i8),
+    read_parcel_interface!(i32),
+    read_parcel_interface!(i64),
+    read_parcel_interface!(f32),
+    read_parcel_interface!(f64),
+    read_parcel_interface!(u16),
+    read_parcel_interface!(u32),
+    read_parcel_interface!(u64),
+    read_parcel_interface!(String),
+    //read vec of basic types
+    read_parcel_interface!(Vec<i8>),
+    read_parcel_interface!(Vec<i32>),
+    read_parcel_interface!(Vec<i64>),
+    read_parcel_interface!(Vec<f32>),
+    read_parcel_interface!(Vec<f64>),
+    read_parcel_interface!(Vec<u16>),
+    read_parcel_interface!(Vec<u32>),
+    read_parcel_interface!(Vec<u64>),
+    read_parcel_interface!(Vec<String>),
+    read_parcel_interface!(Option<Vec<i8>>),
+    read_parcel_interface!(Option<Vec<i32>>),
+    read_parcel_interface!(Option<Vec<i64>>),
+    read_parcel_interface!(Option<Vec<f32>>),
+    read_parcel_interface!(Option<Vec<f64>>),
+    read_parcel_interface!(Option<Vec<u16>>),
+    read_parcel_interface!(Option<Vec<u32>>),
+    read_parcel_interface!(Option<Vec<u64>>),
+    read_parcel_interface!(Option<Vec<String>>),
+    read_parcel_interface!(ParcelFileDescriptor),
+    read_parcel_interface!(Vec<Option<ParcelFileDescriptor>>),
+    read_parcel_interface!(Option<Vec<ParcelFileDescriptor>>),
+    read_parcel_interface!(Option<Vec<Option<ParcelFileDescriptor>>>),
+    read_parcel_interface!(SpIBinder),
+    read_parcel_interface!(Vec<Option<SpIBinder>>),
+    read_parcel_interface!(Option<Vec<SpIBinder>>),
+    read_parcel_interface!(Option<Vec<Option<SpIBinder>>>),
+    read_parcel_interface!(SomeParcelable),
+    read_parcel_interface!(Vec<Option<SomeParcelable>>),
+    read_parcel_interface!(Option<Vec<SomeParcelable>>),
+    read_parcel_interface!(Option<Vec<Option<SomeParcelable>>>),
+    // Fuzz read_from_parcel for AIDL generated parcelables
+    |parcel| {
+        let mut empty_parcelable: EmptyParcelable = EmptyParcelable::default();
+        match empty_parcelable.read_from_parcel(parcel) {
+            Ok(result) => result,
+            Err(e) => {
+                println!("EmptyParcelable: error occurred while reading from a parcel: {:?}", e)
+            }
+        }
+    },
+    |parcel| {
+        let mut single_parcelable: SingleDataParcelable = SingleDataParcelable::default();
+        match single_parcelable.read_from_parcel(parcel) {
+            Ok(result) => result,
+            Err(e) => println!(
+                "SingleDataParcelable: error occurred while reading from a parcel: {:?}",
+                e
+            ),
+        }
+    },
+    |parcel| {
+        let mut generic_parcelable: GenericDataParcelable = GenericDataParcelable::default();
+        match generic_parcelable.read_from_parcel(parcel) {
+            Ok(result) => result,
+            Err(e) => println!(
+                "GenericDataParcelable: error occurred while reading from a parcel: {:?}",
+                e
+            ),
+        }
+    },
+];
diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp
index 777f3c9..692cc95 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -156,6 +156,10 @@
                                              std::optional<std::string>* _aidl_return) override {
         return mImpl->updatableViaApex(name, _aidl_return);
     }
+    android::binder::Status getUpdatableNames(const std::string& apexName,
+                                              std::vector<std::string>* _aidl_return) override {
+        return mImpl->getUpdatableNames(apexName, _aidl_return);
+    }
     android::binder::Status getConnectionInfo(
             const std::string& name,
             std::optional<android::os::ConnectionInfo>* _aidl_return) override {
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 92d132f..a999d59 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -232,6 +232,7 @@
     srcs: [
         "binderRpcTest.cpp",
         "binderRpcTestCommon.cpp",
+        "binderRpcUniversalTests.cpp",
     ],
 
     test_suites: ["general-tests"],
@@ -722,5 +723,7 @@
             "smoreland@google.com",
             "waghpawan@google.com",
         ],
+        // Adds bugs to hotlist "AIDL fuzzers bugs" on buganizer
+        hotlists: ["4637097"],
     },
 }
diff --git a/libs/binder/tests/BinderRpcTestServerConfig.aidl b/libs/binder/tests/BinderRpcTestServerConfig.aidl
index 4cdeac4..b2e0ef2 100644
--- a/libs/binder/tests/BinderRpcTestServerConfig.aidl
+++ b/libs/binder/tests/BinderRpcTestServerConfig.aidl
@@ -21,6 +21,6 @@
     int rpcSecurity;
     int serverVersion;
     int vsockPort;
-    int unixBootstrapFd; // Inherited from parent
+    int socketFd; // Inherited from the parent process.
     @utf8InCpp String addr;
 }
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
index 55a3916..6a6e008 100644
--- a/libs/binder/tests/binderAllocationLimits.cpp
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -172,6 +172,24 @@
     a_binder->pingBinder();
 }
 
+TEST(BinderAllocation, InterfaceDescriptorTransaction) {
+    sp<IBinder> a_binder = GetRemoteBinder();
+
+    size_t mallocs = 0;
+    const auto on_malloc = OnMalloc([&](size_t bytes) {
+        mallocs++;
+        // Happens to be SM package length. We could switch to forking
+        // and registering our own service if it became an issue.
+        EXPECT_EQ(bytes, 78);
+    });
+
+    a_binder->getInterfaceDescriptor();
+    a_binder->getInterfaceDescriptor();
+    a_binder->getInterfaceDescriptor();
+
+    EXPECT_EQ(mallocs, 1);
+}
+
 TEST(BinderAllocation, SmallTransaction) {
     String16 empty_descriptor = String16("");
     sp<IServiceManager> manager = defaultServiceManager();
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 25b524f..f7498c4 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -120,6 +120,7 @@
     BINDER_LIB_TEST_CAN_GET_SID,
     BINDER_LIB_TEST_GET_MAX_THREAD_COUNT,
     BINDER_LIB_TEST_SET_MAX_THREAD_COUNT,
+    BINDER_LIB_TEST_IS_THREADPOOL_STARTED,
     BINDER_LIB_TEST_LOCK_UNLOCK,
     BINDER_LIB_TEST_PROCESS_LOCK,
     BINDER_LIB_TEST_UNLOCK_AFTER_MS,
@@ -1383,6 +1384,14 @@
     EXPECT_EQ(replyi, kKernelThreads + 1);
 }
 
+TEST_F(BinderLibTest, ThreadPoolStarted) {
+    Parcel data, reply;
+    sp<IBinder> server = addServer();
+    ASSERT_TRUE(server != nullptr);
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_IS_THREADPOOL_STARTED, data, &reply), NO_ERROR);
+    EXPECT_TRUE(reply.readBool());
+}
+
 size_t epochMillis() {
     using std::chrono::duration_cast;
     using std::chrono::milliseconds;
@@ -1849,6 +1858,10 @@
                 reply->writeInt32(ProcessState::self()->getThreadPoolMaxTotalThreadCount());
                 return NO_ERROR;
             }
+            case BINDER_LIB_TEST_IS_THREADPOOL_STARTED: {
+                reply->writeBool(ProcessState::self()->isThreadPoolStarted());
+                return NO_ERROR;
+            }
             case BINDER_LIB_TEST_PROCESS_LOCK: {
                 m_blockMutex.lock();
                 return NO_ERROR;
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 7294305..739c217 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -15,7 +15,6 @@
  */
 
 #include <android-base/stringprintf.h>
-#include <gtest/gtest.h>
 
 #include <chrono>
 #include <cstdlib>
@@ -29,6 +28,7 @@
 #include <sys/socket.h>
 
 #include "binderRpcTestCommon.h"
+#include "binderRpcTestFixture.h"
 
 using namespace std::chrono_literals;
 using namespace std::placeholders;
@@ -44,37 +44,6 @@
 constexpr bool kEnableSharedLibs = true;
 #endif
 
-static_assert(RPC_WIRE_PROTOCOL_VERSION + 1 == RPC_WIRE_PROTOCOL_VERSION_NEXT ||
-              RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
-
-TEST(BinderRpcParcel, EntireParcelFormatted) {
-    Parcel p;
-    p.writeInt32(3);
-
-    EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "format must be set before data is written");
-}
-
-TEST(BinderRpc, CannotUseNextWireVersion) {
-    auto session = RpcSession::make();
-    EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT));
-    EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 1));
-    EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 2));
-    EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 15));
-}
-
-TEST(BinderRpc, CanUseExperimentalWireVersion) {
-    auto session = RpcSession::make();
-    EXPECT_TRUE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL));
-}
-
-using android::binder::Status;
-
-#define EXPECT_OK(status)                 \
-    do {                                  \
-        Status stat = (status);           \
-        EXPECT_TRUE(stat.isOk()) << stat; \
-    } while (false)
-
 static std::string WaitStatusToString(int wstatus) {
     if (WIFEXITED(wstatus)) {
         return base::StringPrintf("exit status %d", WEXITSTATUS(wstatus));
@@ -92,7 +61,15 @@
 
 class Process {
 public:
-    Process(Process&&) = default;
+    Process(Process&& other)
+          : mCustomExitStatusCheck(std::move(other.mCustomExitStatusCheck)),
+            mReadEnd(std::move(other.mReadEnd)),
+            mWriteEnd(std::move(other.mWriteEnd)) {
+        // The default move constructor doesn't clear mPid after moving it,
+        // which we need to do because the destructor checks for mPid!=0
+        mPid = other.mPid;
+        other.mPid = 0;
+    }
     Process(const std::function<void(android::base::borrowed_fd /* writeEnd */,
                                      android::base::borrowed_fd /* readEnd */)>& f) {
         android::base::unique_fd childWriteEnd;
@@ -152,21 +129,26 @@
     return vsockPort++;
 }
 
-struct ProcessSession {
+static base::unique_fd initUnixSocket(std::string addr) {
+    auto socket_addr = UnixSocketAddress(addr.c_str());
+    base::unique_fd fd(
+            TEMP_FAILURE_RETRY(socket(socket_addr.addr()->sa_family, SOCK_STREAM, AF_UNIX)));
+    CHECK(fd.ok());
+    CHECK_EQ(0, TEMP_FAILURE_RETRY(bind(fd.get(), socket_addr.addr(), socket_addr.addrSize())));
+    return fd;
+}
+
+// Destructors need to be defined, even if pure virtual
+ProcessSession::~ProcessSession() {}
+
+class LinuxProcessSession : public ProcessSession {
+public:
     // reference to process hosting a socket server
     Process host;
 
-    struct SessionInfo {
-        sp<RpcSession> session;
-        sp<IBinder> root;
-    };
-
-    // client session objects associated with other process
-    // each one represents a separate session
-    std::vector<SessionInfo> sessions;
-
-    ProcessSession(ProcessSession&&) = default;
-    ~ProcessSession() {
+    LinuxProcessSession(LinuxProcessSession&&) = default;
+    LinuxProcessSession(Process&& host) : host(std::move(host)) {}
+    ~LinuxProcessSession() override {
         for (auto& session : sessions) {
             session.root = nullptr;
         }
@@ -197,46 +179,12 @@
             }
         }
     }
-};
 
-// Process session where the process hosts IBinderRpcTest, the server used
-// for most testing here
-struct BinderRpcTestProcessSession {
-    ProcessSession proc;
-
-    // pre-fetched root object (for first session)
-    sp<IBinder> rootBinder;
-
-    // pre-casted root object (for first session)
-    sp<IBinderRpcTest> rootIface;
-
-    // whether session should be invalidated by end of run
-    bool expectAlreadyShutdown = false;
-
-    BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default;
-    ~BinderRpcTestProcessSession() {
-        if (!expectAlreadyShutdown) {
-            EXPECT_NE(nullptr, rootIface);
-            if (rootIface == nullptr) return;
-
-            std::vector<int32_t> remoteCounts;
-            // calling over any sessions counts across all sessions
-            EXPECT_OK(rootIface->countBinders(&remoteCounts));
-            EXPECT_EQ(remoteCounts.size(), proc.sessions.size());
-            for (auto remoteCount : remoteCounts) {
-                EXPECT_EQ(remoteCount, 1);
-            }
-
-            // even though it is on another thread, shutdown races with
-            // the transaction reply being written
-            if (auto status = rootIface->scheduleShutdown(); !status.isOk()) {
-                EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
-            }
-        }
-
-        rootIface = nullptr;
-        rootBinder = nullptr;
+    void setCustomExitStatusCheck(std::function<void(int wstatus)> f) override {
+        host.setCustomExitStatusCheck(std::move(f));
     }
+
+    void terminate() override { host.terminate(); }
 };
 
 static base::unique_fd connectTo(const RpcSocketAddress& addr) {
@@ -273,552 +221,138 @@
     return std::move(sockClient);
 }
 
-using RunServiceFn = void (*)(android::base::borrowed_fd writeEnd,
-                              android::base::borrowed_fd readEnd);
-
-class BinderRpc : public ::testing::TestWithParam<
-                          std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t, bool, bool>> {
-public:
-    SocketType socketType() const { return std::get<0>(GetParam()); }
-    RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); }
-    uint32_t clientVersion() const { return std::get<2>(GetParam()); }
-    uint32_t serverVersion() const { return std::get<3>(GetParam()); }
-    bool serverSingleThreaded() const { return std::get<4>(GetParam()); }
-    bool noKernel() const { return std::get<5>(GetParam()); }
-
-    bool clientOrServerSingleThreaded() const {
-        return !kEnableRpcThreads || serverSingleThreaded();
+std::string BinderRpc::PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+    auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param;
+    auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
+            std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
+    if (singleThreaded) {
+        ret += "_single_threaded";
     }
-
-    // Whether the test params support sending FDs in parcels.
-    bool supportsFdTransport() const {
-        return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS &&
-                (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX ||
-                 socketType() == SocketType::UNIX_BOOTSTRAP);
+    if (noKernel) {
+        ret += "_no_kernel";
     }
+    return ret;
+}
 
-    void SetUp() override {
-        if (socketType() == SocketType::UNIX_BOOTSTRAP && rpcSecurity() == RpcSecurity::TLS) {
-            GTEST_SKIP() << "Unix bootstrap not supported over a TLS transport";
-        }
-    }
+// This creates a new process serving an interface on a certain number of
+// threads.
+std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc(
+        const BinderRpcOptions& options) {
+    CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
 
-    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
-        auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param;
-        auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
-                std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
-        if (singleThreaded) {
-            ret += "_single_threaded";
-        }
-        if (noKernel) {
-            ret += "_no_kernel";
-        }
-        return ret;
-    }
+    SocketType socketType = std::get<0>(GetParam());
+    RpcSecurity rpcSecurity = std::get<1>(GetParam());
+    uint32_t clientVersion = std::get<2>(GetParam());
+    uint32_t serverVersion = std::get<3>(GetParam());
+    bool singleThreaded = std::get<4>(GetParam());
+    bool noKernel = std::get<5>(GetParam());
 
-    // This creates a new process serving an interface on a certain number of
-    // threads.
-    ProcessSession createRpcTestSocketServerProcessEtc(const BinderRpcOptions& options) {
-        CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
+    std::string path = android::base::GetExecutableDirectory();
+    auto servicePath = android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(),
+                                                   singleThreaded ? "_single_threaded" : "",
+                                                   noKernel ? "_no_kernel" : "");
 
-        SocketType socketType = std::get<0>(GetParam());
-        RpcSecurity rpcSecurity = std::get<1>(GetParam());
-        uint32_t clientVersion = std::get<2>(GetParam());
-        uint32_t serverVersion = std::get<3>(GetParam());
-        bool singleThreaded = std::get<4>(GetParam());
-        bool noKernel = std::get<5>(GetParam());
+    base::unique_fd bootstrapClientFd, socketFd;
 
-        std::string path = android::base::GetExecutableDirectory();
-        auto servicePath =
-                android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(),
-                                            singleThreaded ? "_single_threaded" : "",
-                                            noKernel ? "_no_kernel" : "");
-
-        base::unique_fd bootstrapClientFd, bootstrapServerFd;
+    auto addr = allocateSocketAddress();
+    // Initializes the socket before the fork/exec.
+    if (socketType == SocketType::UNIX_RAW) {
+        socketFd = initUnixSocket(addr);
+    } else if (socketType == SocketType::UNIX_BOOTSTRAP) {
         // Do not set O_CLOEXEC, bootstrapServerFd needs to survive fork/exec.
         // This is because we cannot pass ParcelFileDescriptor over a pipe.
-        if (!base::Socketpair(SOCK_STREAM, &bootstrapClientFd, &bootstrapServerFd)) {
+        if (!base::Socketpair(SOCK_STREAM, &bootstrapClientFd, &socketFd)) {
             int savedErrno = errno;
             LOG(FATAL) << "Failed socketpair(): " << strerror(savedErrno);
         }
+    }
 
-        auto ret = ProcessSession{
-                .host = Process([=](android::base::borrowed_fd writeEnd,
-                                    android::base::borrowed_fd readEnd) {
-                    auto writeFd = std::to_string(writeEnd.get());
-                    auto readFd = std::to_string(readEnd.get());
-                    execl(servicePath.c_str(), servicePath.c_str(), writeFd.c_str(), readFd.c_str(),
-                          NULL);
-                }),
-        };
+    auto ret = std::make_unique<LinuxProcessSession>(
+            Process([=](android::base::borrowed_fd writeEnd, android::base::borrowed_fd readEnd) {
+                auto writeFd = std::to_string(writeEnd.get());
+                auto readFd = std::to_string(readEnd.get());
+                execl(servicePath.c_str(), servicePath.c_str(), writeFd.c_str(), readFd.c_str(),
+                      NULL);
+            }));
 
-        BinderRpcTestServerConfig serverConfig;
-        serverConfig.numThreads = options.numThreads;
-        serverConfig.socketType = static_cast<int32_t>(socketType);
-        serverConfig.rpcSecurity = static_cast<int32_t>(rpcSecurity);
-        serverConfig.serverVersion = serverVersion;
-        serverConfig.vsockPort = allocateVsockPort();
-        serverConfig.addr = allocateSocketAddress();
-        serverConfig.unixBootstrapFd = bootstrapServerFd.get();
-        for (auto mode : options.serverSupportedFileDescriptorTransportModes) {
-            serverConfig.serverSupportedFileDescriptorTransportModes.push_back(
-                    static_cast<int32_t>(mode));
-        }
-        writeToFd(ret.host.writeEnd(), serverConfig);
+    BinderRpcTestServerConfig serverConfig;
+    serverConfig.numThreads = options.numThreads;
+    serverConfig.socketType = static_cast<int32_t>(socketType);
+    serverConfig.rpcSecurity = static_cast<int32_t>(rpcSecurity);
+    serverConfig.serverVersion = serverVersion;
+    serverConfig.vsockPort = allocateVsockPort();
+    serverConfig.addr = addr;
+    serverConfig.socketFd = socketFd.get();
+    for (auto mode : options.serverSupportedFileDescriptorTransportModes) {
+        serverConfig.serverSupportedFileDescriptorTransportModes.push_back(
+                static_cast<int32_t>(mode));
+    }
+    writeToFd(ret->host.writeEnd(), serverConfig);
 
-        std::vector<sp<RpcSession>> sessions;
-        auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
-        for (size_t i = 0; i < options.numSessions; i++) {
-            sessions.emplace_back(RpcSession::make(newFactory(rpcSecurity, certVerifier)));
-        }
+    std::vector<sp<RpcSession>> sessions;
+    auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+    for (size_t i = 0; i < options.numSessions; i++) {
+        sessions.emplace_back(RpcSession::make(newFactory(rpcSecurity, certVerifier)));
+    }
 
-        auto serverInfo = readFromFd<BinderRpcTestServerInfo>(ret.host.readEnd());
-        BinderRpcTestClientInfo clientInfo;
-        for (const auto& session : sessions) {
-            auto& parcelableCert = clientInfo.certs.emplace_back();
-            parcelableCert.data = session->getCertificate(RpcCertificateFormat::PEM);
-        }
-        writeToFd(ret.host.writeEnd(), clientInfo);
+    auto serverInfo = readFromFd<BinderRpcTestServerInfo>(ret->host.readEnd());
+    BinderRpcTestClientInfo clientInfo;
+    for (const auto& session : sessions) {
+        auto& parcelableCert = clientInfo.certs.emplace_back();
+        parcelableCert.data = session->getCertificate(RpcCertificateFormat::PEM);
+    }
+    writeToFd(ret->host.writeEnd(), clientInfo);
 
-        CHECK_LE(serverInfo.port, std::numeric_limits<unsigned int>::max());
-        if (socketType == SocketType::INET) {
-            CHECK_NE(0, serverInfo.port);
-        }
+    CHECK_LE(serverInfo.port, std::numeric_limits<unsigned int>::max());
+    if (socketType == SocketType::INET) {
+        CHECK_NE(0, serverInfo.port);
+    }
 
-        if (rpcSecurity == RpcSecurity::TLS) {
-            const auto& serverCert = serverInfo.cert.data;
-            CHECK_EQ(OK,
-                     certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
-                                                             serverCert));
-        }
+    if (rpcSecurity == RpcSecurity::TLS) {
+        const auto& serverCert = serverInfo.cert.data;
+        CHECK_EQ(OK,
+                 certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM, serverCert));
+    }
 
-        status_t status;
+    status_t status;
 
-        for (const auto& session : sessions) {
-            CHECK(session->setProtocolVersion(clientVersion));
-            session->setMaxIncomingThreads(options.numIncomingConnections);
-            session->setMaxOutgoingThreads(options.numOutgoingConnections);
-            session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode);
+    for (const auto& session : sessions) {
+        CHECK(session->setProtocolVersion(clientVersion));
+        session->setMaxIncomingThreads(options.numIncomingConnections);
+        session->setMaxOutgoingThreads(options.numOutgoingConnections);
+        session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode);
 
-            switch (socketType) {
-                case SocketType::PRECONNECTED:
-                    status = session->setupPreconnectedClient({}, [=]() {
-                        return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
-                    });
-                    break;
-                case SocketType::UNIX:
-                    status = session->setupUnixDomainClient(serverConfig.addr.c_str());
-                    break;
-                case SocketType::UNIX_BOOTSTRAP:
-                    status = session->setupUnixDomainSocketBootstrapClient(
-                            base::unique_fd(dup(bootstrapClientFd.get())));
-                    break;
-                case SocketType::VSOCK:
-                    status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort);
-                    break;
-                case SocketType::INET:
-                    status = session->setupInetClient("127.0.0.1", serverInfo.port);
-                    break;
-                default:
-                    LOG_ALWAYS_FATAL("Unknown socket type");
-            }
-            if (options.allowConnectFailure && status != OK) {
-                ret.sessions.clear();
+        switch (socketType) {
+            case SocketType::PRECONNECTED:
+                status = session->setupPreconnectedClient({}, [=]() {
+                    return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
+                });
                 break;
-            }
-            CHECK_EQ(status, OK) << "Could not connect: " << statusToString(status);
-            ret.sessions.push_back({session, session->getRootObject()});
+            case SocketType::UNIX_RAW:
+            case SocketType::UNIX:
+                status = session->setupUnixDomainClient(serverConfig.addr.c_str());
+                break;
+            case SocketType::UNIX_BOOTSTRAP:
+                status = session->setupUnixDomainSocketBootstrapClient(
+                        base::unique_fd(dup(bootstrapClientFd.get())));
+                break;
+            case SocketType::VSOCK:
+                status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort);
+                break;
+            case SocketType::INET:
+                status = session->setupInetClient("127.0.0.1", serverInfo.port);
+                break;
+            default:
+                LOG_ALWAYS_FATAL("Unknown socket type");
         }
-        return ret;
+        if (options.allowConnectFailure && status != OK) {
+            ret->sessions.clear();
+            break;
+        }
+        CHECK_EQ(status, OK) << "Could not connect: " << statusToString(status);
+        ret->sessions.push_back({session, session->getRootObject()});
     }
-
-    BinderRpcTestProcessSession createRpcTestSocketServerProcess(const BinderRpcOptions& options) {
-        BinderRpcTestProcessSession ret{
-                .proc = createRpcTestSocketServerProcessEtc(options),
-        };
-
-        ret.rootBinder = ret.proc.sessions.empty() ? nullptr : ret.proc.sessions.at(0).root;
-        ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
-
-        return ret;
-    }
-
-    void testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
-                                     size_t sleepMs = 500);
-};
-
-TEST_P(BinderRpc, Ping) {
-    auto proc = createRpcTestSocketServerProcess({});
-    ASSERT_NE(proc.rootBinder, nullptr);
-    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
-}
-
-TEST_P(BinderRpc, GetInterfaceDescriptor) {
-    auto proc = createRpcTestSocketServerProcess({});
-    ASSERT_NE(proc.rootBinder, nullptr);
-    EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
-}
-
-TEST_P(BinderRpc, MultipleSessions) {
-    if (serverSingleThreaded()) {
-        // Tests with multiple sessions require a multi-threaded service,
-        // but work fine on a single-threaded client
-        GTEST_SKIP() << "This test requires a multi-threaded service";
-    }
-
-    auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5});
-    for (auto session : proc.proc.sessions) {
-        ASSERT_NE(nullptr, session.root);
-        EXPECT_EQ(OK, session.root->pingBinder());
-    }
-}
-
-TEST_P(BinderRpc, SeparateRootObject) {
-    if (serverSingleThreaded()) {
-        GTEST_SKIP() << "This test requires a multi-threaded service";
-    }
-
-    SocketType type = std::get<0>(GetParam());
-    if (type == SocketType::PRECONNECTED || type == SocketType::UNIX ||
-        type == SocketType::UNIX_BOOTSTRAP) {
-        // we can't get port numbers for unix sockets
-        return;
-    }
-
-    auto proc = createRpcTestSocketServerProcess({.numSessions = 2});
-
-    int port1 = 0;
-    EXPECT_OK(proc.rootIface->getClientPort(&port1));
-
-    sp<IBinderRpcTest> rootIface2 = interface_cast<IBinderRpcTest>(proc.proc.sessions.at(1).root);
-    int port2;
-    EXPECT_OK(rootIface2->getClientPort(&port2));
-
-    // we should have a different IBinderRpcTest object created for each
-    // session, because we use setPerSessionRootObject
-    EXPECT_NE(port1, port2);
-}
-
-TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
-    auto proc = createRpcTestSocketServerProcess({});
-    Parcel data;
-    Parcel reply;
-    EXPECT_EQ(BAD_TYPE, proc.rootBinder->transact(IBinder::PING_TRANSACTION, data, &reply, 0));
-}
-
-TEST_P(BinderRpc, AppendSeparateFormats) {
-    auto proc1 = createRpcTestSocketServerProcess({});
-    auto proc2 = createRpcTestSocketServerProcess({});
-
-    Parcel pRaw;
-
-    Parcel p1;
-    p1.markForBinder(proc1.rootBinder);
-    p1.writeInt32(3);
-
-    EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, pRaw.dataSize()));
-    EXPECT_EQ(BAD_TYPE, pRaw.appendFrom(&p1, 0, p1.dataSize()));
-
-    Parcel p2;
-    p2.markForBinder(proc2.rootBinder);
-    p2.writeInt32(7);
-
-    EXPECT_EQ(BAD_TYPE, p1.appendFrom(&p2, 0, p2.dataSize()));
-    EXPECT_EQ(BAD_TYPE, p2.appendFrom(&p1, 0, p1.dataSize()));
-}
-
-TEST_P(BinderRpc, UnknownTransaction) {
-    auto proc = createRpcTestSocketServerProcess({});
-    Parcel data;
-    data.markForBinder(proc.rootBinder);
-    Parcel reply;
-    EXPECT_EQ(UNKNOWN_TRANSACTION, proc.rootBinder->transact(1337, data, &reply, 0));
-}
-
-TEST_P(BinderRpc, SendSomethingOneway) {
-    auto proc = createRpcTestSocketServerProcess({});
-    EXPECT_OK(proc.rootIface->sendString("asdf"));
-}
-
-TEST_P(BinderRpc, SendAndGetResultBack) {
-    auto proc = createRpcTestSocketServerProcess({});
-    std::string doubled;
-    EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled));
-    EXPECT_EQ("cool cool ", doubled);
-}
-
-TEST_P(BinderRpc, SendAndGetResultBackBig) {
-    auto proc = createRpcTestSocketServerProcess({});
-    std::string single = std::string(1024, 'a');
-    std::string doubled;
-    EXPECT_OK(proc.rootIface->doubleString(single, &doubled));
-    EXPECT_EQ(single + single, doubled);
-}
-
-TEST_P(BinderRpc, InvalidNullBinderReturn) {
-    auto proc = createRpcTestSocketServerProcess({});
-
-    sp<IBinder> outBinder;
-    EXPECT_EQ(proc.rootIface->getNullBinder(&outBinder).transactionError(), UNEXPECTED_NULL);
-}
-
-TEST_P(BinderRpc, CallMeBack) {
-    auto proc = createRpcTestSocketServerProcess({});
-
-    int32_t pingResult;
-    EXPECT_OK(proc.rootIface->pingMe(new MyBinderRpcSession("foo"), &pingResult));
-    EXPECT_EQ(OK, pingResult);
-
-    EXPECT_EQ(0, MyBinderRpcSession::gNum);
-}
-
-TEST_P(BinderRpc, RepeatBinder) {
-    auto proc = createRpcTestSocketServerProcess({});
-
-    sp<IBinder> inBinder = new MyBinderRpcSession("foo");
-    sp<IBinder> outBinder;
-    EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
-    EXPECT_EQ(inBinder, outBinder);
-
-    wp<IBinder> weak = inBinder;
-    inBinder = nullptr;
-    outBinder = nullptr;
-
-    // Force reading a reply, to process any pending dec refs from the other
-    // process (the other process will process dec refs there before processing
-    // the ping here).
-    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
-
-    EXPECT_EQ(nullptr, weak.promote());
-
-    EXPECT_EQ(0, MyBinderRpcSession::gNum);
-}
-
-TEST_P(BinderRpc, RepeatTheirBinder) {
-    auto proc = createRpcTestSocketServerProcess({});
-
-    sp<IBinderRpcSession> session;
-    EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
-
-    sp<IBinder> inBinder = IInterface::asBinder(session);
-    sp<IBinder> outBinder;
-    EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
-    EXPECT_EQ(inBinder, outBinder);
-
-    wp<IBinder> weak = inBinder;
-    session = nullptr;
-    inBinder = nullptr;
-    outBinder = nullptr;
-
-    // Force reading a reply, to process any pending dec refs from the other
-    // process (the other process will process dec refs there before processing
-    // the ping here).
-    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
-
-    EXPECT_EQ(nullptr, weak.promote());
-}
-
-TEST_P(BinderRpc, RepeatBinderNull) {
-    auto proc = createRpcTestSocketServerProcess({});
-
-    sp<IBinder> outBinder;
-    EXPECT_OK(proc.rootIface->repeatBinder(nullptr, &outBinder));
-    EXPECT_EQ(nullptr, outBinder);
-}
-
-TEST_P(BinderRpc, HoldBinder) {
-    auto proc = createRpcTestSocketServerProcess({});
-
-    IBinder* ptr = nullptr;
-    {
-        sp<IBinder> binder = new BBinder();
-        ptr = binder.get();
-        EXPECT_OK(proc.rootIface->holdBinder(binder));
-    }
-
-    sp<IBinder> held;
-    EXPECT_OK(proc.rootIface->getHeldBinder(&held));
-
-    EXPECT_EQ(held.get(), ptr);
-
-    // stop holding binder, because we test to make sure references are cleaned
-    // up
-    EXPECT_OK(proc.rootIface->holdBinder(nullptr));
-    // and flush ref counts
-    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
-}
-
-// START TESTS FOR LIMITATIONS OF SOCKET BINDER
-// These are behavioral differences form regular binder, where certain usecases
-// aren't supported.
-
-TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketSessions) {
-    auto proc1 = createRpcTestSocketServerProcess({});
-    auto proc2 = createRpcTestSocketServerProcess({});
-
-    sp<IBinder> outBinder;
-    EXPECT_EQ(INVALID_OPERATION,
-              proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
-}
-
-TEST_P(BinderRpc, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
-    if (serverSingleThreaded()) {
-        GTEST_SKIP() << "This test requires a multi-threaded service";
-    }
-
-    auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 2});
-
-    sp<IBinder> outBinder;
-    EXPECT_EQ(INVALID_OPERATION,
-              proc.rootIface->repeatBinder(proc.proc.sessions.at(1).root, &outBinder)
-                      .transactionError());
-}
-
-TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
-    if (!kEnableKernelIpc || noKernel()) {
-        GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
-                        "at build time.";
-    }
-
-    auto proc = createRpcTestSocketServerProcess({});
-
-    sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
-    sp<IBinder> outBinder;
-    EXPECT_EQ(INVALID_OPERATION,
-              proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError());
-}
-
-TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
-    if (!kEnableKernelIpc || noKernel()) {
-        GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
-                        "at build time.";
-    }
-
-    auto proc = createRpcTestSocketServerProcess({});
-
-    // for historical reasons, IServiceManager interface only returns the
-    // exception code
-    EXPECT_EQ(binder::Status::EX_TRANSACTION_FAILED,
-              defaultServiceManager()->addService(String16("not_suspicious"), proc.rootBinder));
-}
-
-// END TESTS FOR LIMITATIONS OF SOCKET BINDER
-
-TEST_P(BinderRpc, RepeatRootObject) {
-    auto proc = createRpcTestSocketServerProcess({});
-
-    sp<IBinder> outBinder;
-    EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &outBinder));
-    EXPECT_EQ(proc.rootBinder, outBinder);
-}
-
-TEST_P(BinderRpc, NestedTransactions) {
-    auto proc = createRpcTestSocketServerProcess({
-            // Enable FD support because it uses more stack space and so represents
-            // something closer to a worst case scenario.
-            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
-            .serverSupportedFileDescriptorTransportModes =
-                    {RpcSession::FileDescriptorTransportMode::UNIX},
-    });
-
-    auto nastyNester = sp<MyBinderRpcTest>::make();
-    EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
-
-    wp<IBinder> weak = nastyNester;
-    nastyNester = nullptr;
-    EXPECT_EQ(nullptr, weak.promote());
-}
-
-TEST_P(BinderRpc, SameBinderEquality) {
-    auto proc = createRpcTestSocketServerProcess({});
-
-    sp<IBinder> a;
-    EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
-
-    sp<IBinder> b;
-    EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
-
-    EXPECT_EQ(a, b);
-}
-
-TEST_P(BinderRpc, SameBinderEqualityWeak) {
-    auto proc = createRpcTestSocketServerProcess({});
-
-    sp<IBinder> a;
-    EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
-    wp<IBinder> weak = a;
-    a = nullptr;
-
-    sp<IBinder> b;
-    EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
-
-    // this is the wrong behavior, since BpBinder
-    // doesn't implement onIncStrongAttempted
-    // but make sure there is no crash
-    EXPECT_EQ(nullptr, weak.promote());
-
-    GTEST_SKIP() << "Weak binders aren't currently re-promotable for RPC binder.";
-
-    // In order to fix this:
-    // - need to have incStrongAttempted reflected across IPC boundary (wait for
-    //   response to promote - round trip...)
-    // - sendOnLastWeakRef, to delete entries out of RpcState table
-    EXPECT_EQ(b, weak.promote());
-}
-
-#define expectSessions(expected, iface)                   \
-    do {                                                  \
-        int session;                                      \
-        EXPECT_OK((iface)->getNumOpenSessions(&session)); \
-        EXPECT_EQ(expected, session);                     \
-    } while (false)
-
-TEST_P(BinderRpc, SingleSession) {
-    auto proc = createRpcTestSocketServerProcess({});
-
-    sp<IBinderRpcSession> session;
-    EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
-    std::string out;
-    EXPECT_OK(session->getName(&out));
-    EXPECT_EQ("aoeu", out);
-
-    expectSessions(1, proc.rootIface);
-    session = nullptr;
-    expectSessions(0, proc.rootIface);
-}
-
-TEST_P(BinderRpc, ManySessions) {
-    auto proc = createRpcTestSocketServerProcess({});
-
-    std::vector<sp<IBinderRpcSession>> sessions;
-
-    for (size_t i = 0; i < 15; i++) {
-        expectSessions(i, proc.rootIface);
-        sp<IBinderRpcSession> session;
-        EXPECT_OK(proc.rootIface->openSession(std::to_string(i), &session));
-        sessions.push_back(session);
-    }
-    expectSessions(sessions.size(), proc.rootIface);
-    for (size_t i = 0; i < sessions.size(); i++) {
-        std::string out;
-        EXPECT_OK(sessions.at(i)->getName(&out));
-        EXPECT_EQ(std::to_string(i), out);
-    }
-    expectSessions(sessions.size(), proc.rootIface);
-
-    while (!sessions.empty()) {
-        sessions.pop_back();
-        expectSessions(sessions.size(), proc.rootIface);
-    }
-    expectSessions(0, proc.rootIface);
-}
-
-size_t epochMillis() {
-    using std::chrono::duration_cast;
-    using std::chrono::milliseconds;
-    using std::chrono::seconds;
-    using std::chrono::system_clock;
-    return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+    return ret;
 }
 
 TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
@@ -857,8 +391,8 @@
     for (auto& t : ts) t.join();
 }
 
-void BinderRpc::testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
-                                            size_t sleepMs) {
+static void testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
+                                        size_t sleepMs = 500) {
     size_t epochMsBefore = epochMillis();
 
     std::vector<std::thread> ts;
@@ -958,20 +492,6 @@
     saturateThreadPool(kNumServerThreads, proc.rootIface);
 }
 
-TEST_P(BinderRpc, OnewayCallDoesNotWait) {
-    constexpr size_t kReallyLongTimeMs = 100;
-    constexpr size_t kSleepMs = kReallyLongTimeMs * 5;
-
-    auto proc = createRpcTestSocketServerProcess({});
-
-    size_t epochMsBefore = epochMillis();
-
-    EXPECT_OK(proc.rootIface->sleepMsAsync(kSleepMs));
-
-    size_t epochMsAfter = epochMillis();
-    EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
-}
-
 TEST_P(BinderRpc, OnewayCallQueueingWithFds) {
     if (!supportsFdTransport()) {
         GTEST_SKIP() << "Would fail trivially (which is tested elsewhere)";
@@ -1057,7 +577,7 @@
     // Build up oneway calls on the second session to make sure it terminates
     // and shuts down. The first session should be unaffected (proc destructor
     // checks the first session).
-    auto iface = interface_cast<IBinderRpcTest>(proc.proc.sessions.at(1).root);
+    auto iface = interface_cast<IBinderRpcTest>(proc.proc->sessions.at(1).root);
 
     std::vector<std::thread> threads;
     for (size_t i = 0; i < kNumClients; i++) {
@@ -1085,66 +605,7 @@
     // any pending commands). We need to erase this session from the record
     // here, so that the destructor for our session won't check that this
     // session is valid, but we still want it to test the other session.
-    proc.proc.sessions.erase(proc.proc.sessions.begin() + 1);
-}
-
-TEST_P(BinderRpc, Callbacks) {
-    const static std::string kTestString = "good afternoon!";
-
-    for (bool callIsOneway : {true, false}) {
-        for (bool callbackIsOneway : {true, false}) {
-            for (bool delayed : {true, false}) {
-                if (clientOrServerSingleThreaded() &&
-                    (callIsOneway || callbackIsOneway || delayed)) {
-                    // we have no incoming connections to receive the callback
-                    continue;
-                }
-
-                size_t numIncomingConnections = clientOrServerSingleThreaded() ? 0 : 1;
-                auto proc = createRpcTestSocketServerProcess(
-                        {.numThreads = 1,
-                         .numSessions = 1,
-                         .numIncomingConnections = numIncomingConnections});
-                auto cb = sp<MyBinderRpcCallback>::make();
-
-                if (callIsOneway) {
-                    EXPECT_OK(proc.rootIface->doCallbackAsync(cb, callbackIsOneway, delayed,
-                                                              kTestString));
-                } else {
-                    EXPECT_OK(
-                            proc.rootIface->doCallback(cb, callbackIsOneway, delayed, kTestString));
-                }
-
-                // if both transactions are synchronous and the response is sent back on the
-                // same thread, everything should have happened in a nested call. Otherwise,
-                // the callback will be processed on another thread.
-                if (callIsOneway || callbackIsOneway || delayed) {
-                    using std::literals::chrono_literals::operator""s;
-                    RpcMutexUniqueLock _l(cb->mMutex);
-                    cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
-                }
-
-                EXPECT_EQ(cb->mValues.size(), 1)
-                        << "callIsOneway: " << callIsOneway
-                        << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
-                if (cb->mValues.empty()) continue;
-                EXPECT_EQ(cb->mValues.at(0), kTestString)
-                        << "callIsOneway: " << callIsOneway
-                        << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
-
-                // since we are severing the connection, we need to go ahead and
-                // tell the server to shutdown and exit so that waitpid won't hang
-                if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
-                    EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
-                }
-
-                // since this session has an incoming connection w/ a threadpool, we
-                // need to manually shut it down
-                EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
-                proc.expectAlreadyShutdown = true;
-            }
-        }
-    }
+    proc.proc->sessions.erase(proc.proc->sessions.begin() + 1);
 }
 
 TEST_P(BinderRpc, SingleDeathRecipient) {
@@ -1177,7 +638,7 @@
     ASSERT_TRUE(dr->mCv.wait_for(lock, 100ms, [&]() { return dr->dead; }));
 
     // need to wait for the session to shutdown so we don't "Leak session"
-    EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+    EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
     proc.expectAlreadyShutdown = true;
 }
 
@@ -1205,7 +666,7 @@
 
     // Explicitly calling shutDownAndWait will cause the death recipients
     // to be called.
-    EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+    EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
 
     std::unique_lock<std::mutex> lock(dr->mMtx);
     if (!dr->dead) {
@@ -1213,8 +674,8 @@
     }
     EXPECT_TRUE(dr->dead) << "Failed to receive the death notification.";
 
-    proc.proc.host.terminate();
-    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+    proc.proc->terminate();
+    proc.proc->setCustomExitStatusCheck([](int wstatus) {
         EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
                 << "server process failed incorrectly: " << WaitStatusToString(wstatus);
     });
@@ -1259,18 +720,10 @@
     }
 
     // need to wait for the session to shutdown so we don't "Leak session"
-    EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+    EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
     proc.expectAlreadyShutdown = true;
 }
 
-TEST_P(BinderRpc, OnewayCallbackWithNoThread) {
-    auto proc = createRpcTestSocketServerProcess({});
-    auto cb = sp<MyBinderRpcCallback>::make();
-
-    Status status = proc.rootIface->doCallback(cb, true /*oneway*/, false /*delayed*/, "anything");
-    EXPECT_EQ(WOULD_BLOCK, status.transactionError());
-}
-
 TEST_P(BinderRpc, Die) {
     for (bool doDeathCleanup : {true, false}) {
         auto proc = createRpcTestSocketServerProcess({});
@@ -1286,7 +739,7 @@
         EXPECT_EQ(DEAD_OBJECT, proc.rootIface->die(doDeathCleanup).transactionError())
                 << "Do death cleanup: " << doDeathCleanup;
 
-        proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+        proc.proc->setCustomExitStatusCheck([](int wstatus) {
             EXPECT_TRUE(WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 1)
                     << "server process failed incorrectly: " << WaitStatusToString(wstatus);
         });
@@ -1316,7 +769,7 @@
     // second time! we catch the error :)
     EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError());
 
-    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+    proc.proc->setCustomExitStatusCheck([](int wstatus) {
         EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT)
                 << "server process failed incorrectly: " << WaitStatusToString(wstatus);
     });
@@ -1330,9 +783,9 @@
                     {RpcSession::FileDescriptorTransportMode::UNIX},
             .allowConnectFailure = true,
     });
-    EXPECT_TRUE(proc.proc.sessions.empty()) << "session connections should have failed";
-    proc.proc.host.terminate();
-    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+    EXPECT_TRUE(proc.proc->sessions.empty()) << "session connections should have failed";
+    proc.proc->terminate();
+    proc.proc->setCustomExitStatusCheck([](int wstatus) {
         EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
                 << "server process failed incorrectly: " << WaitStatusToString(wstatus);
     });
@@ -1346,9 +799,9 @@
                     {RpcSession::FileDescriptorTransportMode::NONE},
             .allowConnectFailure = true,
     });
-    EXPECT_TRUE(proc.proc.sessions.empty()) << "session connections should have failed";
-    proc.proc.host.terminate();
-    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+    EXPECT_TRUE(proc.proc->sessions.empty()) << "session connections should have failed";
+    proc.proc->terminate();
+    proc.proc->setCustomExitStatusCheck([](int wstatus) {
         EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
                 << "server process failed incorrectly: " << WaitStatusToString(wstatus);
     });
@@ -1460,6 +913,33 @@
     EXPECT_EQ(status.transactionError(), BAD_VALUE) << status;
 }
 
+TEST_P(BinderRpc, AppendInvalidFd) {
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::UNIX},
+    });
+
+    int badFd = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 0);
+    ASSERT_NE(badFd, -1);
+
+    // Close the file descriptor so it becomes invalid for dup
+    close(badFd);
+
+    Parcel p1;
+    p1.markForBinder(proc.rootBinder);
+    p1.writeInt32(3);
+    EXPECT_EQ(OK, p1.writeFileDescriptor(badFd, false));
+
+    Parcel pRaw;
+    pRaw.markForBinder(proc.rootBinder);
+    EXPECT_EQ(OK, pRaw.appendFrom(&p1, 0, p1.dataSize()));
+
+    pRaw.setDataPosition(0);
+    EXPECT_EQ(3, pRaw.readInt32());
+    ASSERT_EQ(-1, pRaw.readFileDescriptor());
+}
+
 TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
     if constexpr (!kEnableSharedLibs) {
         GTEST_SKIP() << "Test disabled because Binder was built as a static library";
@@ -1516,16 +996,6 @@
     ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
 }
 
-TEST_P(BinderRpc, AidlDelegatorTest) {
-    auto proc = createRpcTestSocketServerProcess({});
-    auto myDelegator = sp<IBinderRpcTestDelegator>::make(proc.rootIface);
-    ASSERT_NE(nullptr, myDelegator);
-
-    std::string doubled;
-    EXPECT_OK(myDelegator->doubleString("cool ", &doubled));
-    EXPECT_EQ("cool cool ", doubled);
-}
-
 static bool testSupportVsockLoopback() {
     // We don't need to enable TLS to know if vsock is supported.
     unsigned int vsockPort = allocateVsockPort();
@@ -1616,7 +1086,8 @@
 }
 
 static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
-    std::vector<SocketType> ret = {SocketType::UNIX, SocketType::UNIX_BOOTSTRAP, SocketType::INET};
+    std::vector<SocketType> ret = {SocketType::UNIX, SocketType::UNIX_BOOTSTRAP, SocketType::INET,
+                                   SocketType::UNIX_RAW};
 
     if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED);
 
@@ -1858,9 +1329,20 @@
                     mAcceptConnection = &Server::recvmsgServerConnection;
                     mConnectToServer = [this] { return connectToUnixBootstrap(mBootstrapSocket); };
                 } break;
+                case SocketType::UNIX_RAW: {
+                    auto addr = allocateSocketAddress();
+                    auto status = rpcServer->setupRawSocketServer(initUnixSocket(addr));
+                    if (status != OK) {
+                        return AssertionFailure()
+                                << "setupRawSocketServer: " << statusToString(status);
+                    }
+                    mConnectToServer = [addr] {
+                        return connectTo(UnixSocketAddress(addr.c_str()));
+                    };
+                } break;
                 case SocketType::VSOCK: {
                     auto port = allocateVsockPort();
-                    auto status = rpcServer->setupVsockServer(port);
+                    auto status = rpcServer->setupVsockServer(VMADDR_CID_LOCAL, port);
                     if (status != OK) {
                         return AssertionFailure() << "setupVsockServer: " << statusToString(status);
                     }
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
index 823bbf6..654e16c 100644
--- a/libs/binder/tests/binderRpcTestCommon.h
+++ b/libs/binder/tests/binderRpcTestCommon.h
@@ -69,6 +69,7 @@
     PRECONNECTED,
     UNIX,
     UNIX_BOOTSTRAP,
+    UNIX_RAW,
     VSOCK,
     INET,
 };
@@ -81,6 +82,8 @@
             return "unix_domain_socket";
         case SocketType::UNIX_BOOTSTRAP:
             return "unix_domain_socket_bootstrap";
+        case SocketType::UNIX_RAW:
+            return "raw_uds";
         case SocketType::VSOCK:
             return "vm_socket";
         case SocketType::INET:
@@ -91,6 +94,14 @@
     }
 }
 
+static inline size_t epochMillis() {
+    using std::chrono::duration_cast;
+    using std::chrono::milliseconds;
+    using std::chrono::seconds;
+    using std::chrono::system_clock;
+    return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+}
+
 struct BinderRpcOptions {
     size_t numThreads = 1;
     size_t numSessions = 1;
diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h
new file mode 100644
index 0000000..5a78782
--- /dev/null
+++ b/libs/binder/tests/binderRpcTestFixture.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gtest/gtest.h>
+
+#include "binderRpcTestCommon.h"
+
+#define EXPECT_OK(status)                        \
+    do {                                         \
+        android::binder::Status stat = (status); \
+        EXPECT_TRUE(stat.isOk()) << stat;        \
+    } while (false)
+
+namespace android {
+
+// Abstract base class with a virtual destructor that handles the
+// ownership of a process session for BinderRpcTestSession below
+class ProcessSession {
+public:
+    struct SessionInfo {
+        sp<RpcSession> session;
+        sp<IBinder> root;
+    };
+
+    // client session objects associated with other process
+    // each one represents a separate session
+    std::vector<SessionInfo> sessions;
+
+    virtual ~ProcessSession() = 0;
+
+    // If the process exits with a status, run the given callback on that value.
+    virtual void setCustomExitStatusCheck(std::function<void(int wstatus)> f) = 0;
+
+    // Kill the process. Avoid if possible. Shutdown gracefully via an RPC instead.
+    virtual void terminate() = 0;
+};
+
+// Process session where the process hosts IBinderRpcTest, the server used
+// for most testing here
+struct BinderRpcTestProcessSession {
+    std::unique_ptr<ProcessSession> proc;
+
+    // pre-fetched root object (for first session)
+    sp<IBinder> rootBinder;
+
+    // pre-casted root object (for first session)
+    sp<IBinderRpcTest> rootIface;
+
+    // whether session should be invalidated by end of run
+    bool expectAlreadyShutdown = false;
+
+    BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default;
+    ~BinderRpcTestProcessSession() {
+        if (!expectAlreadyShutdown) {
+            EXPECT_NE(nullptr, rootIface);
+            if (rootIface == nullptr) return;
+
+            std::vector<int32_t> remoteCounts;
+            // calling over any sessions counts across all sessions
+            EXPECT_OK(rootIface->countBinders(&remoteCounts));
+            EXPECT_EQ(remoteCounts.size(), proc->sessions.size());
+            for (auto remoteCount : remoteCounts) {
+                EXPECT_EQ(remoteCount, 1);
+            }
+
+            // even though it is on another thread, shutdown races with
+            // the transaction reply being written
+            if (auto status = rootIface->scheduleShutdown(); !status.isOk()) {
+                EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+            }
+        }
+
+        rootIface = nullptr;
+        rootBinder = nullptr;
+    }
+};
+
+class BinderRpc : public ::testing::TestWithParam<
+                          std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t, bool, bool>> {
+public:
+    SocketType socketType() const { return std::get<0>(GetParam()); }
+    RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); }
+    uint32_t clientVersion() const { return std::get<2>(GetParam()); }
+    uint32_t serverVersion() const { return std::get<3>(GetParam()); }
+    bool serverSingleThreaded() const { return std::get<4>(GetParam()); }
+    bool noKernel() const { return std::get<5>(GetParam()); }
+
+    bool clientOrServerSingleThreaded() const {
+        return !kEnableRpcThreads || serverSingleThreaded();
+    }
+
+    // Whether the test params support sending FDs in parcels.
+    bool supportsFdTransport() const {
+        return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS &&
+                (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX ||
+                 socketType() == SocketType::UNIX_BOOTSTRAP ||
+                 socketType() == SocketType::UNIX_RAW);
+    }
+
+    void SetUp() override {
+        if (socketType() == SocketType::UNIX_BOOTSTRAP && rpcSecurity() == RpcSecurity::TLS) {
+            GTEST_SKIP() << "Unix bootstrap not supported over a TLS transport";
+        }
+    }
+
+    BinderRpcTestProcessSession createRpcTestSocketServerProcess(const BinderRpcOptions& options) {
+        BinderRpcTestProcessSession ret{
+                .proc = createRpcTestSocketServerProcessEtc(options),
+        };
+
+        ret.rootBinder = ret.proc->sessions.empty() ? nullptr : ret.proc->sessions.at(0).root;
+        ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
+
+        return ret;
+    }
+
+    static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info);
+
+protected:
+    std::unique_ptr<ProcessSession> createRpcTestSocketServerProcessEtc(
+            const BinderRpcOptions& options);
+};
+
+} // namespace android
diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp
index a922b21..cc9726b 100644
--- a/libs/binder/tests/binderRpcTestService.cpp
+++ b/libs/binder/tests/binderRpcTestService.cpp
@@ -42,7 +42,7 @@
     server->setSupportedFileDescriptorTransportModes(serverSupportedFileDescriptorTransportModes);
 
     unsigned int outPort = 0;
-    base::unique_fd unixBootstrapFd(serverConfig.unixBootstrapFd);
+    base::unique_fd socketFd(serverConfig.socketFd);
 
     switch (socketType) {
         case SocketType::PRECONNECTED:
@@ -52,10 +52,13 @@
                     << serverConfig.addr;
             break;
         case SocketType::UNIX_BOOTSTRAP:
-            CHECK_EQ(OK, server->setupUnixDomainSocketBootstrapServer(std::move(unixBootstrapFd)));
+            CHECK_EQ(OK, server->setupUnixDomainSocketBootstrapServer(std::move(socketFd)));
+            break;
+        case SocketType::UNIX_RAW:
+            CHECK_EQ(OK, server->setupRawSocketServer(std::move(socketFd)));
             break;
         case SocketType::VSOCK:
-            CHECK_EQ(OK, server->setupVsockServer(serverConfig.vsockPort));
+            CHECK_EQ(OK, server->setupVsockServer(VMADDR_CID_LOCAL, serverConfig.vsockPort));
             break;
         case SocketType::INET: {
             CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp
new file mode 100644
index 0000000..f960442
--- /dev/null
+++ b/libs/binder/tests/binderRpcUniversalTests.cpp
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <chrono>
+#include <cstdlib>
+#include <type_traits>
+
+#include "binderRpcTestCommon.h"
+#include "binderRpcTestFixture.h"
+
+using namespace std::chrono_literals;
+using namespace std::placeholders;
+using testing::AssertionFailure;
+using testing::AssertionResult;
+using testing::AssertionSuccess;
+
+namespace android {
+
+static_assert(RPC_WIRE_PROTOCOL_VERSION + 1 == RPC_WIRE_PROTOCOL_VERSION_NEXT ||
+              RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
+
+TEST(BinderRpcParcel, EntireParcelFormatted) {
+    Parcel p;
+    p.writeInt32(3);
+
+    EXPECT_DEATH_IF_SUPPORTED(p.markForBinder(sp<BBinder>::make()),
+                              "format must be set before data is written");
+}
+
+TEST(BinderRpc, CannotUseNextWireVersion) {
+    auto session = RpcSession::make();
+    EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT));
+    EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 1));
+    EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 2));
+    EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 15));
+}
+
+TEST(BinderRpc, CanUseExperimentalWireVersion) {
+    auto session = RpcSession::make();
+    EXPECT_TRUE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL));
+}
+
+TEST_P(BinderRpc, Ping) {
+    auto proc = createRpcTestSocketServerProcess({});
+    ASSERT_NE(proc.rootBinder, nullptr);
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+}
+
+TEST_P(BinderRpc, GetInterfaceDescriptor) {
+    auto proc = createRpcTestSocketServerProcess({});
+    ASSERT_NE(proc.rootBinder, nullptr);
+    EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
+}
+
+TEST_P(BinderRpc, MultipleSessions) {
+    if (serverSingleThreaded()) {
+        // Tests with multiple sessions require a multi-threaded service,
+        // but work fine on a single-threaded client
+        GTEST_SKIP() << "This test requires a multi-threaded service";
+    }
+
+    auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5});
+    for (auto session : proc.proc->sessions) {
+        ASSERT_NE(nullptr, session.root);
+        EXPECT_EQ(OK, session.root->pingBinder());
+    }
+}
+
+TEST_P(BinderRpc, SeparateRootObject) {
+    if (serverSingleThreaded()) {
+        GTEST_SKIP() << "This test requires a multi-threaded service";
+    }
+
+    SocketType type = std::get<0>(GetParam());
+    if (type == SocketType::PRECONNECTED || type == SocketType::UNIX ||
+        type == SocketType::UNIX_BOOTSTRAP || type == SocketType::UNIX_RAW) {
+        // we can't get port numbers for unix sockets
+        return;
+    }
+
+    auto proc = createRpcTestSocketServerProcess({.numSessions = 2});
+
+    int port1 = 0;
+    EXPECT_OK(proc.rootIface->getClientPort(&port1));
+
+    sp<IBinderRpcTest> rootIface2 = interface_cast<IBinderRpcTest>(proc.proc->sessions.at(1).root);
+    int port2;
+    EXPECT_OK(rootIface2->getClientPort(&port2));
+
+    // we should have a different IBinderRpcTest object created for each
+    // session, because we use setPerSessionRootObject
+    EXPECT_NE(port1, port2);
+}
+
+TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
+    auto proc = createRpcTestSocketServerProcess({});
+    Parcel data;
+    Parcel reply;
+    EXPECT_EQ(BAD_TYPE, proc.rootBinder->transact(IBinder::PING_TRANSACTION, data, &reply, 0));
+}
+
+TEST_P(BinderRpc, AppendSeparateFormats) {
+    auto proc1 = createRpcTestSocketServerProcess({});
+    auto proc2 = createRpcTestSocketServerProcess({});
+
+    Parcel pRaw;
+
+    Parcel p1;
+    p1.markForBinder(proc1.rootBinder);
+    p1.writeInt32(3);
+
+    EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, pRaw.dataSize()));
+    EXPECT_EQ(BAD_TYPE, pRaw.appendFrom(&p1, 0, p1.dataSize()));
+
+    Parcel p2;
+    p2.markForBinder(proc2.rootBinder);
+    p2.writeInt32(7);
+
+    EXPECT_EQ(BAD_TYPE, p1.appendFrom(&p2, 0, p2.dataSize()));
+    EXPECT_EQ(BAD_TYPE, p2.appendFrom(&p1, 0, p1.dataSize()));
+}
+
+TEST_P(BinderRpc, UnknownTransaction) {
+    auto proc = createRpcTestSocketServerProcess({});
+    Parcel data;
+    data.markForBinder(proc.rootBinder);
+    Parcel reply;
+    EXPECT_EQ(UNKNOWN_TRANSACTION, proc.rootBinder->transact(1337, data, &reply, 0));
+}
+
+TEST_P(BinderRpc, SendSomethingOneway) {
+    auto proc = createRpcTestSocketServerProcess({});
+    EXPECT_OK(proc.rootIface->sendString("asdf"));
+}
+
+TEST_P(BinderRpc, SendAndGetResultBack) {
+    auto proc = createRpcTestSocketServerProcess({});
+    std::string doubled;
+    EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled));
+    EXPECT_EQ("cool cool ", doubled);
+}
+
+TEST_P(BinderRpc, SendAndGetResultBackBig) {
+    auto proc = createRpcTestSocketServerProcess({});
+    std::string single = std::string(1024, 'a');
+    std::string doubled;
+    EXPECT_OK(proc.rootIface->doubleString(single, &doubled));
+    EXPECT_EQ(single + single, doubled);
+}
+
+TEST_P(BinderRpc, InvalidNullBinderReturn) {
+    auto proc = createRpcTestSocketServerProcess({});
+
+    sp<IBinder> outBinder;
+    EXPECT_EQ(proc.rootIface->getNullBinder(&outBinder).transactionError(), UNEXPECTED_NULL);
+}
+
+TEST_P(BinderRpc, CallMeBack) {
+    auto proc = createRpcTestSocketServerProcess({});
+
+    int32_t pingResult;
+    EXPECT_OK(proc.rootIface->pingMe(new MyBinderRpcSession("foo"), &pingResult));
+    EXPECT_EQ(OK, pingResult);
+
+    EXPECT_EQ(0, MyBinderRpcSession::gNum);
+}
+
+TEST_P(BinderRpc, RepeatBinder) {
+    auto proc = createRpcTestSocketServerProcess({});
+
+    sp<IBinder> inBinder = new MyBinderRpcSession("foo");
+    sp<IBinder> outBinder;
+    EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
+    EXPECT_EQ(inBinder, outBinder);
+
+    wp<IBinder> weak = inBinder;
+    inBinder = nullptr;
+    outBinder = nullptr;
+
+    // Force reading a reply, to process any pending dec refs from the other
+    // process (the other process will process dec refs there before processing
+    // the ping here).
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+    EXPECT_EQ(nullptr, weak.promote());
+
+    EXPECT_EQ(0, MyBinderRpcSession::gNum);
+}
+
+TEST_P(BinderRpc, RepeatTheirBinder) {
+    auto proc = createRpcTestSocketServerProcess({});
+
+    sp<IBinderRpcSession> session;
+    EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
+
+    sp<IBinder> inBinder = IInterface::asBinder(session);
+    sp<IBinder> outBinder;
+    EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
+    EXPECT_EQ(inBinder, outBinder);
+
+    wp<IBinder> weak = inBinder;
+    session = nullptr;
+    inBinder = nullptr;
+    outBinder = nullptr;
+
+    // Force reading a reply, to process any pending dec refs from the other
+    // process (the other process will process dec refs there before processing
+    // the ping here).
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+    EXPECT_EQ(nullptr, weak.promote());
+}
+
+TEST_P(BinderRpc, RepeatBinderNull) {
+    auto proc = createRpcTestSocketServerProcess({});
+
+    sp<IBinder> outBinder;
+    EXPECT_OK(proc.rootIface->repeatBinder(nullptr, &outBinder));
+    EXPECT_EQ(nullptr, outBinder);
+}
+
+TEST_P(BinderRpc, HoldBinder) {
+    auto proc = createRpcTestSocketServerProcess({});
+
+    IBinder* ptr = nullptr;
+    {
+        sp<IBinder> binder = new BBinder();
+        ptr = binder.get();
+        EXPECT_OK(proc.rootIface->holdBinder(binder));
+    }
+
+    sp<IBinder> held;
+    EXPECT_OK(proc.rootIface->getHeldBinder(&held));
+
+    EXPECT_EQ(held.get(), ptr);
+
+    // stop holding binder, because we test to make sure references are cleaned
+    // up
+    EXPECT_OK(proc.rootIface->holdBinder(nullptr));
+    // and flush ref counts
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+}
+
+// START TESTS FOR LIMITATIONS OF SOCKET BINDER
+// These are behavioral differences form regular binder, where certain usecases
+// aren't supported.
+
+TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketSessions) {
+    auto proc1 = createRpcTestSocketServerProcess({});
+    auto proc2 = createRpcTestSocketServerProcess({});
+
+    sp<IBinder> outBinder;
+    EXPECT_EQ(INVALID_OPERATION,
+              proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
+}
+
+TEST_P(BinderRpc, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
+    if (serverSingleThreaded()) {
+        GTEST_SKIP() << "This test requires a multi-threaded service";
+    }
+
+    auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 2});
+
+    sp<IBinder> outBinder;
+    EXPECT_EQ(INVALID_OPERATION,
+              proc.rootIface->repeatBinder(proc.proc->sessions.at(1).root, &outBinder)
+                      .transactionError());
+}
+
+TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
+    if (!kEnableKernelIpc || noKernel()) {
+        GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+                        "at build time.";
+    }
+
+    auto proc = createRpcTestSocketServerProcess({});
+
+    sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
+    sp<IBinder> outBinder;
+    EXPECT_EQ(INVALID_OPERATION,
+              proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError());
+}
+
+TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
+    if (!kEnableKernelIpc || noKernel()) {
+        GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+                        "at build time.";
+    }
+
+    auto proc = createRpcTestSocketServerProcess({});
+
+    // for historical reasons, IServiceManager interface only returns the
+    // exception code
+    EXPECT_EQ(binder::Status::EX_TRANSACTION_FAILED,
+              defaultServiceManager()->addService(String16("not_suspicious"), proc.rootBinder));
+}
+
+// END TESTS FOR LIMITATIONS OF SOCKET BINDER
+
+TEST_P(BinderRpc, RepeatRootObject) {
+    auto proc = createRpcTestSocketServerProcess({});
+
+    sp<IBinder> outBinder;
+    EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &outBinder));
+    EXPECT_EQ(proc.rootBinder, outBinder);
+}
+
+TEST_P(BinderRpc, NestedTransactions) {
+    auto proc = createRpcTestSocketServerProcess({
+            // Enable FD support because it uses more stack space and so represents
+            // something closer to a worst case scenario.
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::UNIX},
+    });
+
+    auto nastyNester = sp<MyBinderRpcTest>::make();
+    EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
+
+    wp<IBinder> weak = nastyNester;
+    nastyNester = nullptr;
+    EXPECT_EQ(nullptr, weak.promote());
+}
+
+TEST_P(BinderRpc, SameBinderEquality) {
+    auto proc = createRpcTestSocketServerProcess({});
+
+    sp<IBinder> a;
+    EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
+
+    sp<IBinder> b;
+    EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
+
+    EXPECT_EQ(a, b);
+}
+
+TEST_P(BinderRpc, SameBinderEqualityWeak) {
+    auto proc = createRpcTestSocketServerProcess({});
+
+    sp<IBinder> a;
+    EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
+    wp<IBinder> weak = a;
+    a = nullptr;
+
+    sp<IBinder> b;
+    EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
+
+    // this is the wrong behavior, since BpBinder
+    // doesn't implement onIncStrongAttempted
+    // but make sure there is no crash
+    EXPECT_EQ(nullptr, weak.promote());
+
+    GTEST_SKIP() << "Weak binders aren't currently re-promotable for RPC binder.";
+
+    // In order to fix this:
+    // - need to have incStrongAttempted reflected across IPC boundary (wait for
+    //   response to promote - round trip...)
+    // - sendOnLastWeakRef, to delete entries out of RpcState table
+    EXPECT_EQ(b, weak.promote());
+}
+
+#define expectSessions(expected, iface)                   \
+    do {                                                  \
+        int session;                                      \
+        EXPECT_OK((iface)->getNumOpenSessions(&session)); \
+        EXPECT_EQ(expected, session);                     \
+    } while (false)
+
+TEST_P(BinderRpc, SingleSession) {
+    auto proc = createRpcTestSocketServerProcess({});
+
+    sp<IBinderRpcSession> session;
+    EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
+    std::string out;
+    EXPECT_OK(session->getName(&out));
+    EXPECT_EQ("aoeu", out);
+
+    expectSessions(1, proc.rootIface);
+    session = nullptr;
+    expectSessions(0, proc.rootIface);
+}
+
+TEST_P(BinderRpc, ManySessions) {
+    auto proc = createRpcTestSocketServerProcess({});
+
+    std::vector<sp<IBinderRpcSession>> sessions;
+
+    for (size_t i = 0; i < 15; i++) {
+        expectSessions(i, proc.rootIface);
+        sp<IBinderRpcSession> session;
+        EXPECT_OK(proc.rootIface->openSession(std::to_string(i), &session));
+        sessions.push_back(session);
+    }
+    expectSessions(sessions.size(), proc.rootIface);
+    for (size_t i = 0; i < sessions.size(); i++) {
+        std::string out;
+        EXPECT_OK(sessions.at(i)->getName(&out));
+        EXPECT_EQ(std::to_string(i), out);
+    }
+    expectSessions(sessions.size(), proc.rootIface);
+
+    while (!sessions.empty()) {
+        sessions.pop_back();
+        expectSessions(sessions.size(), proc.rootIface);
+    }
+    expectSessions(0, proc.rootIface);
+}
+
+TEST_P(BinderRpc, OnewayCallDoesNotWait) {
+    constexpr size_t kReallyLongTimeMs = 100;
+    constexpr size_t kSleepMs = kReallyLongTimeMs * 5;
+
+    auto proc = createRpcTestSocketServerProcess({});
+
+    size_t epochMsBefore = epochMillis();
+
+    EXPECT_OK(proc.rootIface->sleepMsAsync(kSleepMs));
+
+    size_t epochMsAfter = epochMillis();
+    EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
+}
+
+TEST_P(BinderRpc, Callbacks) {
+    const static std::string kTestString = "good afternoon!";
+
+    for (bool callIsOneway : {true, false}) {
+        for (bool callbackIsOneway : {true, false}) {
+            for (bool delayed : {true, false}) {
+                if (clientOrServerSingleThreaded() &&
+                    (callIsOneway || callbackIsOneway || delayed)) {
+                    // we have no incoming connections to receive the callback
+                    continue;
+                }
+
+                size_t numIncomingConnections = clientOrServerSingleThreaded() ? 0 : 1;
+                auto proc = createRpcTestSocketServerProcess(
+                        {.numThreads = 1,
+                         .numSessions = 1,
+                         .numIncomingConnections = numIncomingConnections});
+                auto cb = sp<MyBinderRpcCallback>::make();
+
+                if (callIsOneway) {
+                    EXPECT_OK(proc.rootIface->doCallbackAsync(cb, callbackIsOneway, delayed,
+                                                              kTestString));
+                } else {
+                    EXPECT_OK(
+                            proc.rootIface->doCallback(cb, callbackIsOneway, delayed, kTestString));
+                }
+
+                // if both transactions are synchronous and the response is sent back on the
+                // same thread, everything should have happened in a nested call. Otherwise,
+                // the callback will be processed on another thread.
+                if (callIsOneway || callbackIsOneway || delayed) {
+                    using std::literals::chrono_literals::operator""s;
+                    RpcMutexUniqueLock _l(cb->mMutex);
+                    cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
+                }
+
+                EXPECT_EQ(cb->mValues.size(), 1)
+                        << "callIsOneway: " << callIsOneway
+                        << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
+                if (cb->mValues.empty()) continue;
+                EXPECT_EQ(cb->mValues.at(0), kTestString)
+                        << "callIsOneway: " << callIsOneway
+                        << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
+
+                // since we are severing the connection, we need to go ahead and
+                // tell the server to shutdown and exit so that waitpid won't hang
+                if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
+                    EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+                }
+
+                // since this session has an incoming connection w/ a threadpool, we
+                // need to manually shut it down
+                EXPECT_TRUE(proc.proc->sessions.at(0).session->shutdownAndWait(true));
+                proc.expectAlreadyShutdown = true;
+            }
+        }
+    }
+}
+
+TEST_P(BinderRpc, OnewayCallbackWithNoThread) {
+    auto proc = createRpcTestSocketServerProcess({});
+    auto cb = sp<MyBinderRpcCallback>::make();
+
+    Status status = proc.rootIface->doCallback(cb, true /*oneway*/, false /*delayed*/, "anything");
+    EXPECT_EQ(WOULD_BLOCK, status.transactionError());
+}
+
+TEST_P(BinderRpc, AidlDelegatorTest) {
+    auto proc = createRpcTestSocketServerProcess({});
+    auto myDelegator = sp<IBinderRpcTestDelegator>::make(proc.rootIface);
+    ASSERT_NE(nullptr, myDelegator);
+
+    std::string doubled;
+    EXPECT_OK(myDelegator->doubleString("cool ", &doubled));
+    EXPECT_EQ("cool cool ", doubled);
+}
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 3904e1d..35866ad 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -12,13 +12,17 @@
     host_supported: true,
     unstable: true,
     srcs: [
-        "EmptyParcelable.aidl",
-        "SingleDataParcelable.aidl",
-        "GenericDataParcelable.aidl",
+        "parcelables/EmptyParcelable.aidl",
+        "parcelables/SingleDataParcelable.aidl",
+        "parcelables/GenericDataParcelable.aidl",
     ],
     backend: {
         java: {
-            enabled: false,
+            enabled: true,
+            platform_apis: true,
+        },
+        rust: {
+            enabled: true,
         },
     },
 }
diff --git a/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl b/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl
deleted file mode 100644
index 96d6223..0000000
--- a/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-parcelable EmptyParcelable{
-}
\ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 9dac2c9..768fbe1 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -16,9 +16,9 @@
 #define FUZZ_LOG_TAG "binder"
 
 #include "binder.h"
-#include "EmptyParcelable.h"
-#include "GenericDataParcelable.h"
-#include "SingleDataParcelable.h"
+#include "parcelables/EmptyParcelable.h"
+#include "parcelables/GenericDataParcelable.h"
+#include "parcelables/SingleDataParcelable.h"
 #include "util.h"
 
 #include <android-base/hex.h>
@@ -359,19 +359,19 @@
     },
     [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to call readFromParcel() with status for EmptyParcelable";
-        EmptyParcelable emptyParcelable{};
+        parcelables::EmptyParcelable emptyParcelable{};
         status_t status = emptyParcelable.readFromParcel(&p);
         FUZZ_LOG() << " status: " << status;
     },
     [] (const ::android::Parcel& p , FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to call readFromParcel() with status for SingleDataParcelable";
-        SingleDataParcelable singleDataParcelable;
+        parcelables::SingleDataParcelable singleDataParcelable;
         status_t status = singleDataParcelable.readFromParcel(&p);
         FUZZ_LOG() <<" status: " << status;
     },
     [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to call readFromParcel() with status for GenericDataParcelable";
-        GenericDataParcelable genericDataParcelable;
+        parcelables::GenericDataParcelable genericDataParcelable;
         status_t status = genericDataParcelable.readFromParcel(&p);
         FUZZ_LOG() <<" status: " << status;
     },
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index af773a0..53e7de4 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -16,9 +16,9 @@
 #define FUZZ_LOG_TAG "binder_ndk"
 
 #include "binder_ndk.h"
-#include "aidl/EmptyParcelable.h"
-#include "aidl/GenericDataParcelable.h"
-#include "aidl/SingleDataParcelable.h"
+#include "aidl/parcelables/EmptyParcelable.h"
+#include "aidl/parcelables/GenericDataParcelable.h"
+#include "aidl/parcelables/SingleDataParcelable.h"
 
 #include <android/binder_parcel_utils.h>
 #include <android/binder_parcelable_utils.h>
@@ -183,19 +183,19 @@
 
         [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
             FUZZ_LOG() << "about to read parcel using readFromParcel for EmptyParcelable";
-            aidl::EmptyParcelable emptyParcelable;
+            aidl::parcelables::EmptyParcelable emptyParcelable;
             binder_status_t status = emptyParcelable.readFromParcel(p.aParcel());
             FUZZ_LOG() << "status: " << status;
         },
         [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
             FUZZ_LOG() << "about to read parcel using readFromParcel for SingleDataParcelable";
-            aidl::SingleDataParcelable singleDataParcelable;
+            aidl::parcelables::SingleDataParcelable singleDataParcelable;
             binder_status_t status = singleDataParcelable.readFromParcel(p.aParcel());
             FUZZ_LOG() << "status: " << status;
         },
         [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
             FUZZ_LOG() << "about to read parcel using readFromParcel for GenericDataParcelable";
-            aidl::GenericDataParcelable genericDataParcelable;
+            aidl::parcelables::GenericDataParcelable genericDataParcelable;
             binder_status_t status = genericDataParcelable.readFromParcel(p.aParcel());
             FUZZ_LOG() << "status: " << status;
         },
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index 25f6096..8bef33f 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -18,6 +18,7 @@
 #include <fuzzbinder/random_parcel.h>
 
 #include <android-base/logging.h>
+#include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 
 namespace android {
@@ -30,10 +31,19 @@
             .extraFds = {},
     };
 
+    if (provider.ConsumeBool()) {
+        // set calling uid
+        IPCThreadState::self()->restoreCallingIdentity(provider.ConsumeIntegral<int64_t>());
+    }
+
     while (provider.remaining_bytes() > 0) {
-        uint32_t code = provider.ConsumeIntegral<uint32_t>();
+        // Most of the AIDL services will have small set of transaction codes.
+        uint32_t code = provider.ConsumeBool() ? provider.ConsumeIntegral<uint32_t>()
+                                               : provider.ConsumeIntegralInRange<uint32_t>(0, 100);
         uint32_t flags = provider.ConsumeIntegral<uint32_t>();
         Parcel data;
+        // for increased fuzz coverage
+        data.setEnforceNoDataAvail(provider.ConsumeBool());
 
         sp<IBinder> target = options.extraBinders.at(
                 provider.ConsumeIntegralInRange<size_t>(0, options.extraBinders.size() - 1));
@@ -50,6 +60,8 @@
         fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), &options);
 
         Parcel reply;
+        // for increased fuzz coverage
+        reply.setEnforceNoDataAvail(provider.ConsumeBool());
         (void)target->transact(code, data, &reply, flags);
 
         // feed back in binders and fds that are returned from the service, so that
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
index 462ef9a..a1fb701 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
@@ -29,3 +29,12 @@
 }
 
 } // namespace android
+
+extern "C" {
+// This API is used by fuzzers to automatically fuzz aidl services
+void fuzzRustService(void* binder, const uint8_t* data, size_t len) {
+    AIBinder* aiBinder = static_cast<AIBinder*>(binder);
+    FuzzedDataProvider provider(data, len);
+    android::fuzzService(aiBinder, std::move(provider));
+}
+} // extern "C"
diff --git a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/parcelables/EmptyParcelable.aidl
similarity index 92%
copy from libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
copy to libs/binder/tests/parcel_fuzzer/parcelables/EmptyParcelable.aidl
index d62891b..1216250 100644
--- a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
+++ b/libs/binder/tests/parcel_fuzzer/parcelables/EmptyParcelable.aidl
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-parcelable SingleDataParcelable{
-   int data;
+package parcelables;
+parcelable EmptyParcelable {
 }
\ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl
similarity index 97%
rename from libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
rename to libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl
index fc2542b..f1079e9 100644
--- a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
+++ b/libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package parcelables;
 
 parcelable GenericDataParcelable {
     int data;
diff --git a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/parcelables/SingleDataParcelable.aidl
similarity index 96%
rename from libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
rename to libs/binder/tests/parcel_fuzzer/parcelables/SingleDataParcelable.aidl
index d62891b..0187168 100644
--- a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
+++ b/libs/binder/tests/parcel_fuzzer/parcelables/SingleDataParcelable.aidl
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package parcelables;
 
 parcelable SingleDataParcelable{
    int data;
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index edc695f..f0beed2 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -73,6 +73,11 @@
                                                                                 1));
                         CHECK(OK == p->writeFileDescriptor(fd.get(), false /*takeOwnership*/));
                     } else {
+                        // b/260119717 - Adding more FDs can eventually lead to FD limit exhaustion
+                        if (options->extraFds.size() > 1000) {
+                            return;
+                        }
+
                         std::vector<base::unique_fd> fds = getRandomFds(&provider);
                         CHECK(OK ==
                               p->writeFileDescriptor(fds.begin()->release(),
diff --git a/libs/binder/tests/parcel_fuzzer/rust_interface/Android.bp b/libs/binder/tests/parcel_fuzzer/rust_interface/Android.bp
new file mode 100644
index 0000000..b48dc27
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/rust_interface/Android.bp
@@ -0,0 +1,24 @@
+package {
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_static {
+    name: "libbinder_create_parcel",
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    srcs: [
+        "RandomParcelWrapper.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "libbinder_random_parcel",
+    ],
+}
diff --git a/libs/binder/tests/parcel_fuzzer/rust_interface/RandomParcelWrapper.cpp b/libs/binder/tests/parcel_fuzzer/rust_interface/RandomParcelWrapper.cpp
new file mode 100644
index 0000000..2fb7820
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/rust_interface/RandomParcelWrapper.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_libbinder.h>
+#include <android/binder_parcel.h>
+#include <fuzzbinder/random_parcel.h>
+
+extern "C" {
+
+void createRandomParcel(void* aParcel, const uint8_t* data, size_t len) {
+    CHECK_NE(aParcel, nullptr);
+    AParcel* parcel = static_cast<AParcel*>(aParcel);
+    FuzzedDataProvider provider(data, len);
+    android::RandomParcelOptions options;
+
+    android::Parcel* platformParcel = AParcel_viewPlatformParcel(parcel);
+    fillRandomParcel(platformParcel, std::move(provider), &options);
+}
+
+} // extern "C"
\ No newline at end of file
diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp
index 397ff41..8ec9823 100644
--- a/libs/binder/trusty/OS.cpp
+++ b/libs/binder/trusty/OS.cpp
@@ -59,14 +59,14 @@
     return RpcTransportCtxFactoryTipcTrusty::make();
 }
 
-int sendMessageOnSocket(
+ssize_t sendMessageOnSocket(
         const RpcTransportFd& /* socket */, iovec* /* iovs */, int /* niovs */,
         const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /* ancillaryFds */) {
     errno = ENOTSUP;
     return -1;
 }
 
-int receiveMessageFromSocket(
+ssize_t receiveMessageFromSocket(
         const RpcTransportFd& /* socket */, iovec* /* iovs */, int /* niovs */,
         std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /* ancillaryFds */) {
     errno = ENOTSUP;
diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
index 58bfe71..d249b2e 100644
--- a/libs/binder/trusty/RpcTransportTipcTrusty.cpp
+++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
@@ -239,6 +239,12 @@
         }
         if (!(uevt.event & IPC_HANDLE_POLL_MSG)) {
             /* No message, terminate here and leave mHaveMessage false */
+            if (uevt.event & IPC_HANDLE_POLL_HUP) {
+                // Peer closed the connection. We need to preserve the order
+                // between MSG and HUP from FdTrigger.cpp, which means that
+                // getting MSG&HUP should return OK instead of DEAD_OBJECT.
+                return DEAD_OBJECT;
+            }
             return OK;
         }
 
diff --git a/libs/binder/trusty/include/log/log.h b/libs/binder/trusty/include/log/log.h
index bf877a3..de84617 100644
--- a/libs/binder/trusty/include/log/log.h
+++ b/libs/binder/trusty/include/log/log.h
@@ -120,3 +120,9 @@
     do {                                                                 \
         TLOGE("android_errorWriteLog: tag:%x subTag:%s\n", tag, subTag); \
     } while (0)
+
+// Override the definition of __assert from binder_status.h
+#ifndef __BIONIC__
+#undef __assert
+#define __assert(file, line, str) LOG_ALWAYS_FATAL("%s:%d: %s", file, line, str)
+#endif // __BIONIC__
diff --git a/libs/binder/trusty/kernel/rules.mk b/libs/binder/trusty/kernel/rules.mk
new file mode 100644
index 0000000..ab7a50d
--- /dev/null
+++ b/libs/binder/trusty/kernel/rules.mk
@@ -0,0 +1,83 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+LIBBINDER_DIR := frameworks/native/libs/binder
+LIBBASE_DIR := system/libbase
+LIBCUTILS_DIR := system/core/libcutils
+LIBUTILS_DIR := system/core/libutils
+FMTLIB_DIR := external/fmtlib
+
+MODULE_SRCS := \
+	$(LOCAL_DIR)/../logging.cpp \
+	$(LOCAL_DIR)/../TrustyStatus.cpp \
+	$(LIBBINDER_DIR)/Binder.cpp \
+	$(LIBBINDER_DIR)/BpBinder.cpp \
+	$(LIBBINDER_DIR)/FdTrigger.cpp \
+	$(LIBBINDER_DIR)/IInterface.cpp \
+	$(LIBBINDER_DIR)/IResultReceiver.cpp \
+	$(LIBBINDER_DIR)/Parcel.cpp \
+	$(LIBBINDER_DIR)/Stability.cpp \
+	$(LIBBINDER_DIR)/Status.cpp \
+	$(LIBBINDER_DIR)/Utils.cpp \
+	$(LIBBASE_DIR)/hex.cpp \
+	$(LIBBASE_DIR)/stringprintf.cpp \
+	$(LIBUTILS_DIR)/Errors.cpp \
+	$(LIBUTILS_DIR)/misc.cpp \
+	$(LIBUTILS_DIR)/RefBase.cpp \
+	$(LIBUTILS_DIR)/StrongPointer.cpp \
+	$(LIBUTILS_DIR)/Unicode.cpp \
+
+# TODO: remove the following when libbinder supports std::string
+# instead of String16 and String8 for Status and descriptors
+MODULE_SRCS += \
+	$(LIBUTILS_DIR)/SharedBuffer.cpp \
+	$(LIBUTILS_DIR)/String16.cpp \
+	$(LIBUTILS_DIR)/String8.cpp \
+
+# TODO: disable dump() transactions to get rid of Vector
+MODULE_SRCS += \
+	$(LIBUTILS_DIR)/VectorImpl.cpp \
+
+MODULE_DEFINES += \
+	LK_DEBUGLEVEL_NO_ALIASES=1 \
+
+MODULE_INCLUDES += \
+	$(LOCAL_DIR)/.. \
+
+GLOBAL_INCLUDES += \
+	$(LOCAL_DIR)/include \
+	$(LOCAL_DIR)/../include \
+	$(LIBBINDER_DIR)/include \
+	$(LIBBINDER_DIR)/ndk/include_cpp \
+	$(LIBBASE_DIR)/include \
+	$(LIBCUTILS_DIR)/include \
+	$(LIBUTILS_DIR)/include \
+	$(FMTLIB_DIR)/include \
+
+GLOBAL_COMPILEFLAGS += \
+	-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION \
+	-DBINDER_NO_KERNEL_IPC \
+	-DBINDER_RPC_SINGLE_THREADED \
+	-D__ANDROID_VNDK__ \
+
+MODULE_DEPS += \
+	trusty/kernel/lib/libcxx-trusty \
+	trusty/kernel/lib/libcxxabi-trusty \
+
+include make/module.mk
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index a6585c5..067ce17 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -208,5 +208,5 @@
     cmdline = std::string(cmdline.c_str());
 
     return cmdline == "zygote" || cmdline == "zygote64" || cmdline == "usap32" ||
-            cmdline == "usap64";
+            cmdline == "usap64" || cmdline == "webview_zygote";
 }
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 6c6d7f3..1109ad8 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -36,6 +36,9 @@
 status_t ServiceManager::addService(const String16& name, const sp<IBinder>& service,
                                 bool /*allowIsolated*/,
                                 int /*dumpsysFlags*/) {
+    if (service == nullptr) {
+        return UNEXPECTED_NULL;
+    }
     mNameToService[name] = service;
     return NO_ERROR;
 }
@@ -78,6 +81,11 @@
     return std::nullopt;
 }
 
+Vector<String16> ServiceManager::getUpdatableNames(const String16& apexName) {
+    (void)apexName;
+    return {};
+}
+
 std::optional<IServiceManager::ConnectionInfo> ServiceManager::getConnectionInfo(
         const String16& name) {
     (void)name;
@@ -98,4 +106,8 @@
     std::vector<IServiceManager::ServiceDebugInfo> ret;
     return ret;
 }
+
+void ServiceManager::clear() {
+    mNameToService.clear();
+}
 }  // namespace android
diff --git a/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h
index e0af5d4..ba6bb7d 100644
--- a/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h
@@ -52,6 +52,8 @@
 
     std::optional<String16> updatableViaApex(const String16& name) override;
 
+    Vector<String16> getUpdatableNames(const String16& apexName) override;
+
     std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override;
 
     status_t registerForNotifications(const String16& name,
@@ -62,6 +64,9 @@
 
     std::vector<IServiceManager::ServiceDebugInfo> getServiceDebugInfo() override;
 
+    // Clear all of the registered services
+    void clear();
+
 private:
     std::map<String16, sp<IBinder>> mNameToService;
 };
diff --git a/libs/fakeservicemanager/test_sm.cpp b/libs/fakeservicemanager/test_sm.cpp
index 71e5abe..8682c1c 100644
--- a/libs/fakeservicemanager/test_sm.cpp
+++ b/libs/fakeservicemanager/test_sm.cpp
@@ -50,6 +50,12 @@
         IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
 }
 
+TEST(AddService, SadNullBinder) {
+    auto sm = new ServiceManager();
+    EXPECT_EQ(sm->addService(String16("foo"), nullptr, false /*allowIsolated*/,
+        IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), android::UNEXPECTED_NULL);
+}
+
 TEST(AddService, HappyOverExistingService) {
     auto sm = new ServiceManager();
     EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/,
@@ -58,6 +64,15 @@
         IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
 }
 
+TEST(AddService, HappyClearAddedService) {
+    auto sm = new ServiceManager();
+    EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/,
+        IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+    EXPECT_NE(sm->getService(String16("foo")), nullptr);
+    sm->clear();
+    EXPECT_EQ(sm->getService(String16("foo")), nullptr);
+}
+
 TEST(GetService, HappyHappy) {
     auto sm = new ServiceManager();
     sp<IBinder> service = getBinder();
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index bd21fba..f5af425 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -51,14 +51,14 @@
     ],
 
     shared_libs: [
-        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.graphics.common-V4-ndk",
         "android.hardware.graphics.mapper@4.0",
         "libhidlbase",
         "liblog",
     ],
 
     export_shared_lib_headers: [
-        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.graphics.common-V4-ndk",
         "android.hardware.graphics.mapper@4.0",
         "libhidlbase",
     ],
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 7f0cac5..4a0a839 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -364,26 +364,61 @@
     return (mUseAngle == YES) ? true : false;
 }
 
+bool GraphicsEnv::angleIsSystemDriver() {
+    // Make sure we are init'ed
+    if (mAngleAppName.empty()) {
+        ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE.");
+        return false;
+    }
+
+    return (mAngleIsSystemDriver == YES) ? true : false;
+}
+
+bool GraphicsEnv::shouldForceLegacyDriver() {
+    // Make sure we are init'ed
+    if (mAngleAppName.empty()) {
+        ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE.");
+        return false;
+    }
+
+    return (mAngleIsSystemDriver == YES && mUseAngle == NO) ? true : false;
+}
+
+std::string GraphicsEnv::getLegacySuffix() {
+    return mLegacyDriverSuffix;
+}
+
 void GraphicsEnv::updateUseAngle() {
     mUseAngle = NO;
 
     const char* ANGLE_PREFER_ANGLE = "angle";
+    const char* ANGLE_PREFER_LEGACY = "legacy";
+    // The following is a deprecated version of "legacy"
     const char* ANGLE_PREFER_NATIVE = "native";
 
     mUseAngle = NO;
     if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) {
-        ALOGV("User set \"Developer Options\" to force the use of ANGLE");
+        ALOGI("Using ANGLE, the %s GLES driver for package '%s'",
+              mAngleIsSystemDriver == YES ? "system" : "optional", mAngleAppName.c_str());
         mUseAngle = YES;
-    } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) {
-        ALOGV("User set \"Developer Options\" to force the use of Native");
+    } else if (mAngleDeveloperOptIn == ANGLE_PREFER_LEGACY ||
+               mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) {
+        ALOGI("Using the (%s) Legacy GLES driver for package '%s'",
+              mAngleIsSystemDriver == YES ? "optional" : "system", mAngleAppName.c_str());
     } else {
         ALOGV("User set invalid \"Developer Options\": '%s'", mAngleDeveloperOptIn.c_str());
     }
 }
 
 void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
-                               const std::string developerOptIn,
+                               const bool angleIsSystemDriver, const std::string developerOptIn,
                                const std::vector<std::string> eglFeatures) {
+    // Set whether ANGLE is the system driver:
+    mAngleIsSystemDriver = angleIsSystemDriver ? YES : NO;
+
+    // Note: Given the current logic and lack of the old rules file processing,
+    // there seems to be little chance that mUseAngle != UNKNOWN.  Leave this
+    // for now, even though it seems outdated.
     if (mUseAngle != UNKNOWN) {
         // We've already figured out an answer for this app, so just return.
         ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", appName.c_str(),
@@ -404,6 +439,25 @@
     updateUseAngle();
 }
 
+void GraphicsEnv::setLegacyDriverInfo(const std::string appName, const bool angleIsSystemDriver,
+                                      const std::string legacyDriverName) {
+    ALOGV("setting legacy app name to '%s'", appName.c_str());
+    mAngleAppName = appName;
+
+    // Force the use of the legacy driver instead of ANGLE
+    const char* ANGLE_PREFER_LEGACY = "legacy";
+    mAngleDeveloperOptIn = ANGLE_PREFER_LEGACY;
+    ALOGV("setting ANGLE application opt-in to 'legacy'");
+
+    // Set whether ANGLE is the system driver:
+    mAngleIsSystemDriver = angleIsSystemDriver ? YES : NO;
+
+    mLegacyDriverSuffix = legacyDriverName;
+
+    // Update the current status of whether we should use ANGLE or not
+    updateUseAngle();
+}
+
 void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) {
     if (mLayerPaths.empty()) {
         mLayerPaths = layerPaths;
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 56d1139..82a6b6c 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -91,17 +91,28 @@
     bool shouldUseAngle(std::string appName);
     // Check if this app process should use ANGLE.
     bool shouldUseAngle();
+    // If ANGLE is the system GLES driver
+    bool angleIsSystemDriver();
+    // If should use legacy driver instead of a system ANGLE driver
+    bool shouldForceLegacyDriver();
     // Set a search path for loading ANGLE libraries. The path is a list of
     // directories separated by ':'. A directory can be contained in a zip file
     // (libraries must be stored uncompressed and page aligned); such elements
     // in the search path must have a '!' after the zip filename, e.g.
     //     /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
-    void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn,
+    void setAngleInfo(const std::string path, const std::string appName,
+                      const bool angleIsSystemDriver, std::string devOptIn,
                       const std::vector<std::string> eglFeatures);
+    // Set the state so that the legacy driver will be used, and in case ANGLE
+    // is the system driver, provide the name of the legacy driver.
+    void setLegacyDriverInfo(const std::string appName, const bool angleIsSystemDriver,
+                             const std::string legacyDriverName);
     // Get the ANGLE driver namespace.
     android_namespace_t* getAngleNamespace();
     // Get the app name for ANGLE debug message.
     std::string& getAngleAppName();
+    // Get the legacy driver's suffix name.
+    std::string getLegacySuffix();
 
     const std::vector<std::string>& getAngleEglFeatures();
 
@@ -156,6 +167,10 @@
     std::string mAngleDeveloperOptIn;
     // ANGLE EGL features;
     std::vector<std::string> mAngleEglFeatures;
+    // ANGLE is System Driver flag.
+    UseAngle mAngleIsSystemDriver = UNKNOWN;
+    // Legacy driver name to use when ANGLE is the system driver.
+    std::string mLegacyDriverSuffix;
     // Use ANGLE flag.
     UseAngle mUseAngle = UNKNOWN;
     // Vulkan debug layers libs.
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 56b17ae..2ac1174 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -177,8 +177,6 @@
 
         "BitTube.cpp",
         "BLASTBufferQueue.cpp",
-        "BufferHubConsumer.cpp",
-        "BufferHubProducer.cpp",
         "BufferItemConsumer.cpp",
         "ConsumerBase.cpp",
         "CpuConsumer.cpp",
@@ -216,9 +214,6 @@
 
     shared_libs: [
         "libbinder",
-        "libbufferhub",
-        "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
-        "libpdx_default_transport",
     ],
 
     export_shared_lib_headers: [
@@ -229,24 +224,6 @@
         "libgui_aidl_headers",
     ],
 
-    // bufferhub is not used when building libgui for vendors
-    target: {
-        vendor: {
-            cflags: [
-                "-DNO_BUFFERHUB",
-            ],
-            exclude_srcs: [
-                "BufferHubConsumer.cpp",
-                "BufferHubProducer.cpp",
-            ],
-            exclude_shared_libs: [
-                "libbufferhub",
-                "libbufferhubqueue",
-                "libpdx_default_transport",
-            ],
-        },
-    },
-
     aidl: {
         export_aidl_headers: true,
     },
@@ -276,7 +253,6 @@
     min_sdk_version: "29",
 
     cflags: [
-        "-DNO_BUFFERHUB",
         "-DNO_BINDER",
     ],
 
@@ -345,7 +321,7 @@
         "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.common@1.2",
-        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.graphics.common-V4-ndk",
         "android.hidl.token@1.0-utils",
         "libbase",
         "libcutils",
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index dbccf30..a51bbb1 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -287,18 +287,17 @@
 
                 // We need to check if we were waiting for a transaction callback in order to
                 // process any pending buffers and unblock. It's possible to get transaction
-                // callbacks for previous requests so we need to ensure the frame from this
-                // transaction callback matches the last acquired buffer. Since acquireNextBuffer
-                // will stop processing buffers when mWaitForTransactionCallback is set, we know
-                // that mLastAcquiredFrameNumber is the frame we're waiting on.
-                // We also want to check if mNextTransaction is null because it's possible another
+                // callbacks for previous requests so we need to ensure that there are no pending
+                // frame numbers that were in a sync. We remove the frame from mSyncedFrameNumbers
+                // set and then check if it's empty. If there are no more pending syncs, we can
+                // proceed with flushing the shadow queue.
+                // We also want to check if mSyncTransaction is null because it's possible another
                 // sync request came in while waiting, but it hasn't started processing yet. In that
                 // case, we don't actually want to flush the frames in between since they will get
                 // processed and merged with the sync transaction and released earlier than if they
                 // were sent to SF
-                if (mWaitForTransactionCallback && mSyncTransaction == nullptr &&
-                    currFrameNumber >= mLastAcquiredFrameNumber) {
-                    mWaitForTransactionCallback = false;
+                mSyncedFrameNumbers.erase(currFrameNumber);
+                if (mSyncedFrameNumbers.empty() && mSyncTransaction == nullptr) {
                     flushShadowQueue();
                 }
             } else {
@@ -308,7 +307,6 @@
             BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
                      "empty.");
         }
-
         decStrong((void*)transactionCommittedCallbackThunk);
     }
 }
@@ -351,6 +349,20 @@
                                                     stat.latchTime,
                                                     stat.frameEventStats.dequeueReadyTime);
                 }
+                auto currFrameNumber = stat.frameEventStats.frameNumber;
+                std::vector<ReleaseCallbackId> staleReleases;
+                for (const auto& [key, value]: mSubmitted) {
+                    if (currFrameNumber > key.framenumber) {
+                        staleReleases.push_back(key);
+                    }
+                }
+                for (const auto& staleRelease : staleReleases) {
+                    BQA_LOGE("Faking releaseBufferCallback from transactionCompleteCallback");
+                    BBQ_TRACE("FakeReleaseCallback");
+                    releaseBufferCallbackLocked(staleRelease,
+                        stat.previousReleaseFence ? stat.previousReleaseFence : Fence::NO_FENCE,
+                        stat.currentMaxAcquiredBufferCount);
+                }
             } else {
                 BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback");
             }
@@ -391,7 +403,14 @@
         const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
         std::optional<uint32_t> currentMaxAcquiredBufferCount) {
     BBQ_TRACE();
+
     std::unique_lock _lock{mMutex};
+    releaseBufferCallbackLocked(id, releaseFence, currentMaxAcquiredBufferCount);
+}
+
+void BLASTBufferQueue::releaseBufferCallbackLocked(const ReleaseCallbackId& id,
+        const sp<Fence>& releaseFence, std::optional<uint32_t> currentMaxAcquiredBufferCount) {
+    ATRACE_CALL();
     BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str());
 
     // Calculate how many buffers we need to hold before we release them back
@@ -409,16 +428,22 @@
 
     const auto numPendingBuffersToHold =
             isEGL ? std::max(0u, mMaxAcquiredBuffers - mCurrentMaxAcquiredBufferCount) : 0;
-    mPendingRelease.emplace_back(ReleasedBuffer{id, releaseFence});
+
+    auto rb = ReleasedBuffer{id, releaseFence};
+    if (std::find(mPendingRelease.begin(), mPendingRelease.end(), rb) == mPendingRelease.end()) {
+        mPendingRelease.emplace_back(rb);
+    }
 
     // Release all buffers that are beyond the ones that we need to hold
     while (mPendingRelease.size() > numPendingBuffersToHold) {
         const auto releasedBuffer = mPendingRelease.front();
         mPendingRelease.pop_front();
         releaseBuffer(releasedBuffer.callbackId, releasedBuffer.releaseFence);
-        // Don't process the transactions here if mWaitForTransactionCallback is set. Instead, let
-        // onFrameAvailable handle processing them since it will merge with the syncTransaction.
-        if (!mWaitForTransactionCallback) {
+        // Don't process the transactions here if mSyncedFrameNumbers is not empty. That means
+        // are still transactions that have sync buffers in them that have not been applied or
+        // dropped. Instead, let onFrameAvailable handle processing them since it will merge with
+        // the syncTransaction.
+        if (mSyncedFrameNumbers.empty()) {
             acquireNextBufferLocked(std::nullopt);
         }
     }
@@ -442,6 +467,9 @@
     BQA_LOGV("released %s", callbackId.to_string().c_str());
     mBufferItemConsumer->releaseBuffer(it->second, releaseFence);
     mSubmitted.erase(it);
+    // Remove the frame number from mSyncedFrameNumbers since we can get a release callback
+    // without getting a transaction committed if the buffer was dropped.
+    mSyncedFrameNumbers.erase(callbackId.framenumber);
 }
 
 void BLASTBufferQueue::acquireNextBufferLocked(
@@ -608,7 +636,7 @@
 }
 
 void BLASTBufferQueue::flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock) {
-    if (mWaitForTransactionCallback && mNumFrameAvailable > 0) {
+    if (!mSyncedFrameNumbers.empty() && mNumFrameAvailable > 0) {
         // We are waiting on a previous sync's transaction callback so allow another sync
         // transaction to proceed.
         //
@@ -635,6 +663,8 @@
 void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
     std::function<void(SurfaceComposerClient::Transaction*)> prevCallback = nullptr;
     SurfaceComposerClient::Transaction* prevTransaction = nullptr;
+    bool waitForTransactionCallback = !mSyncedFrameNumbers.empty();
+
     {
         BBQ_TRACE();
         std::unique_lock _lock{mMutex};
@@ -666,7 +696,7 @@
 
         // add to shadow queue
         mNumFrameAvailable++;
-        if (mWaitForTransactionCallback && mNumFrameAvailable >= 2) {
+        if (waitForTransactionCallback && mNumFrameAvailable >= 2) {
             acquireAndReleaseBuffer();
         }
         ATRACE_INT(mQueuedBufferTrace.c_str(),
@@ -683,14 +713,14 @@
             incStrong((void*)transactionCommittedCallbackThunk);
             mSyncTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk,
                                                               static_cast<void*>(this));
-            mWaitForTransactionCallback = true;
+            mSyncedFrameNumbers.emplace(item.mFrameNumber);
             if (mAcquireSingleBuffer) {
                 prevCallback = mTransactionReadyCallback;
                 prevTransaction = mSyncTransaction;
                 mTransactionReadyCallback = nullptr;
                 mSyncTransaction = nullptr;
             }
-        } else if (!mWaitForTransactionCallback) {
+        } else if (!waitForTransactionCallback) {
             acquireNextBufferLocked(std::nullopt);
         }
     }
@@ -1097,9 +1127,9 @@
     }
 
     // Clear sync states
-    if (mWaitForTransactionCallback) {
-        BQA_LOGD("mWaitForTransactionCallback cleared");
-        mWaitForTransactionCallback = false;
+    if (!mSyncedFrameNumbers.empty()) {
+        BQA_LOGD("mSyncedFrameNumbers cleared");
+        mSyncedFrameNumbers.clear();
     }
 
     if (mSyncTransaction != nullptr) {
diff --git a/libs/gui/BufferHubConsumer.cpp b/libs/gui/BufferHubConsumer.cpp
deleted file mode 100644
index b5cdeb2..0000000
--- a/libs/gui/BufferHubConsumer.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 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 <gui/BufferHubConsumer.h>
-
-namespace android {
-
-using namespace dvr;
-
-/* static */
-sp<BufferHubConsumer> BufferHubConsumer::Create(const std::shared_ptr<ConsumerQueue>& queue) {
-    sp<BufferHubConsumer> consumer = new BufferHubConsumer;
-    consumer->mQueue = queue;
-    return consumer;
-}
-
-/* static */ sp<BufferHubConsumer> BufferHubConsumer::Create(ConsumerQueueParcelable parcelable) {
-    if (!parcelable.IsValid()) {
-        ALOGE("BufferHubConsumer::Create: Invalid consumer parcelable.");
-        return nullptr;
-    }
-
-    sp<BufferHubConsumer> consumer = new BufferHubConsumer;
-    consumer->mQueue = ConsumerQueue::Import(parcelable.TakeChannelHandle());
-    return consumer;
-}
-
-status_t BufferHubConsumer::acquireBuffer(BufferItem* /*buffer*/, nsecs_t /*presentWhen*/,
-                                          uint64_t /*maxFrameNumber*/) {
-    ALOGE("BufferHubConsumer::acquireBuffer: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::detachBuffer(int /*slot*/) {
-    ALOGE("BufferHubConsumer::detachBuffer: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::attachBuffer(int* /*outSlot*/, const sp<GraphicBuffer>& /*buffer*/) {
-    ALOGE("BufferHubConsumer::attachBuffer: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::releaseBuffer(int /*buf*/, uint64_t /*frameNumber*/,
-                                          EGLDisplay /*display*/, EGLSyncKHR /*fence*/,
-                                          const sp<Fence>& /*releaseFence*/) {
-    ALOGE("BufferHubConsumer::releaseBuffer: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::consumerConnect(const sp<IConsumerListener>& /*consumer*/,
-                                            bool /*controlledByApp*/) {
-    ALOGE("BufferHubConsumer::consumerConnect: not implemented.");
-
-    // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to
-    // make IGraphicBufferConsumer_test happy.
-    return NO_ERROR;
-}
-
-status_t BufferHubConsumer::consumerDisconnect() {
-    ALOGE("BufferHubConsumer::consumerDisconnect: not implemented.");
-
-    // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to
-    // make IGraphicBufferConsumer_test happy.
-    return NO_ERROR;
-}
-
-status_t BufferHubConsumer::getReleasedBuffers(uint64_t* /*slotMask*/) {
-    ALOGE("BufferHubConsumer::getReleasedBuffers: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {
-    ALOGE("BufferHubConsumer::setDefaultBufferSize: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setMaxBufferCount(int /*bufferCount*/) {
-    ALOGE("BufferHubConsumer::setMaxBufferCount: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setMaxAcquiredBufferCount(int /*maxAcquiredBuffers*/) {
-    ALOGE("BufferHubConsumer::setMaxAcquiredBufferCount: not implemented.");
-
-    // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to
-    // make IGraphicBufferConsumer_test happy.
-    return NO_ERROR;
-}
-
-status_t BufferHubConsumer::setConsumerName(const String8& /*name*/) {
-    ALOGE("BufferHubConsumer::setConsumerName: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setDefaultBufferFormat(PixelFormat /*defaultFormat*/) {
-    ALOGE("BufferHubConsumer::setDefaultBufferFormat: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setDefaultBufferDataSpace(android_dataspace /*defaultDataSpace*/) {
-    ALOGE("BufferHubConsumer::setDefaultBufferDataSpace: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setConsumerUsageBits(uint64_t /*usage*/) {
-    ALOGE("BufferHubConsumer::setConsumerUsageBits: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setConsumerIsProtected(bool /*isProtected*/) {
-    ALOGE("BufferHubConsumer::setConsumerIsProtected: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::setTransformHint(uint32_t /*hint*/) {
-    ALOGE("BufferHubConsumer::setTransformHint: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::getSidebandStream(sp<NativeHandle>* /*outStream*/) const {
-    ALOGE("BufferHubConsumer::getSidebandStream: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::getOccupancyHistory(
-        bool /*forceFlush*/, std::vector<OccupancyTracker::Segment>* /*outHistory*/) {
-    ALOGE("BufferHubConsumer::getOccupancyHistory: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::discardFreeBuffers() {
-    ALOGE("BufferHubConsumer::discardFreeBuffers: not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubConsumer::dumpState(const String8& /*prefix*/, String8* /*outResult*/) const {
-    ALOGE("BufferHubConsumer::dumpState: not implemented.");
-    return INVALID_OPERATION;
-}
-
-IBinder* BufferHubConsumer::onAsBinder() {
-    ALOGE("BufferHubConsumer::onAsBinder: BufferHubConsumer should never be used as an Binder "
-          "object.");
-    return nullptr;
-}
-
-} // namespace android
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
deleted file mode 100644
index 1f71e23..0000000
--- a/libs/gui/BufferHubProducer.cpp
+++ /dev/null
@@ -1,868 +0,0 @@
-/*
- * Copyright 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 <dvr/dvr_api.h>
-#include <gui/BufferHubProducer.h>
-#include <inttypes.h>
-#include <log/log.h>
-#include <system/window.h>
-
-namespace android {
-
-using namespace dvr;
-
-/* static */
-sp<BufferHubProducer> BufferHubProducer::Create(const std::shared_ptr<ProducerQueue>& queue) {
-    sp<BufferHubProducer> producer = new BufferHubProducer;
-    producer->queue_ = queue;
-    return producer;
-}
-
-/* static */
-sp<BufferHubProducer> BufferHubProducer::Create(ProducerQueueParcelable parcelable) {
-    if (!parcelable.IsValid()) {
-        ALOGE("BufferHubProducer::Create: Invalid producer parcelable.");
-        return nullptr;
-    }
-
-    sp<BufferHubProducer> producer = new BufferHubProducer;
-    producer->queue_ = ProducerQueue::Import(parcelable.TakeChannelHandle());
-    return producer;
-}
-
-status_t BufferHubProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
-    ALOGV("requestBuffer: slot=%d", slot);
-
-    std::unique_lock<std::mutex> lock(mutex_);
-
-    if (connected_api_ == kNoConnectedApi) {
-        ALOGE("requestBuffer: BufferHubProducer has no connected producer");
-        return NO_INIT;
-    }
-
-    if (slot < 0 || slot >= max_buffer_count_) {
-        ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
-        return BAD_VALUE;
-    } else if (!buffers_[slot].mBufferState.isDequeued()) {
-        ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)", slot,
-              buffers_[slot].mBufferState.string());
-        return BAD_VALUE;
-    } else if (buffers_[slot].mGraphicBuffer != nullptr) {
-        ALOGE("requestBuffer: slot %d is not empty.", slot);
-        return BAD_VALUE;
-    } else if (buffers_[slot].mProducerBuffer == nullptr) {
-        ALOGE("requestBuffer: slot %d is not dequeued.", slot);
-        return BAD_VALUE;
-    }
-
-    const auto& producer_buffer = buffers_[slot].mProducerBuffer;
-    sp<GraphicBuffer> graphic_buffer = producer_buffer->buffer()->buffer();
-
-    buffers_[slot].mGraphicBuffer = graphic_buffer;
-    buffers_[slot].mRequestBufferCalled = true;
-
-    *buf = graphic_buffer;
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::setMaxDequeuedBufferCount(int max_dequeued_buffers) {
-    ALOGV("setMaxDequeuedBufferCount: max_dequeued_buffers=%d", max_dequeued_buffers);
-
-    std::unique_lock<std::mutex> lock(mutex_);
-
-    if (max_dequeued_buffers <= 0 ||
-        max_dequeued_buffers >
-                int(BufferHubQueue::kMaxQueueCapacity - kDefaultUndequeuedBuffers)) {
-        ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]", max_dequeued_buffers,
-              BufferHubQueue::kMaxQueueCapacity);
-        return BAD_VALUE;
-    }
-
-    // The new dequeued_buffers count should not be violated by the number
-    // of currently dequeued buffers.
-    int dequeued_count = 0;
-    for (const auto& buf : buffers_) {
-        if (buf.mBufferState.isDequeued()) {
-            dequeued_count++;
-        }
-    }
-    if (dequeued_count > max_dequeued_buffers) {
-        ALOGE("setMaxDequeuedBufferCount: the requested dequeued_buffers"
-              "count (%d) exceeds the current dequeued buffer count (%d)",
-              max_dequeued_buffers, dequeued_count);
-        return BAD_VALUE;
-    }
-
-    max_dequeued_buffer_count_ = max_dequeued_buffers;
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::setAsyncMode(bool async) {
-    if (async) {
-        // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer
-        // automatically and behaves differently from IGraphicBufferConsumer. Thus,
-        // android::BufferQueue's async mode (a.k.a. allocating an additional buffer
-        // to prevent dequeueBuffer from being blocking) technically does not apply
-        // here.
-        //
-        // In Daydream, non-blocking producer side dequeue is guaranteed by careful
-        // buffer consumer implementations. In another word, BufferHubQueue based
-        // dequeueBuffer should never block whether setAsyncMode(true) is set or
-        // not.
-        //
-        // See: IGraphicBufferProducer::setAsyncMode and
-        // BufferQueueProducer::setAsyncMode for more about original implementation.
-        ALOGW("BufferHubProducer::setAsyncMode: BufferHubQueue should always be "
-              "asynchronous. This call makes no effact.");
-        return NO_ERROR;
-    }
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width,
-                                          uint32_t height, PixelFormat format, uint64_t usage,
-                                          uint64_t* /*outBufferAge*/,
-                                          FrameEventHistoryDelta* /* out_timestamps */) {
-    ALOGV("dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width, height, format, usage);
-
-    status_t ret;
-    std::unique_lock<std::mutex> lock(mutex_);
-
-    if (connected_api_ == kNoConnectedApi) {
-        ALOGE("dequeueBuffer: BufferQueue has no connected producer");
-        return NO_INIT;
-    }
-
-    const uint32_t kLayerCount = 1;
-    if (int32_t(queue_->capacity()) < max_dequeued_buffer_count_ + kDefaultUndequeuedBuffers) {
-        // Lazy allocation. When the capacity of |queue_| has not reached
-        // |max_dequeued_buffer_count_|, allocate new buffer.
-        // TODO(jwcai) To save memory, the really reasonable thing to do is to go
-        // over existing slots and find first existing one to dequeue.
-        ret = AllocateBuffer(width, height, kLayerCount, format, usage);
-        if (ret < 0) return ret;
-    }
-
-    size_t slot = 0;
-    std::shared_ptr<ProducerBuffer> producer_buffer;
-
-    for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) {
-        LocalHandle fence;
-        auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence);
-        if (!buffer_status) return NO_MEMORY;
-
-        producer_buffer = buffer_status.take();
-        if (!producer_buffer) return NO_MEMORY;
-
-        if (width == producer_buffer->width() && height == producer_buffer->height() &&
-            uint32_t(format) == producer_buffer->format()) {
-            // The producer queue returns a producer buffer matches the request.
-            break;
-        }
-
-        // Needs reallocation.
-        // TODO(jwcai) Consider use VLOG instead if we find this log is not useful.
-        ALOGI("dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different "
-              "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need "
-              "re-allocattion.",
-              width, height, format, slot, producer_buffer->width(), producer_buffer->height(),
-              producer_buffer->format());
-        // Mark the slot as reallocating, so that later we can set
-        // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued.
-        buffers_[slot].mIsReallocating = true;
-
-        // Remove the old buffer once the allocation before allocating its
-        // replacement.
-        RemoveBuffer(slot);
-
-        // Allocate a new producer buffer with new buffer configs. Note that if
-        // there are already multiple buffers in the queue, the next one returned
-        // from |queue_->Dequeue| may not be the new buffer we just reallocated.
-        // Retry up to BufferHubQueue::kMaxQueueCapacity times.
-        ret = AllocateBuffer(width, height, kLayerCount, format, usage);
-        if (ret < 0) return ret;
-    }
-
-    // With the BufferHub backed solution. Buffer slot returned from
-    // |queue_->Dequeue| is guaranteed to avaiable for producer's use.
-    // It's either in free state (if the buffer has never been used before) or
-    // in queued state (if the buffer has been dequeued and queued back to
-    // BufferHubQueue).
-    LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() &&
-                         !buffers_[slot].mBufferState.isQueued()),
-                        "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot,
-                        buffers_[slot].mBufferState.string());
-
-    buffers_[slot].mBufferState.freeQueued();
-    buffers_[slot].mBufferState.dequeue();
-    ALOGV("dequeueBuffer: slot=%zu", slot);
-
-    // TODO(jwcai) Handle fence properly. |BufferHub| has full fence support, we
-    // just need to exopose that through |BufferHubQueue| once we need fence.
-    *out_fence = Fence::NO_FENCE;
-    *out_slot = int(slot);
-    ret = NO_ERROR;
-
-    if (buffers_[slot].mIsReallocating) {
-        ret |= BUFFER_NEEDS_REALLOCATION;
-        buffers_[slot].mIsReallocating = false;
-    }
-
-    return ret;
-}
-
-status_t BufferHubProducer::detachBuffer(int slot) {
-    ALOGV("detachBuffer: slot=%d", slot);
-    std::unique_lock<std::mutex> lock(mutex_);
-
-    return DetachBufferLocked(static_cast<size_t>(slot));
-}
-
-status_t BufferHubProducer::DetachBufferLocked(size_t slot) {
-    if (connected_api_ == kNoConnectedApi) {
-        ALOGE("detachBuffer: BufferHubProducer is not connected.");
-        return NO_INIT;
-    }
-
-    if (slot >= static_cast<size_t>(max_buffer_count_)) {
-        ALOGE("detachBuffer: slot index %zu out of range [0, %d)", slot, max_buffer_count_);
-        return BAD_VALUE;
-    } else if (!buffers_[slot].mBufferState.isDequeued()) {
-        ALOGE("detachBuffer: slot %zu is not owned by the producer (state = %s)", slot,
-              buffers_[slot].mBufferState.string());
-        return BAD_VALUE;
-    } else if (!buffers_[slot].mRequestBufferCalled) {
-        ALOGE("detachBuffer: buffer in slot %zu has not been requested", slot);
-        return BAD_VALUE;
-    }
-    std::shared_ptr<ProducerBuffer> producer_buffer = queue_->GetBuffer(slot);
-    if (producer_buffer == nullptr || producer_buffer->buffer() == nullptr) {
-        ALOGE("detachBuffer: Invalid ProducerBuffer at slot %zu.", slot);
-        return BAD_VALUE;
-    }
-    sp<GraphicBuffer> graphic_buffer = producer_buffer->buffer()->buffer();
-    if (graphic_buffer == nullptr) {
-        ALOGE("detachBuffer: Invalid GraphicBuffer at slot %zu.", slot);
-        return BAD_VALUE;
-    }
-
-    // Remove the ProducerBuffer from the ProducerQueue.
-    status_t error = RemoveBuffer(slot);
-    if (error != NO_ERROR) {
-        ALOGE("detachBuffer: Failed to remove buffer, slot=%zu, error=%d.", slot, error);
-        return error;
-    }
-
-    // Here we need to convert the existing ProducerBuffer into a DetachedBufferHandle and inject
-    // the handle into the GraphicBuffer object at the requested slot.
-    auto status_or_handle = producer_buffer->Detach();
-    if (!status_or_handle.ok()) {
-        ALOGE("detachBuffer: Failed to detach from a ProducerBuffer at slot %zu, error=%d.", slot,
-              status_or_handle.error());
-        return BAD_VALUE;
-    }
-
-    // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
-    // be directly backed by BufferHub.
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) {
-    ALOGV("detachNextBuffer.");
-
-    if (out_buffer == nullptr || out_fence == nullptr) {
-        ALOGE("detachNextBuffer: Invalid parameter: out_buffer=%p, out_fence=%p", out_buffer,
-              out_fence);
-        return BAD_VALUE;
-    }
-
-    std::unique_lock<std::mutex> lock(mutex_);
-
-    if (connected_api_ == kNoConnectedApi) {
-        ALOGE("detachNextBuffer: BufferHubProducer is not connected.");
-        return NO_INIT;
-    }
-
-    // detachNextBuffer is equivalent to calling dequeueBuffer, requestBuffer, and detachBuffer in
-    // sequence, except for two things:
-    //
-    // 1) It is unnecessary to know the dimensions, format, or usage of the next buffer, i.e. the
-    // function just returns whatever ProducerBuffer is available from the ProducerQueue and no
-    // buffer allocation or re-allocation will happen.
-    // 2) It will not block, since if it cannot find an appropriate buffer to return, it will return
-    // an error instead.
-    size_t slot = 0;
-    LocalHandle fence;
-
-    // First, dequeue a ProducerBuffer from the ProducerQueue with no timeout. Report error
-    // immediately if ProducerQueue::Dequeue() fails.
-    auto status_or_buffer = queue_->Dequeue(/*timeout=*/0, &slot, &fence);
-    if (!status_or_buffer.ok()) {
-        ALOGE("detachNextBuffer: Failed to dequeue buffer, error=%d.", status_or_buffer.error());
-        return NO_MEMORY;
-    }
-
-    std::shared_ptr<ProducerBuffer> producer_buffer = status_or_buffer.take();
-    if (producer_buffer == nullptr) {
-        ALOGE("detachNextBuffer: Dequeued buffer is null.");
-        return NO_MEMORY;
-    }
-
-    // With the BufferHub backed solution, slot returned from |queue_->Dequeue| is guaranteed to
-    // be available for producer's use. It's either in free state (if the buffer has never been used
-    // before) or in queued state (if the buffer has been dequeued and queued back to
-    // BufferHubQueue).
-    if (!buffers_[slot].mBufferState.isFree() && !buffers_[slot].mBufferState.isQueued()) {
-        ALOGE("detachNextBuffer: slot %zu is not free or queued, actual state: %s.", slot,
-              buffers_[slot].mBufferState.string());
-        return BAD_VALUE;
-    }
-    if (buffers_[slot].mProducerBuffer == nullptr) {
-        ALOGE("detachNextBuffer: ProducerBuffer at slot %zu is null.", slot);
-        return BAD_VALUE;
-    }
-    if (buffers_[slot].mProducerBuffer->id() != producer_buffer->id()) {
-        ALOGE("detachNextBuffer: ProducerBuffer at slot %zu has mismatched id, actual: "
-              "%d, expected: %d.",
-              slot, buffers_[slot].mProducerBuffer->id(), producer_buffer->id());
-        return BAD_VALUE;
-    }
-
-    ALOGV("detachNextBuffer: slot=%zu", slot);
-    buffers_[slot].mBufferState.freeQueued();
-    buffers_[slot].mBufferState.dequeue();
-
-    // Second, request the buffer.
-    sp<GraphicBuffer> graphic_buffer = producer_buffer->buffer()->buffer();
-    buffers_[slot].mGraphicBuffer = producer_buffer->buffer()->buffer();
-
-    // Finally, detach the buffer and then return.
-    status_t error = DetachBufferLocked(slot);
-    if (error == NO_ERROR) {
-        *out_fence = new Fence(fence.Release());
-        *out_buffer = graphic_buffer;
-    }
-    return error;
-}
-
-status_t BufferHubProducer::attachBuffer(int* out_slot, const sp<GraphicBuffer>& buffer) {
-    // In the BufferHub design, all buffers are allocated and owned by the BufferHub. Thus only
-    // GraphicBuffers that are originated from BufferHub can be attached to a BufferHubProducer.
-    ALOGV("queueBuffer: buffer=%p", buffer.get());
-
-    if (out_slot == nullptr) {
-        ALOGE("attachBuffer: out_slot cannot be NULL.");
-        return BAD_VALUE;
-    }
-    if (buffer == nullptr) {
-        ALOGE("attachBuffer: invalid GraphicBuffer.");
-        return BAD_VALUE;
-    }
-
-    std::unique_lock<std::mutex> lock(mutex_);
-
-    if (connected_api_ == kNoConnectedApi) {
-        ALOGE("attachBuffer: BufferQueue has no connected producer");
-        return NO_INIT;
-    }
-
-    // Before attaching the buffer, caller is supposed to call
-    // IGraphicBufferProducer::setGenerationNumber to inform the
-    // BufferHubProducer the next generation number.
-    if (buffer->getGenerationNumber() != generation_number_) {
-        ALOGE("attachBuffer: Mismatched generation number, buffer: %u, queue: %u.",
-              buffer->getGenerationNumber(), generation_number_);
-        return BAD_VALUE;
-    }
-
-    // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
-    // be directly backed by BufferHub.
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input,
-                                        QueueBufferOutput* output) {
-    ALOGV("queueBuffer: slot %d", slot);
-
-    if (output == nullptr) {
-        return BAD_VALUE;
-    }
-
-    int64_t timestamp;
-    bool is_auto_timestamp;
-    android_dataspace dataspace;
-    Rect crop(Rect::EMPTY_RECT);
-    int scaling_mode;
-    uint32_t transform;
-    sp<Fence> fence;
-
-    input.deflate(&timestamp, &is_auto_timestamp, &dataspace, &crop, &scaling_mode, &transform,
-                  &fence);
-
-    // Check input scaling mode is valid.
-    switch (scaling_mode) {
-        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
-        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
-        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
-        case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
-            break;
-        default:
-            ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode);
-            return BAD_VALUE;
-    }
-
-    // Check input fence is valid.
-    if (fence == nullptr) {
-        ALOGE("queueBuffer: fence is NULL");
-        return BAD_VALUE;
-    }
-
-    std::unique_lock<std::mutex> lock(mutex_);
-
-    if (connected_api_ == kNoConnectedApi) {
-        ALOGE("queueBuffer: BufferQueue has no connected producer");
-        return NO_INIT;
-    }
-
-    if (slot < 0 || slot >= max_buffer_count_) {
-        ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
-        return BAD_VALUE;
-    } else if (!buffers_[slot].mBufferState.isDequeued()) {
-        ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)", slot,
-              buffers_[slot].mBufferState.string());
-        return BAD_VALUE;
-    } else if ((!buffers_[slot].mRequestBufferCalled || buffers_[slot].mGraphicBuffer == nullptr)) {
-        ALOGE("queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, "
-              "mGraphicBuffer=%p)",
-              slot, buffers_[slot].mRequestBufferCalled, buffers_[slot].mGraphicBuffer.get());
-        return BAD_VALUE;
-    }
-
-    // Post the producer buffer with timestamp in the metadata.
-    const auto& producer_buffer = buffers_[slot].mProducerBuffer;
-
-    // Check input crop is not out of boundary of current buffer.
-    Rect buffer_rect(producer_buffer->width(), producer_buffer->height());
-    Rect cropped_rect(Rect::EMPTY_RECT);
-    crop.intersect(buffer_rect, &cropped_rect);
-    if (cropped_rect != crop) {
-        ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot);
-        return BAD_VALUE;
-    }
-
-    LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1);
-
-    DvrNativeBufferMetadata meta_data;
-    meta_data.timestamp = timestamp;
-    meta_data.is_auto_timestamp = int32_t(is_auto_timestamp);
-    meta_data.dataspace = int32_t(dataspace);
-    meta_data.crop_left = crop.left;
-    meta_data.crop_top = crop.top;
-    meta_data.crop_right = crop.right;
-    meta_data.crop_bottom = crop.bottom;
-    meta_data.scaling_mode = int32_t(scaling_mode);
-    meta_data.transform = int32_t(transform);
-
-    producer_buffer->PostAsync(&meta_data, fence_fd);
-    buffers_[slot].mBufferState.queue();
-
-    output->width = producer_buffer->width();
-    output->height = producer_buffer->height();
-    output->transformHint = 0; // default value, we don't use it yet.
-
-    // |numPendingBuffers| counts of the number of buffers that has been enqueued
-    // by the producer but not yet acquired by the consumer. Due to the nature
-    // of BufferHubQueue design, this is hard to trace from the producer's client
-    // side, but it's safe to assume it's zero.
-    output->numPendingBuffers = 0;
-
-    // Note that we are not setting nextFrameNumber here as it seems to be only
-    // used by surface flinger. See more at b/22802885, ag/791760.
-    output->nextFrameNumber = 0;
-
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
-    ALOGV(__FUNCTION__);
-
-    std::unique_lock<std::mutex> lock(mutex_);
-
-    if (connected_api_ == kNoConnectedApi) {
-        ALOGE("cancelBuffer: BufferQueue has no connected producer");
-        return NO_INIT;
-    }
-
-    if (slot < 0 || slot >= max_buffer_count_) {
-        ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
-        return BAD_VALUE;
-    } else if (!buffers_[slot].mBufferState.isDequeued()) {
-        ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)", slot,
-              buffers_[slot].mBufferState.string());
-        return BAD_VALUE;
-    } else if (fence == nullptr) {
-        ALOGE("cancelBuffer: fence is NULL");
-        return BAD_VALUE;
-    }
-
-    auto producer_buffer = buffers_[slot].mProducerBuffer;
-    queue_->Enqueue(producer_buffer, size_t(slot), 0U);
-    buffers_[slot].mBufferState.cancel();
-    buffers_[slot].mFence = fence;
-    ALOGV("cancelBuffer: slot %d", slot);
-
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::query(int what, int* out_value) {
-    ALOGV(__FUNCTION__);
-
-    std::unique_lock<std::mutex> lock(mutex_);
-
-    if (out_value == nullptr) {
-        ALOGE("query: out_value was NULL");
-        return BAD_VALUE;
-    }
-
-    int value = 0;
-    switch (what) {
-        case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
-            // TODO(b/36187402) This should be the maximum number of buffers that this
-            // producer queue's consumer can acquire. Set to be at least one. Need to
-            // find a way to set from the consumer side.
-            value = kDefaultUndequeuedBuffers;
-            break;
-        case NATIVE_WINDOW_BUFFER_AGE:
-            value = 0;
-            break;
-        case NATIVE_WINDOW_WIDTH:
-            value = int32_t(queue_->default_width());
-            break;
-        case NATIVE_WINDOW_HEIGHT:
-            value = int32_t(queue_->default_height());
-            break;
-        case NATIVE_WINDOW_FORMAT:
-            value = int32_t(queue_->default_format());
-            break;
-        case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
-            // BufferHubQueue is always operating in async mode, thus semantically
-            // consumer can never be running behind. See BufferQueueCore.cpp core
-            // for more information about the original meaning of this flag.
-            value = 0;
-            break;
-        case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
-            // TODO(jwcai) This is currently not implement as we don't need
-            // IGraphicBufferConsumer parity.
-            value = 0;
-            break;
-        case NATIVE_WINDOW_DEFAULT_DATASPACE:
-            // TODO(jwcai) Return the default value android::BufferQueue is using as
-            // there is no way dvr::ConsumerQueue can set it.
-            value = 0; // HAL_DATASPACE_UNKNOWN
-            break;
-        case NATIVE_WINDOW_STICKY_TRANSFORM:
-            // TODO(jwcai) Return the default value android::BufferQueue is using as
-            // there is no way dvr::ConsumerQueue can set it.
-            value = 0;
-            break;
-        case NATIVE_WINDOW_CONSUMER_IS_PROTECTED:
-            // In Daydream's implementation, the consumer end (i.e. VR Compostior)
-            // knows how to handle protected buffers.
-            value = 1;
-            break;
-        default:
-            return BAD_VALUE;
-    }
-
-    ALOGV("query: key=%d, v=%d", what, value);
-    *out_value = value;
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::connect(const sp<IProducerListener>& /* listener */, int api,
-                                    bool /* producer_controlled_by_app */,
-                                    QueueBufferOutput* output) {
-    // Consumer interaction are actually handled by buffer hub, and we need
-    // to maintain consumer operations here. We only need to perform basic input
-    // parameter checks here.
-    ALOGV(__FUNCTION__);
-
-    if (output == nullptr) {
-        return BAD_VALUE;
-    }
-
-    std::unique_lock<std::mutex> lock(mutex_);
-
-    if (connected_api_ != kNoConnectedApi) {
-        return BAD_VALUE;
-    }
-
-    if (!queue_->is_connected()) {
-        ALOGE("BufferHubProducer::connect: This BufferHubProducer is not "
-              "connected to bufferhud. Has it been taken out as a parcelable?");
-        return BAD_VALUE;
-    }
-
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-        case NATIVE_WINDOW_API_CPU:
-        case NATIVE_WINDOW_API_MEDIA:
-        case NATIVE_WINDOW_API_CAMERA:
-            connected_api_ = api;
-
-            output->width = queue_->default_width();
-            output->height = queue_->default_height();
-
-            // default values, we don't use them yet.
-            output->transformHint = 0;
-            output->numPendingBuffers = 0;
-            output->nextFrameNumber = 0;
-            output->bufferReplaced = false;
-
-            break;
-        default:
-            ALOGE("BufferHubProducer::connect: unknow API %d", api);
-            return BAD_VALUE;
-    }
-
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::disconnect(int api, DisconnectMode /*mode*/) {
-    // Consumer interaction are actually handled by buffer hub, and we need
-    // to maintain consumer operations here.  We only need to perform basic input
-    // parameter checks here.
-    ALOGV(__FUNCTION__);
-
-    std::unique_lock<std::mutex> lock(mutex_);
-
-    if (kNoConnectedApi == connected_api_) {
-        return NO_INIT;
-    } else if (api != connected_api_) {
-        return BAD_VALUE;
-    }
-
-    FreeAllBuffers();
-    connected_api_ = kNoConnectedApi;
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::setSidebandStream(const sp<NativeHandle>& stream) {
-    if (stream != nullptr) {
-        // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's
-        // metadata.
-        ALOGE("SidebandStream is not currently supported.");
-        return INVALID_OPERATION;
-    }
-    return NO_ERROR;
-}
-
-void BufferHubProducer::allocateBuffers(uint32_t /* width */, uint32_t /* height */,
-                                        PixelFormat /* format */, uint64_t /* usage */) {
-    // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number
-    // of buffers permitted by the current BufferQueue configuration (aka
-    // |max_buffer_count_|).
-    ALOGE("BufferHubProducer::allocateBuffers not implemented.");
-}
-
-status_t BufferHubProducer::allowAllocation(bool /* allow */) {
-    ALOGE("BufferHubProducer::allowAllocation not implemented.");
-    return INVALID_OPERATION;
-}
-
-status_t BufferHubProducer::setGenerationNumber(uint32_t generation_number) {
-    ALOGV(__FUNCTION__);
-
-    std::unique_lock<std::mutex> lock(mutex_);
-    generation_number_ = generation_number;
-    return NO_ERROR;
-}
-
-String8 BufferHubProducer::getConsumerName() const {
-    // BufferHub based implementation could have one to many producer/consumer
-    // relationship, thus |getConsumerName| from the producer side does not
-    // make any sense.
-    ALOGE("BufferHubProducer::getConsumerName not supported.");
-    return String8("BufferHubQueue::StubConsumer");
-}
-
-status_t BufferHubProducer::setSharedBufferMode(bool shared_buffer_mode) {
-    if (shared_buffer_mode) {
-        ALOGE("BufferHubProducer::setSharedBufferMode(true) is not supported.");
-        // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow.
-        return INVALID_OPERATION;
-    }
-    // Setting to default should just work as a no-op.
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::setAutoRefresh(bool auto_refresh) {
-    if (auto_refresh) {
-        ALOGE("BufferHubProducer::setAutoRefresh(true) is not supported.");
-        return INVALID_OPERATION;
-    }
-    // Setting to default should just work as a no-op.
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::setDequeueTimeout(nsecs_t timeout) {
-    ALOGV(__FUNCTION__);
-
-    std::unique_lock<std::mutex> lock(mutex_);
-    dequeue_timeout_ms_ = static_cast<int>(timeout / (1000 * 1000));
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::getLastQueuedBuffer(sp<GraphicBuffer>* /* out_buffer */,
-                                                sp<Fence>* /* out_fence */,
-                                                float /*out_transform_matrix*/[16]) {
-    ALOGE("BufferHubProducer::getLastQueuedBuffer not implemented.");
-    return INVALID_OPERATION;
-}
-
-void BufferHubProducer::getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) {
-    ALOGE("BufferHubProducer::getFrameTimestamps not implemented.");
-}
-
-status_t BufferHubProducer::getUniqueId(uint64_t* out_id) const {
-    ALOGV(__FUNCTION__);
-
-    *out_id = unique_id_;
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::getConsumerUsage(uint64_t* out_usage) const {
-    ALOGV(__FUNCTION__);
-
-    // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS
-    *out_usage = 0;
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::TakeAsParcelable(ProducerQueueParcelable* out_parcelable) {
-    if (!out_parcelable || out_parcelable->IsValid()) return BAD_VALUE;
-
-    if (connected_api_ != kNoConnectedApi) {
-        ALOGE("BufferHubProducer::TakeAsParcelable: BufferHubProducer has "
-              "connected client. Must disconnect first.");
-        return BAD_VALUE;
-    }
-
-    if (!queue_->is_connected()) {
-        ALOGE("BufferHubProducer::TakeAsParcelable: This BufferHubProducer "
-              "is not connected to bufferhud. Has it been taken out as a "
-              "parcelable?");
-        return BAD_VALUE;
-    }
-
-    auto status = queue_->TakeAsParcelable();
-    if (!status) {
-        ALOGE("BufferHubProducer::TakeAsParcelable: Failed to take out "
-              "ProducuerQueueParcelable from the producer queue, error: %s.",
-              status.GetErrorMessage().c_str());
-        return BAD_VALUE;
-    }
-
-    *out_parcelable = status.take();
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
-                                           PixelFormat format, uint64_t usage) {
-    auto status = queue_->AllocateBuffer(width, height, layer_count, uint32_t(format), usage);
-    if (!status) {
-        ALOGE("BufferHubProducer::AllocateBuffer: Failed to allocate buffer: %s",
-              status.GetErrorMessage().c_str());
-        return NO_MEMORY;
-    }
-
-    size_t slot = status.get();
-    auto producer_buffer = queue_->GetBuffer(slot);
-
-    LOG_ALWAYS_FATAL_IF(producer_buffer == nullptr,
-                        "Failed to get the producer buffer at slot: %zu", slot);
-
-    buffers_[slot].mProducerBuffer = producer_buffer;
-
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::RemoveBuffer(size_t slot) {
-    auto status = queue_->RemoveBuffer(slot);
-    if (!status) {
-        ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer at slot: %zu, error: %s.",
-              slot, status.GetErrorMessage().c_str());
-        return INVALID_OPERATION;
-    }
-
-    // Reset in memory objects related the the buffer.
-    buffers_[slot].mProducerBuffer = nullptr;
-    buffers_[slot].mBufferState.detachProducer();
-    buffers_[slot].mFence = Fence::NO_FENCE;
-    buffers_[slot].mGraphicBuffer = nullptr;
-    buffers_[slot].mRequestBufferCalled = false;
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::FreeAllBuffers() {
-    for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
-        // Reset in memory objects related the the buffer.
-        buffers_[slot].mProducerBuffer = nullptr;
-        buffers_[slot].mBufferState.reset();
-        buffers_[slot].mFence = Fence::NO_FENCE;
-        buffers_[slot].mGraphicBuffer = nullptr;
-        buffers_[slot].mRequestBufferCalled = false;
-    }
-
-    auto status = queue_->FreeAllBuffers();
-    if (!status) {
-        ALOGE("BufferHubProducer::FreeAllBuffers: Failed to free all buffers on "
-              "the queue: %s",
-              status.GetErrorMessage().c_str());
-    }
-
-    if (queue_->capacity() != 0 || queue_->count() != 0) {
-        LOG_ALWAYS_FATAL("BufferHubProducer::FreeAllBuffers: Not all buffers are freed.");
-    }
-
-    return NO_ERROR;
-}
-
-status_t BufferHubProducer::exportToParcel(Parcel* parcel) {
-    status_t res = TakeAsParcelable(&pending_producer_parcelable_);
-    if (res != NO_ERROR) return res;
-
-    if (!pending_producer_parcelable_.IsValid()) {
-        ALOGE("BufferHubProducer::exportToParcel: Invalid parcelable object.");
-        return BAD_VALUE;
-    }
-
-    res = parcel->writeUint32(USE_BUFFER_HUB);
-    if (res != NO_ERROR) {
-        ALOGE("BufferHubProducer::exportToParcel: Cannot write magic, res=%d.", res);
-        return res;
-    }
-
-    return pending_producer_parcelable_.writeToParcel(parcel);
-}
-
-IBinder* BufferHubProducer::onAsBinder() {
-    ALOGE("BufferHubProducer::onAsBinder: BufferHubProducer should never be used as an Binder "
-          "object.");
-    return nullptr;
-}
-
-} // namespace android
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index c1d92a2..66cad03 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -18,11 +18,6 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 //#define LOG_NDEBUG 0
 
-#ifndef NO_BUFFERHUB
-#include <gui/BufferHubConsumer.h>
-#include <gui/BufferHubProducer.h>
-#endif
-
 #include <gui/BufferQueue.h>
 #include <gui/BufferQueueConsumer.h>
 #include <gui/BufferQueueCore.h>
@@ -127,32 +122,4 @@
     *outConsumer = consumer;
 }
 
-#ifndef NO_BUFFERHUB
-void BufferQueue::createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer,
-                                       sp<IGraphicBufferConsumer>* outConsumer) {
-    LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BufferQueue: outProducer must not be NULL");
-    LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BufferQueue: outConsumer must not be NULL");
-
-    sp<IGraphicBufferProducer> producer;
-    sp<IGraphicBufferConsumer> consumer;
-
-    dvr::ProducerQueueConfigBuilder configBuilder;
-    std::shared_ptr<dvr::ProducerQueue> producerQueue =
-            dvr::ProducerQueue::Create(configBuilder.Build(), dvr::UsagePolicy{});
-    LOG_ALWAYS_FATAL_IF(producerQueue == nullptr, "BufferQueue: failed to create ProducerQueue.");
-
-    std::shared_ptr<dvr::ConsumerQueue> consumerQueue = producerQueue->CreateConsumerQueue();
-    LOG_ALWAYS_FATAL_IF(consumerQueue == nullptr, "BufferQueue: failed to create ConsumerQueue.");
-
-    producer = BufferHubProducer::Create(producerQueue);
-    consumer = BufferHubConsumer::Create(consumerQueue);
-
-    LOG_ALWAYS_FATAL_IF(producer == nullptr, "BufferQueue: failed to create BufferQueueProducer");
-    LOG_ALWAYS_FATAL_IF(consumer == nullptr, "BufferQueue: failed to create BufferQueueConsumer");
-
-    *outProducer = producer;
-    *outConsumer = consumer;
-}
-#endif
-
 }; // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 797069c..918ff2d 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -27,10 +27,6 @@
 #include <binder/Parcel.h>
 #include <binder/IInterface.h>
 
-#ifndef NO_BUFFERHUB
-#include <gui/BufferHubProducer.h>
-#endif
-
 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
 #include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
 #include <gui/BufferQueueDefs.h>
@@ -1012,17 +1008,7 @@
         }
         case USE_BUFFER_HUB: {
             ALOGE("createFromParcel: BufferHub not implemented.");
-#ifndef NO_BUFFERHUB
-            dvr::ProducerQueueParcelable producerParcelable;
-            res = producerParcelable.readFromParcel(parcel);
-            if (res != NO_ERROR) {
-                ALOGE("createFromParcel: Failed to read from parcel, error=%d", res);
-                return nullptr;
-            }
-            return BufferHubProducer::Create(std::move(producerParcelable));
-#else
             return nullptr;
-#endif
         }
         default: {
             ALOGE("createFromParcel: Unexpected mgaic: 0x%x.", outMagic);
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 6b544b2..3b13708 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1107,9 +1107,12 @@
     ATRACE_CALL();
     auto& mapper = GraphicBufferMapper::get();
     mapper.setDataspace(buffer->handle, static_cast<ui::Dataspace>(queueBufferInput.dataSpace));
-    mapper.setSmpte2086(buffer->handle, queueBufferInput.getHdrMetadata().getSmpte2086());
-    mapper.setCta861_3(buffer->handle, queueBufferInput.getHdrMetadata().getCta8613());
-    mapper.setSmpte2094_40(buffer->handle, queueBufferInput.getHdrMetadata().getHdr10Plus());
+    if (mHdrMetadataIsSet & HdrMetadata::SMPTE2086)
+        mapper.setSmpte2086(buffer->handle, queueBufferInput.getHdrMetadata().getSmpte2086());
+    if (mHdrMetadataIsSet & HdrMetadata::CTA861_3)
+        mapper.setCta861_3(buffer->handle, queueBufferInput.getHdrMetadata().getCta8613());
+    if (mHdrMetadataIsSet & HdrMetadata::HDR10PLUS)
+        mapper.setSmpte2094_40(buffer->handle, queueBufferInput.getHdrMetadata().getHdr10Plus());
 }
 
 void Surface::onBufferQueuedLocked(int slot, sp<Fence> fence,
@@ -2250,6 +2253,7 @@
 int Surface::setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata) {
     ALOGV("Surface::setBuffersSmpte2086Metadata");
     Mutex::Autolock lock(mMutex);
+    mHdrMetadataIsSet |= HdrMetadata::SMPTE2086;
     if (metadata) {
         mHdrMetadata.smpte2086 = *metadata;
         mHdrMetadata.validTypes |= HdrMetadata::SMPTE2086;
@@ -2262,6 +2266,7 @@
 int Surface::setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata) {
     ALOGV("Surface::setBuffersCta8613Metadata");
     Mutex::Autolock lock(mMutex);
+    mHdrMetadataIsSet |= HdrMetadata::CTA861_3;
     if (metadata) {
         mHdrMetadata.cta8613 = *metadata;
         mHdrMetadata.validTypes |= HdrMetadata::CTA861_3;
@@ -2274,6 +2279,7 @@
 int Surface::setBuffersHdr10PlusMetadata(const size_t size, const uint8_t* metadata) {
     ALOGV("Surface::setBuffersBlobMetadata");
     Mutex::Autolock lock(mMutex);
+    mHdrMetadataIsSet |= HdrMetadata::HDR10PLUS;
     if (size > 0) {
         mHdrMetadata.hdr10plus.assign(metadata, metadata + size);
         mHdrMetadata.validTypes |= HdrMetadata::HDR10PLUS;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 47d801a..0f5192d 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -352,7 +352,8 @@
                                       transactionStats.latchTime, surfaceStats.acquireTimeOrFence,
                                       transactionStats.presentFence,
                                       surfaceStats.previousReleaseFence, surfaceStats.transformHint,
-                                      surfaceStats.eventStats);
+                                      surfaceStats.eventStats,
+                                      surfaceStats.currentMaxAcquiredBufferCount);
             }
 
             callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
@@ -377,7 +378,8 @@
                                       transactionStats.latchTime, surfaceStats.acquireTimeOrFence,
                                       transactionStats.presentFence,
                                       surfaceStats.previousReleaseFence, surfaceStats.transformHint,
-                                      surfaceStats.eventStats);
+                                      surfaceStats.eventStats,
+                                      surfaceStats.currentMaxAcquiredBufferCount);
                 if (callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]) {
                     callbacksMap[callbackId]
                             .surfaceControls[surfaceStats.surfaceControl]
@@ -897,6 +899,10 @@
     mApplyToken = nullptr;
 }
 
+uint64_t SurfaceComposerClient::Transaction::getId() {
+    return mId;
+}
+
 void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
 
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 9328a54..f5898d2 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -95,9 +95,12 @@
                                      const std::vector<SurfaceControlStats>& stats);
     void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
                                std::optional<uint32_t> currentMaxAcquiredBufferCount);
+    void releaseBufferCallbackLocked(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
+                               std::optional<uint32_t> currentMaxAcquiredBufferCount);
     void syncNextTransaction(std::function<void(SurfaceComposerClient::Transaction*)> callback,
                              bool acquireSingleBuffer = true);
     void stopContinuousSyncTransaction();
+
     void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
     void applyPendingTransactions(uint64_t frameNumber);
     SurfaceComposerClient::Transaction* gatherPendingTransactions(uint64_t frameNumber);
@@ -177,6 +180,12 @@
     struct ReleasedBuffer {
         ReleaseCallbackId callbackId;
         sp<Fence> releaseFence;
+        bool operator==(const ReleasedBuffer& rhs) const {
+            // Only compare Id so if we somehow got two callbacks
+            // with different fences we don't decrement mNumAcquired
+            // too far.
+            return rhs.callbackId == callbackId;
+        }
     };
     std::deque<ReleasedBuffer> mPendingRelease GUARDED_BY(mMutex);
 
@@ -251,7 +260,6 @@
     std::queue<sp<SurfaceControl>> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex);
 
     uint32_t mCurrentMaxAcquiredBufferCount;
-    bool mWaitForTransactionCallback GUARDED_BY(mMutex) = false;
 
     // Flag to determine if syncTransaction should only acquire a single buffer and then clear or
     // continue to acquire buffers until explicitly cleared
@@ -279,6 +287,8 @@
     uint64_t mLastAppliedFrameNumber = 0;
 
     std::function<void(bool)> mTransactionHangCallback;
+
+    std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex);
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/BufferHubConsumer.h b/libs/gui/include/gui/BufferHubConsumer.h
deleted file mode 100644
index d380770..0000000
--- a/libs/gui/include/gui/BufferHubConsumer.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 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 ANDROID_GUI_BUFFERHUBCONSUMER_H_
-#define ANDROID_GUI_BUFFERHUBCONSUMER_H_
-
-#include <gui/IGraphicBufferConsumer.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/buffer_hub_queue_parcelable.h>
-
-namespace android {
-
-class BufferHubConsumer : public IGraphicBufferConsumer {
-public:
-    // Creates a BufferHubConsumer instance by importing an existing producer queue.
-    static sp<BufferHubConsumer> Create(const std::shared_ptr<dvr::ConsumerQueue>& queue);
-
-    // Creates a BufferHubConsumer instance by importing an existing producer
-    // parcelable. Note that this call takes the ownership of the parcelable
-    // object and is guaranteed to succeed if parcelable object is valid.
-    static sp<BufferHubConsumer> Create(dvr::ConsumerQueueParcelable parcelable);
-
-    // See |IGraphicBufferConsumer::acquireBuffer|
-    status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
-                           uint64_t maxFrameNumber = 0) override;
-
-    // See |IGraphicBufferConsumer::detachBuffer|
-    status_t detachBuffer(int slot) override;
-
-    // See |IGraphicBufferConsumer::attachBuffer|
-    status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) override;
-
-    // See |IGraphicBufferConsumer::releaseBuffer|
-    status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence,
-                           const sp<Fence>& releaseFence) override;
-
-    // See |IGraphicBufferConsumer::consumerConnect|
-    status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) override;
-
-    // See |IGraphicBufferConsumer::consumerDisconnect|
-    status_t consumerDisconnect() override;
-
-    // See |IGraphicBufferConsumer::getReleasedBuffers|
-    status_t getReleasedBuffers(uint64_t* slotMask) override;
-
-    // See |IGraphicBufferConsumer::setDefaultBufferSize|
-    status_t setDefaultBufferSize(uint32_t w, uint32_t h) override;
-
-    // See |IGraphicBufferConsumer::setMaxBufferCount|
-    status_t setMaxBufferCount(int bufferCount) override;
-
-    // See |IGraphicBufferConsumer::setMaxAcquiredBufferCount|
-    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) override;
-
-    // See |IGraphicBufferConsumer::setConsumerName|
-    status_t setConsumerName(const String8& name) override;
-
-    // See |IGraphicBufferConsumer::setDefaultBufferFormat|
-    status_t setDefaultBufferFormat(PixelFormat defaultFormat) override;
-
-    // See |IGraphicBufferConsumer::setDefaultBufferDataSpace|
-    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) override;
-
-    // See |IGraphicBufferConsumer::setConsumerUsageBits|
-    status_t setConsumerUsageBits(uint64_t usage) override;
-
-    // See |IGraphicBufferConsumer::setConsumerIsProtected|
-    status_t setConsumerIsProtected(bool isProtected) override;
-
-    // See |IGraphicBufferConsumer::setTransformHint|
-    status_t setTransformHint(uint32_t hint) override;
-
-    // See |IGraphicBufferConsumer::getSidebandStream|
-    status_t getSidebandStream(sp<NativeHandle>* outStream) const override;
-
-    // See |IGraphicBufferConsumer::getOccupancyHistory|
-    status_t getOccupancyHistory(bool forceFlush,
-                                 std::vector<OccupancyTracker::Segment>* outHistory) override;
-
-    // See |IGraphicBufferConsumer::discardFreeBuffers|
-    status_t discardFreeBuffers() override;
-
-    // See |IGraphicBufferConsumer::dumpState|
-    status_t dumpState(const String8& prefix, String8* outResult) const override;
-
-    // BufferHubConsumer provides its own logic to cast to a binder object.
-    IBinder* onAsBinder() override;
-
-private:
-    // Private constructor to force use of |Create|.
-    BufferHubConsumer() = default;
-
-    // Concrete implementation backed by BufferHubBuffer.
-    std::shared_ptr<dvr::ConsumerQueue> mQueue;
-};
-
-} // namespace android
-
-#endif // ANDROID_GUI_BUFFERHUBCONSUMER_H_
diff --git a/libs/gui/include/gui/BufferHubProducer.h b/libs/gui/include/gui/BufferHubProducer.h
deleted file mode 100644
index 0e925ce..0000000
--- a/libs/gui/include/gui/BufferHubProducer.h
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright 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 ANDROID_GUI_BUFFERHUBPRODUCER_H_
-#define ANDROID_GUI_BUFFERHUBPRODUCER_H_
-
-#include <gui/BufferSlot.h>
-#include <gui/IGraphicBufferProducer.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/buffer_hub_queue_parcelable.h>
-
-namespace android {
-
-class BufferHubProducer : public IGraphicBufferProducer {
-public:
-    static constexpr int kNoConnectedApi = -1;
-
-    // TODO(b/36187402) The actual implementation of BufferHubQueue's consumer
-    // side logic doesn't limit the number of buffer it can acquire
-    // simultaneously. We need a way for consumer logic to configure and enforce
-    // that.
-    static constexpr int kDefaultUndequeuedBuffers = 1;
-
-    // Creates a BufferHubProducer instance by importing an existing prodcuer
-    // queue.
-    static sp<BufferHubProducer> Create(const std::shared_ptr<dvr::ProducerQueue>& producer);
-
-    // Creates a BufferHubProducer instance by importing an existing prodcuer
-    // parcelable. Note that this call takes the ownership of the parcelable
-    // object and is guaranteed to succeed if parcelable object is valid.
-    static sp<BufferHubProducer> Create(dvr::ProducerQueueParcelable parcelable);
-
-    // See |IGraphicBufferProducer::requestBuffer|
-    status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
-
-    // For the BufferHub based implementation. All buffers in the queue are
-    // allowed to be dequeued from the consumer side. It call always returns
-    // 0 for |NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS| query. Thus setting
-    // |max_dequeued_buffers| here can be considered the same as setting queue
-    // capacity.
-    //
-    // See |IGraphicBufferProducer::setMaxDequeuedBufferCount| for more info
-    status_t setMaxDequeuedBufferCount(int max_dequeued_buffers) override;
-
-    // See |IGraphicBufferProducer::setAsyncMode|
-    status_t setAsyncMode(bool async) override;
-
-    // See |IGraphicBufferProducer::dequeueBuffer|
-    status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height,
-                           PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
-                           FrameEventHistoryDelta* outTimestamps) override;
-
-    // See |IGraphicBufferProducer::detachBuffer|
-    status_t detachBuffer(int slot) override;
-
-    // See |IGraphicBufferProducer::detachNextBuffer|
-    status_t detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) override;
-
-    // See |IGraphicBufferProducer::attachBuffer|
-    status_t attachBuffer(int* out_slot, const sp<GraphicBuffer>& buffer) override;
-
-    // See |IGraphicBufferProducer::queueBuffer|
-    status_t queueBuffer(int slot, const QueueBufferInput& input,
-                         QueueBufferOutput* output) override;
-
-    // See |IGraphicBufferProducer::cancelBuffer|
-    status_t cancelBuffer(int slot, const sp<Fence>& fence) override;
-
-    // See |IGraphicBufferProducer::query|
-    status_t query(int what, int* out_value) override;
-
-    // See |IGraphicBufferProducer::connect|
-    status_t connect(const sp<IProducerListener>& listener, int api,
-                     bool producer_controlled_by_app, QueueBufferOutput* output) override;
-
-    // See |IGraphicBufferProducer::disconnect|
-    status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api) override;
-
-    // See |IGraphicBufferProducer::setSidebandStream|
-    status_t setSidebandStream(const sp<NativeHandle>& stream) override;
-
-    // See |IGraphicBufferProducer::allocateBuffers|
-    void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
-                         uint64_t usage) override;
-
-    // See |IGraphicBufferProducer::allowAllocation|
-    status_t allowAllocation(bool allow) override;
-
-    // See |IGraphicBufferProducer::setGenerationNumber|
-    status_t setGenerationNumber(uint32_t generation_number) override;
-
-    // See |IGraphicBufferProducer::getConsumerName|
-    String8 getConsumerName() const override;
-
-    // See |IGraphicBufferProducer::setSharedBufferMode|
-    status_t setSharedBufferMode(bool shared_buffer_mode) override;
-
-    // See |IGraphicBufferProducer::setAutoRefresh|
-    status_t setAutoRefresh(bool auto_refresh) override;
-
-    // See |IGraphicBufferProducer::setDequeueTimeout|
-    status_t setDequeueTimeout(nsecs_t timeout) override;
-
-    // See |IGraphicBufferProducer::getLastQueuedBuffer|
-    status_t getLastQueuedBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence,
-                                 float out_transform_matrix[16]) override;
-
-    // See |IGraphicBufferProducer::getFrameTimestamps|
-    void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) override;
-
-    // See |IGraphicBufferProducer::getUniqueId|
-    status_t getUniqueId(uint64_t* out_id) const override;
-
-    // See |IGraphicBufferProducer::getConsumerUsage|
-    status_t getConsumerUsage(uint64_t* out_usage) const override;
-
-    // Takes out the current producer as a binder parcelable object. Note that the
-    // producer must be disconnected to be exportable. After successful export,
-    // the producer queue can no longer be connected again. Returns NO_ERROR when
-    // takeout is successful and out_parcelable will hold the new parcelable
-    // object. Also note that out_parcelable cannot be NULL and must points to an
-    // invalid parcelable.
-    status_t TakeAsParcelable(dvr::ProducerQueueParcelable* out_parcelable);
-
-    IBinder* onAsBinder() override;
-
-protected:
-    // See |IGraphicBufferProducer::exportToParcel|
-    status_t exportToParcel(Parcel* parcel) override;
-
-private:
-    using LocalHandle = pdx::LocalHandle;
-
-    // Private constructor to force use of |Create|.
-    BufferHubProducer() {}
-
-    static uint64_t genUniqueId() {
-        static std::atomic<uint32_t> counter{0};
-        static uint64_t id = static_cast<uint64_t>(getpid()) << 32;
-        return id | counter++;
-    }
-
-    // Allocate new buffer through BufferHub and add it into |queue_| for
-    // bookkeeping.
-    status_t AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
-                            PixelFormat format, uint64_t usage);
-
-    // Remove a buffer via BufferHubRPC.
-    status_t RemoveBuffer(size_t slot);
-
-    // Free all buffers which are owned by the prodcuer. Note that if graphic
-    // buffers are acquired by the consumer, we can't .
-    status_t FreeAllBuffers();
-
-    // Helper function that implements the detachBuffer() call, but assuming |mutex_| has been
-    // locked already.
-    status_t DetachBufferLocked(size_t slot);
-
-    // Concreate implementation backed by BufferHubBuffer.
-    std::shared_ptr<dvr::ProducerQueue> queue_;
-
-    // Mutex for thread safety.
-    std::mutex mutex_;
-
-    // Connect client API, should be one of the NATIVE_WINDOW_API_* flags.
-    int connected_api_{kNoConnectedApi};
-
-    // |max_buffer_count_| sets the capacity of the underlying buffer queue.
-    int32_t max_buffer_count_{dvr::BufferHubQueue::kMaxQueueCapacity};
-
-    // |max_dequeued_buffer_count_| set the maximum number of buffers that can
-    // be dequeued at the same momment.
-    int32_t max_dequeued_buffer_count_{1};
-
-    // Sets how long dequeueBuffer or attachBuffer will block if a buffer or
-    // slot is not yet available. The timeout is stored in milliseconds.
-    int dequeue_timeout_ms_{dvr::BufferHubQueue::kNoTimeOut};
-
-    // |generation_number_| stores the current generation number of the attached
-    // producer. Any attempt to attach a buffer with a different generation
-    // number will fail.
-    // TOOD(b/38137191) Currently not used as we don't support
-    // IGraphicBufferProducer::detachBuffer.
-    uint32_t generation_number_{0};
-
-    // |buffers_| stores the buffers that have been dequeued from
-    // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets
-    // filled in with the result of |Dequeue|.
-    // TODO(jwcai) The buffer allocated to a slot will also be replaced if the
-    // requested buffer usage or geometry differs from that of the buffer
-    // allocated to a slot.
-    struct BufferHubSlot : public BufferSlot {
-        BufferHubSlot() : mProducerBuffer(nullptr), mIsReallocating(false) {}
-        // BufferSlot comes from android framework, using m prefix to comply with
-        // the name convention with the reset of data fields from BufferSlot.
-        std::shared_ptr<dvr::ProducerBuffer> mProducerBuffer;
-        bool mIsReallocating;
-    };
-    BufferHubSlot buffers_[dvr::BufferHubQueue::kMaxQueueCapacity];
-
-    // A uniqueId used by IGraphicBufferProducer interface.
-    const uint64_t unique_id_{genUniqueId()};
-
-    // A pending parcelable object which keeps the bufferhub channel alive.
-    dvr::ProducerQueueParcelable pending_producer_parcelable_;
-};
-
-} // namespace android
-
-#endif // ANDROID_GUI_BUFFERHUBPRODUCER_H_
diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
index 91f80d2..690587f 100644
--- a/libs/gui/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -82,12 +82,6 @@
             sp<IGraphicBufferConsumer>* outConsumer,
             bool consumerIsSurfaceFlinger = false);
 
-#ifndef NO_BUFFERHUB
-    // Creates an IGraphicBufferProducer and IGraphicBufferConsumer pair backed by BufferHub.
-    static void createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer,
-                                     sp<IGraphicBufferConsumer>* outConsumer);
-#endif
-
     BufferQueue() = delete; // Create through createBufferQueue
 };
 
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index ab9ebaa..77615fe 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -111,6 +111,24 @@
         return surface != nullptr && surface->getIGraphicBufferProducer() != nullptr;
     }
 
+    static sp<IGraphicBufferProducer> getIGraphicBufferProducer(ANativeWindow* window) {
+        int val;
+        if (window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &val) >= 0 &&
+            val == NATIVE_WINDOW_SURFACE) {
+            return ((Surface*) window)->mGraphicBufferProducer;
+        }
+        return nullptr;
+    }
+
+    static sp<IBinder> getSurfaceControlHandle(ANativeWindow* window) {
+        int val;
+        if (window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &val) >= 0 &&
+            val == NATIVE_WINDOW_SURFACE) {
+            return ((Surface*) window)->mSurfaceControlHandle;
+        }
+        return nullptr;
+    }
+
     /* Attaches a sideband buffer stream to the Surface's IGraphicBufferProducer.
      *
      * A sideband stream is a device-specific mechanism for passing buffers
@@ -462,6 +480,11 @@
     // queue operation.  There is no HDR metadata by default.
     HdrMetadata mHdrMetadata;
 
+    // mHdrMetadataIsSet is a bitfield to track which HDR metadata has been set.
+    // Prevent Surface from resetting HDR metadata that was set on a bufer when
+    // HDR metadata is not set on this Surface.
+    uint32_t mHdrMetadataIsSet{0};
+
     // mCrop is the crop rectangle that will be used for the next buffer
     // that gets queued. It is set by calling setCrop.
     Rect mCrop;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index efbdb36..9033e17 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -65,14 +65,16 @@
     SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime,
                         std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence,
                         const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
-                        uint32_t hint, FrameEventHistoryStats eventStats)
+                        uint32_t hint, FrameEventHistoryStats eventStats,
+                        uint32_t currentMaxAcquiredBufferCount)
           : surfaceControl(sc),
             latchTime(latchTime),
             acquireTimeOrFence(std::move(acquireTimeOrFence)),
             presentFence(presentFence),
             previousReleaseFence(prevReleaseFence),
             transformHint(hint),
-            frameEventStats(eventStats) {}
+            frameEventStats(eventStats),
+            currentMaxAcquiredBufferCount(currentMaxAcquiredBufferCount) {}
 
     sp<SurfaceControl> surfaceControl;
     nsecs_t latchTime = -1;
@@ -81,6 +83,7 @@
     sp<Fence> previousReleaseFence;
     uint32_t transformHint = 0;
     FrameEventHistoryStats frameEventStats;
+    uint32_t currentMaxAcquiredBufferCount = 0;
 };
 
 using TransactionCompletedCallbackTakesContext =
@@ -461,6 +464,10 @@
         // Clears the contents of the transaction without applying it.
         void clear();
 
+        // Returns the current id of the transaction.
+        // The id is updated every time the transaction is applied.
+        uint64_t getId();
+
         status_t apply(bool synchronous = false, bool oneWay = false);
         // Merge another transaction in to this one, clearing other
         // as if it had been applied.
diff --git a/libs/gui/include/gui/test/CallbackUtils.h b/libs/gui/include/gui/test/CallbackUtils.h
index 62d1496..08785b4 100644
--- a/libs/gui/include/gui/test/CallbackUtils.h
+++ b/libs/gui/include/gui/test/CallbackUtils.h
@@ -135,7 +135,8 @@
         void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
                                        nsecs_t latchTime) const {
             const auto& [surfaceControl, latch, acquireTimeOrFence, presentFence,
-                         previousReleaseFence, transformHint, frameEvents] = surfaceControlStats;
+                         previousReleaseFence, transformHint, frameEvents, ignore] =
+                surfaceControlStats;
 
             ASSERT_TRUE(std::holds_alternative<nsecs_t>(acquireTimeOrFence));
             ASSERT_EQ(std::get<nsecs_t>(acquireTimeOrFence) > 0,
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index fc68ad2..fa54c7d 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -92,39 +92,6 @@
     header_libs: ["libsurfaceflinger_headers"],
 }
 
-// Build a separate binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
-// This test has a main method, and requires a separate binary to be built.
-// To add move tests like this, just add additional cc_test statements,
-// as opposed to adding more source files to this one.
-cc_test {
-    name: "SurfaceParcelable_test",
-    test_suites: ["device-tests"],
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-
-    srcs: [
-        "SurfaceParcelable_test.cpp",
-    ],
-
-    shared_libs: [
-        "liblog",
-        "libbinder",
-        "libcutils",
-        "libgui",
-        "libui",
-        "libutils",
-        "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui.
-        "libpdx_default_transport",
-    ],
-
-    header_libs: [
-        "libdvr_headers",
-    ],
-}
-
 cc_test {
     name: "SamplingDemo",
 
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index cb7e94c..b993289 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -161,6 +161,10 @@
         ASSERT_EQ(numFramesSubmitted, mBlastBufferQueueAdapter->mSubmitted.size());
     }
 
+    void mergeWithNextTransaction(Transaction* merge, uint64_t frameNumber) {
+        mBlastBufferQueueAdapter->mergeWithNextTransaction(merge, frameNumber);
+    }
+
 private:
     sp<TestBLASTBufferQueue> mBlastBufferQueueAdapter;
 };
@@ -1111,6 +1115,39 @@
     ASSERT_TRUE(receivedCallback);
 }
 
+TEST_F(BLASTBufferQueueTest, SyncNextTransactionDropBuffer) {
+    uint8_t r = 255;
+    uint8_t g = 0;
+    uint8_t b = 0;
+
+    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+    sp<IGraphicBufferProducer> igbProducer;
+    setUpProducer(adapter, igbProducer);
+
+    Transaction sync;
+    adapter.setSyncTransaction(sync);
+    queueBuffer(igbProducer, 0, 255, 0, 0);
+
+    // Merge a transaction that has a complete callback into the next frame so we can get notified
+    // when to take a screenshot
+    CallbackHelper transactionCallback;
+    Transaction t;
+    t.addTransactionCompletedCallback(transactionCallback.function,
+                                      transactionCallback.getContext());
+    adapter.mergeWithNextTransaction(&t, 2);
+    queueBuffer(igbProducer, r, g, b, 0);
+
+    // Drop the buffer, but ensure the next one continues to get processed.
+    sync.setBuffer(mSurfaceControl, nullptr);
+
+    CallbackData callbackData;
+    transactionCallback.getCallbackData(&callbackData);
+    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+    ASSERT_NO_FATAL_FAILURE(
+            checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
 // This test will currently fail because the old surfacecontrol will steal the last presented buffer
 // until the old surface control is destroyed. This is not necessarily a bug but to document a
 // limitation with the update API and to test any changes to make the api more robust. The current
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index c6cdeb7..2637f59 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -1184,18 +1184,23 @@
     std::vector<sp<IGraphicBufferProducer>> mProducers;
 };
 
-TEST_F(MultiDisplayTests, drop_input_if_layer_on_invalid_display) {
+TEST_F(MultiDisplayTests, drop_touch_if_layer_on_invalid_display) {
     ui::LayerStack layerStack = ui::LayerStack::fromValue(42);
     // Do not create a display associated with the LayerStack.
     std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
     surface->doTransaction([&](auto &t, auto &sc) { t.setLayerStack(sc, layerStack); });
     surface->showAt(100, 100);
 
+    // Touches should be dropped if the layer is on an invalid display.
     injectTapOnDisplay(101, 101, layerStack.id);
-    surface->requestFocus(layerStack.id);
-    injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
-
     EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+    // However, we still let the window be focused and receive keys.
+    surface->requestFocus(layerStack.id);
+    surface->assertFocusChange(true);
+
+    injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
+    surface->expectKey(AKEYCODE_V);
 }
 
 TEST_F(MultiDisplayTests, virtual_display_receives_input) {
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 2af2fe1..3427731 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -42,10 +42,6 @@
 #define TEST_CONTROLLED_BY_APP false
 #define TEST_PRODUCER_USAGE_BITS (0)
 
-#ifndef USE_BUFFER_HUB_AS_BUFFER_QUEUE
-#define USE_BUFFER_HUB_AS_BUFFER_QUEUE 0
-#endif
-
 namespace android {
 
 namespace {
@@ -77,7 +73,6 @@
     // Enums to control which IGraphicBufferProducer backend to test.
     enum IGraphicBufferProducerTestCode {
         USE_BUFFER_QUEUE_PRODUCER = 0,
-        USE_BUFFER_HUB_PRODUCER,
     };
 }; // namespace anonymous
 
@@ -99,10 +94,6 @@
                 BufferQueue::createBufferQueue(&mProducer, &mConsumer);
                 break;
             }
-            case USE_BUFFER_HUB_PRODUCER: {
-                BufferQueue::createBufferHubQueue(&mProducer, &mConsumer);
-                break;
-            }
             default: {
                 // Should never reach here.
                 LOG_ALWAYS_FATAL("Invalid test params: %u", GetParam());
@@ -880,11 +871,6 @@
 }
 
 TEST_P(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) {
-    if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
-        // TODO(b/36724099): Add support for BufferHubProducer::setAsyncMode(true)
-        return;
-    }
-
     ASSERT_OK(mConsumer->setMaxAcquiredBufferCount(1)) << "maxAcquire: " << 1;
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
     ASSERT_OK(mProducer->setAsyncMode(true)) << "async mode: " << true;
@@ -1117,14 +1103,7 @@
     }
 }
 
-#if USE_BUFFER_HUB_AS_BUFFER_QUEUE
-INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest,
-                        ::testing::Values(USE_BUFFER_QUEUE_PRODUCER, USE_BUFFER_HUB_PRODUCER));
-#else
-// TODO(b/70046255): Remove the #ifdef here and always tests both backends once BufferHubQueue can
-// pass all existing libgui tests.
 INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest,
                         ::testing::Values(USE_BUFFER_QUEUE_PRODUCER));
-#endif
 
 } // namespace android
diff --git a/libs/gui/tests/SurfaceParcelable_test.cpp b/libs/gui/tests/SurfaceParcelable_test.cpp
deleted file mode 100644
index 686dc82..0000000
--- a/libs/gui/tests/SurfaceParcelable_test.cpp
+++ /dev/null
@@ -1,168 +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.
- */
-
-#define LOG_TAG "SurfaceParcelable_test"
-
-#include <gtest/gtest.h>
-
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <gui/BufferHubProducer.h>
-#include <gui/BufferQueue.h>
-#include <gui/view/Surface.h>
-#include <utils/Log.h>
-
-namespace android {
-
-static const String16 kTestServiceName = String16("SurfaceParcelableTestService");
-static const String16 kSurfaceName = String16("TEST_SURFACE");
-static const uint32_t kBufferWidth = 100;
-static const uint32_t kBufferHeight = 1;
-static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-
-enum SurfaceParcelableTestServiceCode {
-    CREATE_BUFFER_QUEUE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
-    CREATE_BUFFER_HUB_SURFACE,
-};
-
-class SurfaceParcelableTestService : public BBinder {
-public:
-    SurfaceParcelableTestService() {
-        // BufferQueue
-        BufferQueue::createBufferQueue(&mBufferQueueProducer, &mBufferQueueConsumer);
-
-        // BufferHub
-        dvr::ProducerQueueConfigBuilder configBuilder;
-        mProducerQueue = dvr::ProducerQueue::Create(configBuilder.SetDefaultWidth(kBufferWidth)
-                                                            .SetDefaultHeight(kBufferHeight)
-                                                            .SetDefaultFormat(kBufferFormat)
-                                                            .Build(),
-                                                    dvr::UsagePolicy{});
-        mBufferHubProducer = BufferHubProducer::Create(mProducerQueue);
-    }
-
-    ~SurfaceParcelableTestService() = default;
-
-    virtual status_t onTransact(uint32_t code, const Parcel& /*data*/, Parcel* reply,
-                                uint32_t /*flags*/ = 0) {
-        switch (code) {
-            case CREATE_BUFFER_QUEUE_SURFACE: {
-                view::Surface surfaceShim;
-                surfaceShim.name = kSurfaceName;
-                surfaceShim.graphicBufferProducer = mBufferQueueProducer;
-                return surfaceShim.writeToParcel(reply);
-            }
-            case CREATE_BUFFER_HUB_SURFACE: {
-                view::Surface surfaceShim;
-                surfaceShim.name = kSurfaceName;
-                surfaceShim.graphicBufferProducer = mBufferHubProducer;
-                return surfaceShim.writeToParcel(reply);
-            }
-            default:
-                return UNKNOWN_TRANSACTION;
-        };
-    }
-
-protected:
-    sp<IGraphicBufferProducer> mBufferQueueProducer;
-    sp<IGraphicBufferConsumer> mBufferQueueConsumer;
-
-    std::shared_ptr<dvr::ProducerQueue> mProducerQueue;
-    sp<IGraphicBufferProducer> mBufferHubProducer;
-};
-
-static int runBinderServer() {
-    ProcessState::self()->startThreadPool();
-
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<SurfaceParcelableTestService> service = new SurfaceParcelableTestService;
-    sm->addService(kTestServiceName, service, false);
-
-    ALOGI("Binder server running...");
-
-    while (true) {
-        int stat, retval;
-        retval = wait(&stat);
-        if (retval == -1 && errno == ECHILD) {
-            break;
-        }
-    }
-
-    ALOGI("Binder server exiting...");
-    return 0;
-}
-
-class SurfaceParcelableTest : public ::testing::TestWithParam<uint32_t> {
-protected:
-    virtual void SetUp() {
-        mService = defaultServiceManager()->getService(kTestServiceName);
-        if (mService == nullptr) {
-            ALOGE("Failed to connect to the test service.");
-            return;
-        }
-
-        ALOGI("Binder service is ready for client.");
-    }
-
-    status_t GetSurface(view::Surface* surfaceShim) {
-        ALOGI("...Test: %d", GetParam());
-
-        uint32_t opCode = GetParam();
-        Parcel data;
-        Parcel reply;
-        status_t error = mService->transact(opCode, data, &reply);
-        if (error != NO_ERROR) {
-            ALOGE("Failed to get surface over binder, error=%d.", error);
-            return error;
-        }
-
-        error = surfaceShim->readFromParcel(&reply);
-        if (error != NO_ERROR) {
-            ALOGE("Failed to get surface from parcel, error=%d.", error);
-            return error;
-        }
-
-        return NO_ERROR;
-    }
-
-private:
-    sp<IBinder> mService;
-};
-
-TEST_P(SurfaceParcelableTest, SendOverBinder) {
-    view::Surface surfaceShim;
-    EXPECT_EQ(GetSurface(&surfaceShim), NO_ERROR);
-    EXPECT_EQ(surfaceShim.name, kSurfaceName);
-    EXPECT_FALSE(surfaceShim.graphicBufferProducer == nullptr);
-}
-
-INSTANTIATE_TEST_CASE_P(SurfaceBackends, SurfaceParcelableTest,
-                        ::testing::Values(CREATE_BUFFER_QUEUE_SURFACE, CREATE_BUFFER_HUB_SURFACE));
-
-} // namespace android
-
-int main(int argc, char** argv) {
-    pid_t pid = fork();
-    if (pid == 0) {
-        android::ProcessState::self()->startThreadPool();
-        ::testing::InitGoogleTest(&argc, argv);
-        return RUN_ALL_TESTS();
-
-    } else {
-        ALOGI("Test process pid: %d.", pid);
-        return android::runBinderServer();
-    }
-}
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 4127f7c..2b7483d 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -64,9 +64,10 @@
 }
 
 bool shouldDisregardTransformation(uint32_t source) {
-    // Do not apply any transformations to axes from joysticks or touchpads.
+    // Do not apply any transformations to axes from joysticks, touchpads, or relative mice.
     return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) ||
-            isFromSource(source, AINPUT_SOURCE_CLASS_POSITION);
+            isFromSource(source, AINPUT_SOURCE_CLASS_POSITION) ||
+            isFromSource(source, AINPUT_SOURCE_MOUSE_RELATIVE);
 }
 
 bool shouldDisregardOffset(uint32_t source) {
@@ -89,6 +90,25 @@
     }
 }
 
+const char* motionToolTypeToString(int32_t toolType) {
+    switch (toolType) {
+        case AMOTION_EVENT_TOOL_TYPE_UNKNOWN:
+            return "UNKNOWN";
+        case AMOTION_EVENT_TOOL_TYPE_FINGER:
+            return "FINGER";
+        case AMOTION_EVENT_TOOL_TYPE_STYLUS:
+            return "STYLUS";
+        case AMOTION_EVENT_TOOL_TYPE_MOUSE:
+            return "MOUSE";
+        case AMOTION_EVENT_TOOL_TYPE_ERASER:
+            return "ERASER";
+        case AMOTION_EVENT_TOOL_TYPE_PALM:
+            return "PALM";
+        default:
+            return "INVALID";
+    }
+}
+
 // --- IdGenerator ---
 IdGenerator::IdGenerator(Source source) : mSource(source) {}
 
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index a92016b..4b31246 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -715,10 +715,10 @@
 }
 
 TEST_F(MotionEventTest, JoystickAndTouchpadAreNotTransformed) {
-    constexpr static std::array kNonTransformedSources = {std::pair(AINPUT_SOURCE_TOUCHPAD,
-                                                                    AMOTION_EVENT_ACTION_DOWN),
-                                                          std::pair(AINPUT_SOURCE_JOYSTICK,
-                                                                    AMOTION_EVENT_ACTION_MOVE)};
+    constexpr static std::array kNonTransformedSources =
+            {std::pair(AINPUT_SOURCE_TOUCHPAD, AMOTION_EVENT_ACTION_DOWN),
+             std::pair(AINPUT_SOURCE_JOYSTICK, AMOTION_EVENT_ACTION_MOVE),
+             std::pair(AINPUT_SOURCE_MOUSE_RELATIVE, AMOTION_EVENT_ACTION_MOVE)};
     // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
     ui::Transform transform(ui::Transform::ROT_90, 800, 400);
     transform.set(transform.tx() + 20, transform.ty() + 40);
@@ -738,7 +738,7 @@
 TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) {
     constexpr static std::array kNonPointerSources = {std::pair(AINPUT_SOURCE_TRACKBALL,
                                                                 AMOTION_EVENT_ACTION_DOWN),
-                                                      std::pair(AINPUT_SOURCE_MOUSE_RELATIVE,
+                                                      std::pair(AINPUT_SOURCE_TOUCH_NAVIGATION,
                                                                 AMOTION_EVENT_ACTION_MOVE)};
     // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
     ui::Transform transform(ui::Transform::ROT_90, 800, 400);
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 4a1784e..b2e069c 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "AHardwareBuffer"
 
+#include <android/hardware_buffer.h>
+#include <android/hardware_buffer_aidl.h>
 #include <vndk/hardware_buffer.h>
 
 #include <errno.h>
@@ -32,6 +34,9 @@
 #include <android/hardware/graphics/common/1.1/types.h>
 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
 
+// TODO: Better way to handle this
+#include "../binder/ndk/parcel_internal.h"
+
 static constexpr int kFdBufferSize = 128 * sizeof(int);  // 128 ints
 
 using namespace android;
@@ -412,6 +417,25 @@
     return OK;
 }
 
+binder_status_t AHardwareBuffer_readFromParcel(const AParcel* _Nonnull parcel,
+        AHardwareBuffer* _Nullable* _Nonnull outBuffer) {
+    if (!parcel || !outBuffer) return STATUS_BAD_VALUE;
+    auto buffer = sp<GraphicBuffer>::make();
+    status_t status = parcel->get()->read(*buffer);
+    if (status != STATUS_OK) return status;
+    *outBuffer = AHardwareBuffer_from_GraphicBuffer(buffer.get());
+    AHardwareBuffer_acquire(*outBuffer);
+    return STATUS_OK;
+}
+
+binder_status_t AHardwareBuffer_writeToParcel(const AHardwareBuffer* _Nonnull buffer,
+        AParcel* _Nonnull parcel) {
+    const GraphicBuffer* gb = AHardwareBuffer_to_GraphicBuffer(buffer);
+    if (!gb) return STATUS_BAD_VALUE;
+    if (!parcel) return STATUS_BAD_VALUE;
+    return parcel->get()->write(*gb);
+}
+
 // ----------------------------------------------------------------------------
 // VNDK functions
 // ----------------------------------------------------------------------------
@@ -593,15 +617,27 @@
     static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_8) ==
                           AHARDWAREBUFFER_FORMAT_R8_UNORM,
             "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_16_UINT) ==
+                          AHARDWAREBUFFER_FORMAT_R16_UINT,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RG_1616_UINT) ==
+                          AHARDWAREBUFFER_FORMAT_R16G16_UINT,
+            "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RGBA_10101010) ==
+                          AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM,
+            "HAL and AHardwareBuffer pixel format don't match");
 
     switch (format) {
         case AHARDWAREBUFFER_FORMAT_R8_UNORM:
+        case AHARDWAREBUFFER_FORMAT_R16_UINT:
+        case AHARDWAREBUFFER_FORMAT_R16G16_UINT:
         case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
         case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
         case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
         case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
         case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
         case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
+        case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM:
         case AHARDWAREBUFFER_FORMAT_BLOB:
         case AHARDWAREBUFFER_FORMAT_D16_UNORM:
         case AHARDWAREBUFFER_FORMAT_D24_UNORM:
@@ -653,6 +689,7 @@
           return 1;
       case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
       case AHARDWAREBUFFER_FORMAT_D16_UNORM:
+      case AHARDWAREBUFFER_FORMAT_R16_UINT:
           return 2;
       case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
       case AHARDWAREBUFFER_FORMAT_D24_UNORM:
@@ -662,8 +699,10 @@
       case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
       case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
       case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
+      case AHARDWAREBUFFER_FORMAT_R16G16_UINT:
           return 4;
       case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+      case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM:
           return 8;
       default:
           return 0;
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 18a4b2d..3762e66 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -20,10 +20,15 @@
 // from nativewindow/includes/system/window.h
 // (not to be confused with the compatibility-only window.h from system/core/includes)
 #include <system/window.h>
+#include <android/native_window_aidl.h>
 
 #include <private/android/AHardwareBufferHelpers.h>
 
+#include <log/log.h>
 #include <ui/GraphicBuffer.h>
+#include <gui/Surface.h>
+#include <gui/view/Surface.h>
+#include <android/binder_libbinder.h>
 
 using namespace android;
 
@@ -59,6 +64,13 @@
             return false;
     }
 }
+static sp<IGraphicBufferProducer> IGraphicBufferProducer_from_ANativeWindow(ANativeWindow* window) {
+    return Surface::getIGraphicBufferProducer(window);
+}
+
+static sp<IBinder> SurfaceControlHandle_from_ANativeWindow(ANativeWindow* window) {
+    return Surface::getSurfaceControlHandle(window);
+}
 
 /**************************************************************************************************
  * NDK
@@ -334,6 +346,42 @@
     return native_window_set_auto_prerotation(window, autoPrerotation);
 }
 
+binder_status_t ANativeWindow_readFromParcel(
+        const AParcel* _Nonnull parcel, ANativeWindow* _Nullable* _Nonnull outWindow) {
+    const Parcel* nativeParcel = AParcel_viewPlatformParcel(parcel);
+
+    // Use a android::view::Surface to unparcel the window
+    std::shared_ptr<android::view::Surface> shimSurface = std::shared_ptr<android::view::Surface>();
+    status_t ret = shimSurface->readFromParcel(nativeParcel);
+    if (ret != OK) {
+        ALOGE("%s: Error: Failed to create android::view::Surface from AParcel", __FUNCTION__);
+        return STATUS_BAD_VALUE;
+    }
+    sp<Surface> surface = sp<Surface>::make(
+            shimSurface->graphicBufferProducer, false, shimSurface->surfaceControlHandle);
+    ANativeWindow* anw = surface.get();
+    ANativeWindow_acquire(anw);
+    *outWindow = anw;
+    return STATUS_OK;
+}
+
+binder_status_t ANativeWindow_writeToParcel(
+        ANativeWindow* _Nonnull window, AParcel* _Nonnull parcel) {
+    int value;
+    int err = (*window->query)(window, NATIVE_WINDOW_CONCRETE_TYPE, &value);
+    if (err != OK || value != NATIVE_WINDOW_SURFACE) {
+        ALOGE("Error: ANativeWindow is not backed by Surface");
+        return STATUS_BAD_VALUE;
+    }
+    // Use a android::view::Surface to parcelize the window
+    std::shared_ptr<android::view::Surface> shimSurface = std::shared_ptr<android::view::Surface>();
+    shimSurface->graphicBufferProducer = IGraphicBufferProducer_from_ANativeWindow(window);
+    shimSurface->surfaceControlHandle = SurfaceControlHandle_from_ANativeWindow(window);
+
+    Parcel* nativeParcel = AParcel_viewPlatformParcel(parcel);
+    return shimSurface->writeToParcel(nativeParcel);
+}
+
 /**************************************************************************************************
  * apex-stable
  **************************************************************************************************/
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index d7db6bd..bc0bfc5 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -74,6 +74,9 @@
         override_export_include_dirs: [
             "include",
         ],
+        export_llndk_headers: [
+            "libarect_headers",
+        ],
     },
     export_include_dirs: [
         "include",
@@ -99,25 +102,27 @@
         "liblog",
         "libutils",
         "libui",
+        "libbinder",
+        "libbinder_ndk",
         "android.hardware.graphics.common@1.1",
     ],
 
     static_libs: [
         "libarect",
         "libgrallocusage",
+        "libgui_aidl_static",
     ],
 
     header_libs: [
+        "libgui_headers",
+        "libarect_headers",
         "libnativebase_headers",
         "libnativewindow_headers",
     ],
 
     // headers we include in our public headers
-    export_static_lib_headers: [
-        "libarect",
-    ],
-
     export_header_lib_headers: [
+        "libarect_headers",
         "libnativebase_headers",
     ],
 
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index c35507b..b2e8bea 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -173,6 +173,27 @@
      *   OpenGL ES: GR_GL_R8
      */
     AHARDWAREBUFFER_FORMAT_R8_UNORM                 = 0x38,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_R16_UINT
+     *   OpenGL ES: GR_GL_R16UI
+     */
+    AHARDWAREBUFFER_FORMAT_R16_UINT                 = 0x39,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_R16G16_UINT
+     *   OpenGL ES: GR_GL_RG16UI
+     */
+    AHARDWAREBUFFER_FORMAT_R16G16_UINT              = 0x3a,
+
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16
+     *   OpenGL ES: N/A
+     */
+    AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM       = 0x3b,
 };
 
 /**
diff --git a/libs/nativewindow/include/android/hardware_buffer_aidl.h b/libs/nativewindow/include/android/hardware_buffer_aidl.h
new file mode 100644
index 0000000..906d9c6
--- /dev/null
+++ b/libs/nativewindow/include/android/hardware_buffer_aidl.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file hardware_buffer_aidl.h
+ * @brief HardwareBuffer NDK AIDL glue code
+ */
+
+/**
+ * @addtogroup AHardwareBuffer
+ *
+ * Parcelable support for AHardwareBuffer. Can be used with libbinder_ndk
+ *
+ * @{
+ */
+
+#ifndef ANDROID_HARDWARE_BUFFER_AIDL_H
+#define ANDROID_HARDWARE_BUFFER_AIDL_H
+
+#include <android/binder_parcel.h>
+#include <android/hardware_buffer.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Read an AHardwareBuffer from a AParcel. The output buffer will have an
+ * initial reference acquired and will need to be released with
+ * AHardwareBuffer_release.
+ *
+ * Available since API level 34.
+ *
+ * \return STATUS_OK on success
+ *         STATUS_BAD_VALUE if the parcel or outBuffer is null, or if there's an
+ *                          issue deserializing (eg, corrupted parcel)
+ *         STATUS_BAD_TYPE if the parcel's current data position is not that of
+ *                         an AHardwareBuffer type
+ *         STATUS_NO_MEMORY if an allocation fails
+ */
+binder_status_t AHardwareBuffer_readFromParcel(const AParcel* _Nonnull parcel,
+        AHardwareBuffer* _Nullable* _Nonnull outBuffer) __INTRODUCED_IN(34);
+
+/**
+ * Write an AHardwareBuffer to an AParcel.
+ *
+ * Available since API level 34.
+ *
+ * \return STATUS_OK on success.
+ *         STATUS_BAD_VALUE if either buffer or parcel is null, or if the AHardwareBuffer*
+ *                          fails to serialize (eg, internally corrupted)
+ *         STATUS_NO_MEMORY if the parcel runs out of space to store the buffer & is
+ *                          unable to allocate more
+ *         STATUS_FDS_NOT_ALLOWED if the parcel does not allow storing FDs
+ */
+binder_status_t AHardwareBuffer_writeToParcel(const AHardwareBuffer* _Nonnull buffer,
+        AParcel* _Nonnull parcel) __INTRODUCED_IN(34);
+
+__END_DECLS
+
+// Only enable the AIDL glue helper if this is C++
+#ifdef __cplusplus
+
+namespace aidl::android::hardware {
+
+/**
+ * Wrapper class that enables interop with AIDL NDK generation
+ * Takes ownership of the AHardwareBuffer* given to it in reset() and will automatically
+ * destroy it in the destructor, similar to a smart pointer container
+ */
+class HardwareBuffer {
+public:
+    HardwareBuffer() noexcept {}
+    explicit HardwareBuffer(HardwareBuffer&& other) noexcept : mBuffer(other.release()) {}
+
+    ~HardwareBuffer() {
+        reset();
+    }
+
+    binder_status_t readFromParcel(const AParcel* _Nonnull parcel) {
+        reset();
+        return AHardwareBuffer_readFromParcel(parcel, &mBuffer);
+    }
+
+    binder_status_t writeToParcel(AParcel* _Nonnull parcel) const {
+        if (!mBuffer) {
+            return STATUS_BAD_VALUE;
+        }
+        return AHardwareBuffer_writeToParcel(mBuffer, parcel);
+    }
+
+    /**
+     * Destroys any currently owned AHardwareBuffer* and takes ownership of the given
+     * AHardwareBuffer*
+     *
+     * @param buffer The buffer to take ownership of
+     */
+    void reset(AHardwareBuffer* _Nullable buffer = nullptr) noexcept {
+        if (mBuffer) {
+            AHardwareBuffer_release(mBuffer);
+            mBuffer = nullptr;
+        }
+        mBuffer = buffer;
+    }
+
+    inline AHardwareBuffer* _Nullable operator-> () const { return mBuffer;  }
+    inline AHardwareBuffer* _Nullable get() const { return mBuffer; }
+    inline explicit operator bool () const { return mBuffer != nullptr; }
+
+    HardwareBuffer& operator=(HardwareBuffer&& other) noexcept {
+        reset(other.release());
+        return *this;
+    }
+
+    /**
+     * Stops managing any contained AHardwareBuffer*, returning it to the caller. Ownership
+     * is released.
+     * @return AHardwareBuffer* or null if this was empty
+     */
+    [[nodiscard]] AHardwareBuffer* _Nullable release() noexcept {
+        AHardwareBuffer* _Nullable ret = mBuffer;
+        mBuffer = nullptr;
+        return ret;
+    }
+
+private:
+    HardwareBuffer(const HardwareBuffer& other) = delete;
+    HardwareBuffer& operator=(const HardwareBuffer& other) = delete;
+
+    AHardwareBuffer* _Nullable mBuffer = nullptr;
+};
+
+} // aidl::android::hardware
+
+#endif // __cplusplus
+
+#endif // ANDROID_HARDWARE_BUFFER_AIDL_H
+
+/** @} */
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index f0e1c4d..a593cd4 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -333,7 +333,7 @@
         __INTRODUCED_IN(31);
 
 #ifdef __cplusplus
-};
+}
 #endif
 
 #endif // ANDROID_NATIVE_WINDOW_H
diff --git a/libs/nativewindow/include/android/native_window_aidl.h b/libs/nativewindow/include/android/native_window_aidl.h
new file mode 100644
index 0000000..a252245
--- /dev/null
+++ b/libs/nativewindow/include/android/native_window_aidl.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file native_window_aidl.h
+ * @brief NativeWindow NDK AIDL glue code
+ */
+
+/**
+ * @addtogroup ANativeWindow
+ *
+ * Parcelable support for ANativeWindow. Can be used with libbinder_ndk
+ *
+ * @{
+ */
+
+#ifndef ANDROID_NATIVE_WINDOW_AIDL_H
+#define ANDROID_NATIVE_WINDOW_AIDL_H
+
+#include <android/binder_parcel.h>
+#include <android/native_window.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Read an ANativeWindow from a AParcel. The output buffer will have an
+ * initial reference acquired and will need to be released with
+ * ANativeWindow_release.
+ *
+ * Available since API level 34.
+ *
+ * \return STATUS_OK on success
+ *         STATUS_BAD_VALUE if the parcel or outBuffer is null, or if there's an
+ *                          issue deserializing (eg, corrupted parcel)
+ *         STATUS_BAD_TYPE if the parcel's current data position is not that of
+ *                         an ANativeWindow type
+ *         STATUS_NO_MEMORY if an allocation fails
+ */
+binder_status_t ANativeWindow_readFromParcel(const AParcel* _Nonnull parcel,
+        ANativeWindow* _Nullable* _Nonnull outWindow) __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
+ * Write an ANativeWindow to an AParcel.
+ *
+ * Available since API level 34.
+ *
+ * \return STATUS_OK on success.
+ *         STATUS_BAD_VALUE if either buffer or parcel is null, or if the ANativeWindow*
+ *                          fails to serialize (eg, internally corrupted)
+ *         STATUS_NO_MEMORY if the parcel runs out of space to store the buffer & is
+ *                          unable to allocate more
+ *         STATUS_FDS_NOT_ALLOWED if the parcel does not allow storing FDs
+ */
+binder_status_t ANativeWindow_writeToParcel(ANativeWindow* _Nonnull window,
+        AParcel* _Nonnull parcel) __INTRODUCED_IN(__ANDROID_API_U__);
+
+__END_DECLS
+
+// Only enable the AIDL glue helper if this is C++
+#ifdef __cplusplus
+
+namespace aidl::android::hardware {
+
+/**
+ * Wrapper class that enables interop with AIDL NDK generation
+ * Takes ownership of the ANativeWindow* given to it in reset() and will automatically
+ * destroy it in the destructor, similar to a smart pointer container
+ */
+class NativeWindow {
+public:
+    NativeWindow() noexcept {}
+    explicit NativeWindow(ANativeWindow* _Nullable window) {
+        reset(window);
+    }
+
+    explicit NativeWindow(NativeWindow&& other) noexcept {
+        mWindow = other.release(); // steal ownership from r-value
+    }
+
+    ~NativeWindow() {
+        reset();
+    }
+
+    binder_status_t readFromParcel(const AParcel* _Nonnull parcel) {
+        reset();
+        return ANativeWindow_readFromParcel(parcel, &mWindow);
+    }
+
+    binder_status_t writeToParcel(AParcel* _Nonnull parcel) const {
+        if (!mWindow) {
+            return STATUS_BAD_VALUE;
+        }
+        return ANativeWindow_writeToParcel(mWindow, parcel);
+    }
+
+    /**
+     * Destroys any currently owned ANativeWindow* and takes ownership of the given
+     * ANativeWindow*
+     *
+     * @param buffer The buffer to take ownership of
+     */
+    void reset(ANativeWindow* _Nullable window = nullptr) noexcept {
+        if (mWindow) {
+            ANativeWindow_release(mWindow);
+            mWindow = nullptr;
+        }
+        if (window != nullptr) {
+            ANativeWindow_acquire(window);
+        }
+        mWindow = window;
+    }
+    inline ANativeWindow* _Nullable operator-> () const { return mWindow;  }
+    inline ANativeWindow* _Nullable get() const { return mWindow; }
+    inline explicit operator bool () const { return mWindow != nullptr; }
+
+    NativeWindow& operator=(NativeWindow&& other) noexcept {
+        mWindow = other.release(); // steal ownership from r-value
+        return *this;
+    }
+
+    /**
+     * Stops managing any contained ANativeWindow*, returning it to the caller. Ownership
+     * is released.
+     * @return ANativeWindow* or null if this was empty
+     */
+    [[nodiscard]] ANativeWindow* _Nullable release() noexcept {
+        ANativeWindow* _Nullable ret = mWindow;
+        mWindow = nullptr;
+        return ret;
+    }
+private:
+    ANativeWindow* _Nullable mWindow = nullptr;
+    NativeWindow(const NativeWindow &other) = delete;
+    NativeWindow& operator=(const NativeWindow &other) = delete;
+};
+
+} // aidl::android::hardware
+  //
+namespace aidl::android::view {
+    using Surface = aidl::android::hardware::NativeWindow;
+}
+
+#endif // __cplusplus
+
+#endif // ANDROID_NATIVE_WINDOW_AIDL_H
+
+/** @} */
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index da42a96..d9ac568 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -14,6 +14,8 @@
     AHardwareBuffer_release;
     AHardwareBuffer_sendHandleToUnixSocket;
     AHardwareBuffer_unlock;
+    AHardwareBuffer_readFromParcel; # introduced=34
+    AHardwareBuffer_writeToParcel; # introduced=34
     ANativeWindowBuffer_getHardwareBuffer; # llndk
     ANativeWindow_OemStorageGet; # llndk
     ANativeWindow_OemStorageSet; # llndk
@@ -53,6 +55,8 @@
     ANativeWindow_setUsage; # llndk
     ANativeWindow_tryAllocateBuffers; # introduced=30
     ANativeWindow_unlockAndPost;
+    ANativeWindow_readFromParcel; # introduced=UpsideDownCake
+    ANativeWindow_writeToParcel; # introduced=UpsideDownCake
   local:
     *;
 };
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index 2b93c6e..b6b9cc4 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -21,9 +21,10 @@
     default_applicable_licenses: ["frameworks_native_license"],
 }
 
-cc_library_shared {
+cc_library {
     name: "libsensor",
 
+    host_supported: true,
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libs/shaders/Android.bp b/libs/shaders/Android.bp
index 6b936de..8477479 100644
--- a/libs/shaders/Android.bp
+++ b/libs/shaders/Android.bp
@@ -28,7 +28,7 @@
     local_include_dirs: ["include"],
 
     shared_libs: [
-        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.graphics.common-V4-ndk",
         "android.hardware.graphics.composer3-V1-ndk",
         "android.hardware.graphics.common@1.2",
         "libnativewindow",
diff --git a/libs/shaders/tests/Android.bp b/libs/shaders/tests/Android.bp
index cf671bc..718d37b 100644
--- a/libs/shaders/tests/Android.bp
+++ b/libs/shaders/tests/Android.bp
@@ -31,7 +31,7 @@
         "libtonemap_headers",
     ],
     shared_libs: [
-        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.graphics.common-V4-ndk",
         "android.hardware.graphics.composer3-V1-ndk",
         "android.hardware.graphics.common@1.2",
         "libnativewindow",
diff --git a/libs/tonemap/Android.bp b/libs/tonemap/Android.bp
index 37c9824..eca051d 100644
--- a/libs/tonemap/Android.bp
+++ b/libs/tonemap/Android.bp
@@ -28,7 +28,7 @@
     local_include_dirs: ["include"],
 
     shared_libs: [
-        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.graphics.common-V4-ndk",
         "android.hardware.graphics.composer3-V1-ndk",
         "liblog",
         "libnativewindow",
diff --git a/libs/tonemap/tests/Android.bp b/libs/tonemap/tests/Android.bp
index 58851b4..0002d3a 100644
--- a/libs/tonemap/tests/Android.bp
+++ b/libs/tonemap/tests/Android.bp
@@ -31,7 +31,7 @@
         "libtonemap_headers",
     ],
     shared_libs: [
-        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.graphics.common-V4-ndk",
         "android.hardware.graphics.composer3-V1-ndk",
         "libnativewindow",
     ],
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 0f771a9..98d9b94 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -155,6 +155,8 @@
     ],
 
     defaults: [
+        "android.hardware.graphics.allocator-ndk_shared",
+        "android.hardware.graphics.common-ndk_shared",
         "libui-defaults",
         // Uncomment the following line to enable VALIDATE_REGIONS traces
         //defaults: ["libui-validate-regions-defaults"],
@@ -164,8 +166,6 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.allocator@4.0",
-        "android.hardware.graphics.allocator-V1-ndk",
-        "android.hardware.graphics.common-V3-ndk",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
@@ -183,7 +183,6 @@
 
     export_shared_lib_headers: [
         "android.hardware.graphics.common@1.2",
-        "android.hardware.graphics.common-V3-ndk",
         "android.hardware.graphics.mapper@4.0",
         "libgralloctypes",
     ],
diff --git a/libs/ui/include/ui/PixelFormat.h b/libs/ui/include/ui/PixelFormat.h
index f422ce4..cf5c2e8 100644
--- a/libs/ui/include/ui/PixelFormat.h
+++ b/libs/ui/include/ui/PixelFormat.h
@@ -53,16 +53,19 @@
 
     // real pixel formats supported for rendering -----------------------------
 
-    PIXEL_FORMAT_RGBA_8888    = HAL_PIXEL_FORMAT_RGBA_8888,    // 4x8-bit RGBA
-    PIXEL_FORMAT_RGBX_8888    = HAL_PIXEL_FORMAT_RGBX_8888,    // 4x8-bit RGB0
-    PIXEL_FORMAT_RGB_888      = HAL_PIXEL_FORMAT_RGB_888,      // 3x8-bit RGB
-    PIXEL_FORMAT_RGB_565      = HAL_PIXEL_FORMAT_RGB_565,      // 16-bit RGB
-    PIXEL_FORMAT_BGRA_8888    = HAL_PIXEL_FORMAT_BGRA_8888,    // 4x8-bit BGRA
-    PIXEL_FORMAT_RGBA_5551    = 6,                             // 16-bit ARGB
-    PIXEL_FORMAT_RGBA_4444    = 7,                             // 16-bit ARGB
-    PIXEL_FORMAT_RGBA_FP16    = HAL_PIXEL_FORMAT_RGBA_FP16,    // 64-bit RGBA
-    PIXEL_FORMAT_RGBA_1010102 = HAL_PIXEL_FORMAT_RGBA_1010102, // 32-bit RGBA
-    PIXEL_FORMAT_R_8          = 0x38,
+    PIXEL_FORMAT_RGBA_8888     = HAL_PIXEL_FORMAT_RGBA_8888,    // 4x8-bit RGBA
+    PIXEL_FORMAT_RGBX_8888     = HAL_PIXEL_FORMAT_RGBX_8888,    // 4x8-bit RGB0
+    PIXEL_FORMAT_RGB_888       = HAL_PIXEL_FORMAT_RGB_888,      // 3x8-bit RGB
+    PIXEL_FORMAT_RGB_565       = HAL_PIXEL_FORMAT_RGB_565,      // 16-bit RGB
+    PIXEL_FORMAT_BGRA_8888     = HAL_PIXEL_FORMAT_BGRA_8888,    // 4x8-bit BGRA
+    PIXEL_FORMAT_RGBA_5551     = 6,                             // 16-bit ARGB
+    PIXEL_FORMAT_RGBA_4444     = 7,                             // 16-bit ARGB
+    PIXEL_FORMAT_RGBA_FP16     = HAL_PIXEL_FORMAT_RGBA_FP16,    // 64-bit RGBA
+    PIXEL_FORMAT_RGBA_1010102  = HAL_PIXEL_FORMAT_RGBA_1010102, // 32-bit RGBA
+    PIXEL_FORMAT_R_8           = 0x38,
+    PIXEL_FORMAT_R_16_UINT     = 0x39,
+    PIXEL_FORMAT_RG_1616_UINT  = 0x3a,
+    PIXEL_FORMAT_RGBA_10101010 = 0x3b,
 };
 
 typedef int32_t PixelFormat;
diff --git a/libs/vibrator/Android.bp b/libs/vibrator/Android.bp
index 83c250a..2af51a7 100644
--- a/libs/vibrator/Android.bp
+++ b/libs/vibrator/Android.bp
@@ -21,31 +21,8 @@
     default_applicable_licenses: ["frameworks_native_license"],
 }
 
-cc_library {
-    name: "libvibrator",
-    vendor_available: true,
-    double_loadable: true,
-
-    shared_libs: [
-        "libbinder",
-        "liblog",
-        "libutils",
-    ],
-
-    header_libs: [
-        "libaudio_system_headers",
-    ],
-
-    aidl: {
-        include_dirs: ["frameworks/base/core/java"],
-        local_include_dirs: ["include/"],
-        export_aidl_headers: true,
-    },
-
-    srcs: [
-        ":libvibrator_aidl",
-        "*.cpp",
-    ],
+cc_defaults {
+    name: "libvibrator_defaults",
 
     cflags: [
         "-Wall",
@@ -64,3 +41,54 @@
         },
     },
 }
+
+cc_library {
+    name: "libvibrator",
+    defaults: ["libvibrator_defaults"],
+
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+
+    whole_static_libs: [
+        "libvibratorutils",
+    ],
+
+    header_libs: [
+        "libaudio_system_headers",
+    ],
+
+    aidl: {
+        include_dirs: ["frameworks/base/core/java"],
+        local_include_dirs: ["include/"],
+        export_aidl_headers: true,
+    },
+
+    srcs: [
+        ":libvibrator_aidl",
+        "ExternalVibration.cpp",
+    ],
+}
+
+cc_library {
+    name: "libvibratorutils",
+    defaults: ["libvibrator_defaults"],
+
+    vendor_available: true,
+    double_loadable: true,
+
+    shared_libs: [
+        "libutils",
+    ],
+
+    srcs: [
+        "ExternalVibrationUtils.cpp",
+    ],
+
+    visibility: [
+        "//frameworks/native/libs/vibrator",
+        "//frameworks/av/media/libeffects/hapticgenerator",
+    ],
+}
diff --git a/libs/vibrator/ExternalVibration.cpp b/libs/vibrator/ExternalVibration.cpp
index f6fc19e..ec90645 100644
--- a/libs/vibrator/ExternalVibration.cpp
+++ b/libs/vibrator/ExternalVibration.cpp
@@ -15,11 +15,22 @@
  */
 
 #include <vibrator/ExternalVibration.h>
+#include <vibrator/ExternalVibrationUtils.h>
 
+#include <android/os/IExternalVibratorService.h>
 #include <binder/Parcel.h>
 #include <log/log.h>
 #include <utils/Errors.h>
 
+
+// To guarantee if HapticScale enum has the same value as IExternalVibratorService
+static_assert(static_cast<int>(android::os::HapticScale::MUTE) == static_cast<int>(android::os::IExternalVibratorService::SCALE_MUTE));
+static_assert(static_cast<int>(android::os::HapticScale::VERY_LOW) == static_cast<int>(android::os::IExternalVibratorService::SCALE_VERY_LOW));
+static_assert(static_cast<int>(android::os::HapticScale::LOW) == static_cast<int>(android::os::IExternalVibratorService::SCALE_LOW));
+static_assert(static_cast<int>(android::os::HapticScale::NONE) == static_cast<int>(android::os::IExternalVibratorService::SCALE_NONE));
+static_assert(static_cast<int>(android::os::HapticScale::HIGH) == static_cast<int>(android::os::IExternalVibratorService::SCALE_HIGH));
+static_assert(static_cast<int>(android::os::HapticScale::VERY_HIGH) == static_cast<int>(android::os::IExternalVibratorService::SCALE_VERY_HIGH));
+
 void writeAudioAttributes(const audio_attributes_t& attrs, android::Parcel* out) {
     out->writeInt32(attrs.usage);
     out->writeInt32(attrs.content_type);
diff --git a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
index 84357fc..c588bfd 100644
--- a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
+++ b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
@@ -17,17 +17,17 @@
 #ifndef ANDROID_EXTERNAL_VIBRATION_UTILS_H
 #define ANDROID_EXTERNAL_VIBRATION_UTILS_H
 
-#include <android/os/IExternalVibratorService.h>
-
 namespace android::os {
 
+// Copied from frameworks/base/core/java/android/os/IExternalVibratorService.aidl
+// The values are checked in ExternalVibration.cpp
 enum class HapticScale {
-    MUTE = IExternalVibratorService::SCALE_MUTE,
-    VERY_LOW = IExternalVibratorService::SCALE_VERY_LOW,
-    LOW = IExternalVibratorService::SCALE_LOW,
-    NONE = IExternalVibratorService::SCALE_NONE,
-    HIGH = IExternalVibratorService::SCALE_HIGH,
-    VERY_HIGH = IExternalVibratorService::SCALE_VERY_HIGH,
+    MUTE = -100,
+    VERY_LOW = -2,
+    LOW = -1,
+    NONE = 0,
+    HIGH = 1,
+    VERY_HIGH = 2,
 };
 
 bool isValidHapticScale(HapticScale scale);
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
deleted file mode 100644
index 0bda798..0000000
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_native_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_native_license"],
-}
-
-sourceFiles = [
-    "buffer_hub_queue_client.cpp",
-    "buffer_hub_queue_parcelable.cpp",
-]
-
-includeFiles = [
-    "include",
-]
-
-staticLibraries = [
-    "libbufferhub",
-]
-
-sharedLibraries = [
-    "libbinder",
-    "libcutils",
-    "liblog",
-    "libui",
-    "libutils",
-    "libpdx_default_transport",
-]
-
-headerLibraries = [
-    "libdvr_headers",
-    "libnativebase_headers",
-]
-
-cc_library_shared {
-    name: "libbufferhubqueue",
-    cflags: [
-        "-DLOG_TAG=\"libbufferhubqueue\"",
-        "-DTRACE=0",
-        "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
-        "-Wall",
-        "-Werror",
-        "-Wno-format",
-        "-Wno-unused-parameter",
-        "-Wno-unused-variable",
-    ],
-    srcs: sourceFiles,
-    export_include_dirs: includeFiles,
-    export_static_lib_headers: staticLibraries,
-    static_libs: staticLibraries,
-    shared_libs: sharedLibraries,
-    header_libs: headerLibraries,
-}
-
-subdirs = ["benchmarks", "tests"]
diff --git a/libs/vr/libbufferhubqueue/benchmarks/Android.bp b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
deleted file mode 100644
index e33e03b..0000000
--- a/libs/vr/libbufferhubqueue/benchmarks/Android.bp
+++ /dev/null
@@ -1,35 +0,0 @@
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_native_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_native_license"],
-}
-
-cc_benchmark {
-    srcs: ["buffer_transport_benchmark.cpp"],
-    shared_libs: [
-        "libbase",
-        "libbinder",
-        "libcutils",
-        "libdvr.google",
-        "libgui",
-        "liblog",
-        "libhardware",
-        "libui",
-        "libutils",
-        "libnativewindow",
-        "libbufferhubqueue",
-        "libpdx_default_transport",
-    ],
-    cflags: [
-        "-DLOG_TAG=\"buffer_transport_benchmark\"",
-        "-DTRACE=0",
-        "-O2",
-        "-Wall",
-        "-Werror",
-    ],
-    name: "buffer_transport_benchmark",
-}
diff --git a/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
deleted file mode 100644
index b6813eb..0000000
--- a/libs/vr/libbufferhubqueue/benchmarks/buffer_transport_benchmark.cpp
+++ /dev/null
@@ -1,589 +0,0 @@
-#include <android-base/logging.h>
-#include <android/native_window.h>
-#include <benchmark/benchmark.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <dvr/dvr_api.h>
-#include <gui/BufferItem.h>
-#include <gui/BufferItemConsumer.h>
-#include <gui/Surface.h>
-#include <private/dvr/epoll_file_descriptor.h>
-#include <utils/Trace.h>
-
-#include <chrono>
-#include <functional>
-#include <iostream>
-#include <thread>
-#include <vector>
-
-#include <dlfcn.h>
-#include <poll.h>
-#include <sys/epoll.h>
-#include <sys/wait.h>
-
-// Use ALWAYS at the tag level. Control is performed manually during command
-// line processing.
-#ifdef ATRACE_TAG
-#undef ATRACE_TAG
-#endif
-#define ATRACE_TAG ATRACE_TAG_ALWAYS
-
-using namespace android;
-using ::benchmark::State;
-
-static const String16 kBinderService = String16("bufferTransport");
-static const uint32_t kBufferWidth = 100;
-static const uint32_t kBufferHeight = 1;
-static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-static const uint64_t kBufferUsage =
-    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
-static const uint32_t kBufferLayer = 1;
-static const int kMaxAcquiredImages = 1;
-static const int kQueueDepth = 2;  // We are double buffering for this test.
-static const size_t kMaxQueueCounts = 128;
-static const int kInvalidFence = -1;
-
-enum BufferTransportServiceCode {
-  CREATE_BUFFER_QUEUE = IBinder::FIRST_CALL_TRANSACTION,
-};
-
-// A binder services that minics a compositor that consumes buffers. It provides
-// one Binder interface to create a new Surface for buffer producer to write
-// into; while itself will carry out no-op buffer consuming by acquiring then
-// releasing the buffer immediately.
-class BufferTransportService : public BBinder {
- public:
-  BufferTransportService() = default;
-  ~BufferTransportService() = default;
-
-  virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-                              uint32_t flags = 0) {
-    (void)flags;
-    (void)data;
-    switch (code) {
-      case CREATE_BUFFER_QUEUE: {
-        auto new_queue = std::make_shared<BufferQueueHolder>(this);
-        reply->writeStrongBinder(
-            IGraphicBufferProducer::asBinder(new_queue->producer));
-        buffer_queues_.push_back(new_queue);
-        return OK;
-      }
-      default:
-        return UNKNOWN_TRANSACTION;
-    };
-  }
-
- private:
-  struct FrameListener : public ConsumerBase::FrameAvailableListener {
-   public:
-    FrameListener(BufferTransportService* /*service*/,
-                  sp<BufferItemConsumer> buffer_item_consumer)
-        : buffer_item_consumer_(buffer_item_consumer) {}
-
-    void onFrameAvailable(const BufferItem& /*item*/) override {
-      BufferItem buffer;
-      status_t ret = 0;
-      {
-        ATRACE_NAME("AcquireBuffer");
-        ret = buffer_item_consumer_->acquireBuffer(&buffer, /*presentWhen=*/0,
-                                                   /*waitForFence=*/false);
-      }
-
-      if (ret != OK) {
-        LOG(ERROR) << "Failed to acquire next buffer.";
-        return;
-      }
-
-      {
-        ATRACE_NAME("ReleaseBuffer");
-        ret = buffer_item_consumer_->releaseBuffer(buffer);
-      }
-
-      if (ret != OK) {
-        LOG(ERROR) << "Failed to release buffer.";
-        return;
-      }
-    }
-
-   private:
-    sp<BufferItemConsumer> buffer_item_consumer_;
-  };
-
-  struct BufferQueueHolder {
-    explicit BufferQueueHolder(BufferTransportService* service) {
-      BufferQueue::createBufferQueue(&producer, &consumer);
-
-      sp<BufferItemConsumer> buffer_item_consumer =
-          new BufferItemConsumer(consumer, kBufferUsage, kMaxAcquiredImages,
-                                 /*controlledByApp=*/true);
-      buffer_item_consumer->setName(String8("BinderBufferTransport"));
-      frame_listener_ = new FrameListener(service, buffer_item_consumer);
-      buffer_item_consumer->setFrameAvailableListener(frame_listener_);
-    }
-
-    sp<IGraphicBufferProducer> producer;
-    sp<IGraphicBufferConsumer> consumer;
-
-   private:
-    sp<FrameListener> frame_listener_;
-  };
-
-  std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
-};
-
-// A virtual interfaces that abstracts the common BufferQueue operations, so
-// that the test suite can use the same test case to drive different types of
-// transport backends.
-class BufferTransport {
- public:
-  virtual ~BufferTransport() {}
-
-  virtual int Start() = 0;
-  virtual sp<Surface> CreateSurface() = 0;
-};
-
-// Binder-based buffer transport backend.
-//
-// On Start() a new process will be swapned to run a Binder server that
-// actually consumes the buffer.
-// On CreateSurface() a new Binder BufferQueue will be created, which the
-// service holds the concrete binder node of the IGraphicBufferProducer while
-// sending the binder proxy to the client. In another word, the producer side
-// operations are carried out process while the consumer side operations are
-// carried out within the BufferTransportService's own process.
-class BinderBufferTransport : public BufferTransport {
- public:
-  BinderBufferTransport() {}
-
-  int Start() override {
-    sp<IServiceManager> sm = defaultServiceManager();
-    service_ = sm->getService(kBinderService);
-    if (service_ == nullptr) {
-      LOG(ERROR) << "Failed to get the benchmark service.";
-      return -EIO;
-    }
-
-    LOG(INFO) << "Binder server is ready for client.";
-    return 0;
-  }
-
-  sp<Surface> CreateSurface() override {
-    Parcel data;
-    Parcel reply;
-    int error = service_->transact(CREATE_BUFFER_QUEUE, data, &reply);
-    if (error != OK) {
-      LOG(ERROR) << "Failed to get buffer queue over binder.";
-      return nullptr;
-    }
-
-    sp<IBinder> binder;
-    error = reply.readNullableStrongBinder(&binder);
-    if (error != OK) {
-      LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder.";
-      return nullptr;
-    }
-
-    auto producer = interface_cast<IGraphicBufferProducer>(binder);
-    if (producer == nullptr) {
-      LOG(ERROR) << "Failed to get IGraphicBufferProducer over binder.";
-      return nullptr;
-    }
-
-    sp<Surface> surface = new Surface(producer, /*controlledByApp=*/true);
-
-    // Set buffer dimension.
-    ANativeWindow* window = static_cast<ANativeWindow*>(surface.get());
-    ANativeWindow_setBuffersGeometry(window, kBufferWidth, kBufferHeight,
-                                     kBufferFormat);
-
-    return surface;
-  }
-
- private:
-  sp<IBinder> service_;
-};
-
-class DvrApi {
- public:
-  DvrApi() {
-    handle_ = dlopen("libdvr.google.so", RTLD_NOW | RTLD_LOCAL);
-    CHECK(handle_);
-
-    auto dvr_get_api =
-        reinterpret_cast<decltype(&dvrGetApi)>(dlsym(handle_, "dvrGetApi"));
-    int ret = dvr_get_api(&api_, sizeof(api_), /*version=*/1);
-
-    CHECK(ret == 0);
-  }
-
-  ~DvrApi() { dlclose(handle_); }
-
-  const DvrApi_v1& Api() { return api_; }
-
- private:
-  void* handle_ = nullptr;
-  DvrApi_v1 api_;
-};
-
-// BufferHub/PDX-based buffer transport.
-//
-// On Start() a new thread will be swapned to run an epoll polling thread which
-// minics the behavior of a compositor. Similar to Binder-based backend, the
-// buffer available handler is also a no-op: Buffer gets acquired and released
-// immediately.
-// On CreateSurface() a pair of dvr::ProducerQueue and dvr::ConsumerQueue will
-// be created. The epoll thread holds on the consumer queue and dequeues buffer
-// from it; while the producer queue will be wrapped in a Surface and returned
-// to test suite.
-class BufferHubTransport : public BufferTransport {
- public:
-  virtual ~BufferHubTransport() {
-    stopped_.store(true);
-    if (reader_thread_.joinable()) {
-      reader_thread_.join();
-    }
-  }
-
-  int Start() override {
-    int ret = epoll_fd_.Create();
-    if (ret < 0) {
-      LOG(ERROR) << "Failed to create epoll fd: %s", strerror(-ret);
-      return -1;
-    }
-
-    // Create the reader thread.
-    reader_thread_ = std::thread([this]() {
-      int ret = dvr_.Api().PerformanceSetSchedulerPolicy(0, "graphics");
-      if (ret < 0) {
-        LOG(ERROR) << "Failed to set scheduler policy, ret=" << ret;
-        return;
-      }
-
-      stopped_.store(false);
-      LOG(INFO) << "Reader Thread Running...";
-
-      while (!stopped_.load()) {
-        std::array<epoll_event, kMaxQueueCounts> events;
-
-        // Don't sleep forever so that we will have a chance to wake up.
-        const int ret = epoll_fd_.Wait(events.data(), events.size(),
-                                       /*timeout=*/100);
-        if (ret < 0) {
-          LOG(ERROR) << "Error polling consumer queues.";
-          continue;
-        }
-        if (ret == 0) {
-          continue;
-        }
-
-        const int num_events = ret;
-        for (int i = 0; i < num_events; i++) {
-          uint32_t index = events[i].data.u32;
-          dvr_.Api().ReadBufferQueueHandleEvents(
-              buffer_queues_[index]->GetReadQueue());
-        }
-      }
-
-      LOG(INFO) << "Reader Thread Exiting...";
-    });
-
-    return 0;
-  }
-
-  sp<Surface> CreateSurface() override {
-    auto new_queue = std::make_shared<BufferQueueHolder>();
-    if (!new_queue->IsReady()) {
-      LOG(ERROR) << "Failed to create BufferHub-based BufferQueue.";
-      return nullptr;
-    }
-
-    // Set buffer dimension.
-    ANativeWindow_setBuffersGeometry(new_queue->GetSurface(), kBufferWidth,
-                                     kBufferHeight, kBufferFormat);
-
-    // Use the next position as buffer_queue index.
-    uint32_t index = buffer_queues_.size();
-    epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u32 = index}};
-    int queue_fd =
-        dvr_.Api().ReadBufferQueueGetEventFd(new_queue->GetReadQueue());
-    const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, queue_fd, &event);
-    if (ret < 0) {
-      LOG(ERROR) << "Failed to track consumer queue: " << strerror(-ret)
-                 << ", consumer queue fd: " << queue_fd;
-      return nullptr;
-    }
-
-    buffer_queues_.push_back(new_queue);
-    ANativeWindow_acquire(new_queue->GetSurface());
-    return static_cast<Surface*>(new_queue->GetSurface());
-  }
-
- private:
-  struct BufferQueueHolder {
-    BufferQueueHolder() {
-      int ret = 0;
-      ret = dvr_.Api().WriteBufferQueueCreate(
-          kBufferWidth, kBufferHeight, kBufferFormat, kBufferLayer,
-          kBufferUsage, 0, sizeof(DvrNativeBufferMetadata), &write_queue_);
-      if (ret < 0) {
-        LOG(ERROR) << "Failed to create write buffer queue, ret=" << ret;
-        return;
-      }
-
-      ret = dvr_.Api().WriteBufferQueueCreateReadQueue(write_queue_,
-                                                       &read_queue_);
-      if (ret < 0) {
-        LOG(ERROR) << "Failed to create read buffer queue, ret=" << ret;
-        return;
-      }
-
-      ret = dvr_.Api().ReadBufferQueueSetBufferAvailableCallback(
-          read_queue_, BufferAvailableCallback, this);
-      if (ret < 0) {
-        LOG(ERROR) << "Failed to create buffer available callback, ret=" << ret;
-        return;
-      }
-
-      ret =
-          dvr_.Api().WriteBufferQueueGetANativeWindow(write_queue_, &surface_);
-      if (ret < 0) {
-        LOG(ERROR) << "Failed to create surface, ret=" << ret;
-        return;
-      }
-    }
-
-    static void BufferAvailableCallback(void* context) {
-      BufferQueueHolder* thiz = static_cast<BufferQueueHolder*>(context);
-      thiz->HandleBufferAvailable();
-    }
-
-    DvrReadBufferQueue* GetReadQueue() { return read_queue_; }
-
-    ANativeWindow* GetSurface() { return surface_; }
-
-    bool IsReady() {
-      return write_queue_ != nullptr && read_queue_ != nullptr &&
-             surface_ != nullptr;
-    }
-
-    void HandleBufferAvailable() {
-      int ret = 0;
-      DvrNativeBufferMetadata meta;
-      DvrReadBuffer* buffer = nullptr;
-      DvrNativeBufferMetadata metadata;
-      int acquire_fence = kInvalidFence;
-
-      {
-        ATRACE_NAME("AcquireBuffer");
-        ret = dvr_.Api().ReadBufferQueueAcquireBuffer(
-            read_queue_, 0, &buffer, &metadata, &acquire_fence);
-      }
-      if (ret < 0) {
-        LOG(ERROR) << "Failed to acquire consumer buffer, error: " << ret;
-        return;
-      }
-
-      if (buffer != nullptr) {
-        ATRACE_NAME("ReleaseBuffer");
-        ret = dvr_.Api().ReadBufferQueueReleaseBuffer(read_queue_, buffer,
-                                                      &meta, kInvalidFence);
-      }
-      if (ret < 0) {
-        LOG(ERROR) << "Failed to release consumer buffer, error: " << ret;
-      }
-    }
-
-   private:
-    DvrWriteBufferQueue* write_queue_ = nullptr;
-    DvrReadBufferQueue* read_queue_ = nullptr;
-    ANativeWindow* surface_ = nullptr;
-  };
-
-  static DvrApi dvr_;
-  std::atomic<bool> stopped_;
-  std::thread reader_thread_;
-
-  dvr::EpollFileDescriptor epoll_fd_;
-  std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
-};
-
-DvrApi BufferHubTransport::dvr_ = {};
-
-enum TransportType {
-  kBinderBufferTransport,
-  kBufferHubTransport,
-};
-
-// Main test suite, which supports two transport backend: 1) BinderBufferQueue,
-// 2) BufferHubQueue. The test case drives the producer end of both transport
-// backend by queuing buffers into the buffer queue by using ANativeWindow API.
-class BufferTransportBenchmark : public ::benchmark::Fixture {
- public:
-  void SetUp(State& state) override {
-    if (state.thread_index == 0) {
-      const int transport = state.range(0);
-      switch (transport) {
-        case kBinderBufferTransport:
-          transport_.reset(new BinderBufferTransport);
-          break;
-        case kBufferHubTransport:
-          transport_.reset(new BufferHubTransport);
-          break;
-        default:
-          CHECK(false) << "Unknown test case.";
-          break;
-      }
-
-      CHECK(transport_);
-      const int ret = transport_->Start();
-      CHECK_EQ(ret, 0);
-
-      LOG(INFO) << "Transport backend running, transport=" << transport << ".";
-
-      // Create surfaces for each thread.
-      surfaces_.resize(state.threads);
-      for (int i = 0; i < state.threads; i++) {
-        // Common setup every thread needs.
-        surfaces_[i] = transport_->CreateSurface();
-        CHECK(surfaces_[i]);
-
-        LOG(INFO) << "Surface initialized on thread " << i << ".";
-      }
-    }
-  }
-
-  void TearDown(State& state) override {
-    if (state.thread_index == 0) {
-      surfaces_.clear();
-      transport_.reset();
-      LOG(INFO) << "Tear down benchmark.";
-    }
-  }
-
- protected:
-  std::unique_ptr<BufferTransport> transport_;
-  std::vector<sp<Surface>> surfaces_;
-};
-
-BENCHMARK_DEFINE_F(BufferTransportBenchmark, Producers)(State& state) {
-  ANativeWindow* window = nullptr;
-  ANativeWindow_Buffer buffer;
-  int32_t error = 0;
-  double total_gain_buffer_us = 0;
-  double total_post_buffer_us = 0;
-  int iterations = 0;
-
-  while (state.KeepRunning()) {
-    if (window == nullptr) {
-      CHECK(surfaces_[state.thread_index]);
-      window = static_cast<ANativeWindow*>(surfaces_[state.thread_index].get());
-
-      // Lock buffers a couple time from the queue, so that we have the buffer
-      // allocated.
-      for (int i = 0; i < kQueueDepth; i++) {
-        error = ANativeWindow_lock(window, &buffer,
-                                   /*inOutDirtyBounds=*/nullptr);
-        CHECK_EQ(error, 0);
-        error = ANativeWindow_unlockAndPost(window);
-        CHECK_EQ(error, 0);
-      }
-    }
-
-    {
-      ATRACE_NAME("GainBuffer");
-      auto t1 = std::chrono::high_resolution_clock::now();
-      error = ANativeWindow_lock(window, &buffer,
-                                 /*inOutDirtyBounds=*/nullptr);
-      auto t2 = std::chrono::high_resolution_clock::now();
-      std::chrono::duration<double, std::micro> delta_us = t2 - t1;
-      total_gain_buffer_us += delta_us.count();
-    }
-    CHECK_EQ(error, 0);
-
-    {
-      ATRACE_NAME("PostBuffer");
-      auto t1 = std::chrono::high_resolution_clock::now();
-      error = ANativeWindow_unlockAndPost(window);
-      auto t2 = std::chrono::high_resolution_clock::now();
-      std::chrono::duration<double, std::micro> delta_us = t2 - t1;
-      total_post_buffer_us += delta_us.count();
-    }
-    CHECK_EQ(error, 0);
-
-    iterations++;
-  }
-
-  state.counters["gain_buffer_us"] = ::benchmark::Counter(
-      total_gain_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
-  state.counters["post_buffer_us"] = ::benchmark::Counter(
-      total_post_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
-  state.counters["producer_us"] = ::benchmark::Counter(
-      (total_gain_buffer_us + total_post_buffer_us) / iterations,
-      ::benchmark::Counter::kAvgThreads);
-}
-
-BENCHMARK_REGISTER_F(BufferTransportBenchmark, Producers)
-    ->Unit(::benchmark::kMicrosecond)
-    ->Ranges({{kBinderBufferTransport, kBufferHubTransport}})
-    ->ThreadRange(1, 32);
-
-static void runBinderServer() {
-  ProcessState::self()->setThreadPoolMaxThreadCount(0);
-  ProcessState::self()->startThreadPool();
-
-  sp<IServiceManager> sm = defaultServiceManager();
-  sp<BufferTransportService> service = new BufferTransportService;
-  sm->addService(kBinderService, service, false);
-
-  LOG(INFO) << "Binder server running...";
-
-  while (true) {
-    int stat, retval;
-    retval = wait(&stat);
-    if (retval == -1 && errno == ECHILD) {
-      break;
-    }
-  }
-
-  LOG(INFO) << "Service Exiting...";
-}
-
-// To run binder-based benchmark, use:
-// adb shell buffer_transport_benchmark \
-//   --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/0/"
-//
-// To run bufferhub-based benchmark, use:
-// adb shell buffer_transport_benchmark \
-//   --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/1/"
-int main(int argc, char** argv) {
-  bool tracing_enabled = false;
-
-  // Parse arguments in addition to "--benchmark_filter" paramters.
-  for (int i = 1; i < argc; i++) {
-    if (std::string(argv[i]) == "--help") {
-      std::cout << "Usage: binderThroughputTest [OPTIONS]" << std::endl;
-      std::cout << "\t--trace: Enable systrace logging." << std::endl;
-      return 0;
-    }
-    if (std::string(argv[i]) == "--trace") {
-      tracing_enabled = true;
-      continue;
-    }
-  }
-
-  // Setup ATRACE/systrace based on command line.
-  atrace_setup();
-  atrace_set_tracing_enabled(tracing_enabled);
-
-  pid_t pid = fork();
-  if (pid == 0) {
-    // Child, i.e. the client side.
-    ProcessState::self()->startThreadPool();
-
-    ::benchmark::Initialize(&argc, argv);
-    ::benchmark::RunSpecifiedBenchmarks();
-  } else {
-    LOG(INFO) << "Benchmark process pid: " << pid;
-    runBinderServer();
-  }
-}
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
deleted file mode 100644
index 2d3fa4a..0000000
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ /dev/null
@@ -1,823 +0,0 @@
-#include "include/private/dvr/buffer_hub_queue_client.h"
-
-#include <inttypes.h>
-#include <log/log.h>
-#include <poll.h>
-#include <sys/epoll.h>
-
-#include <array>
-
-#include <pdx/default_transport/client_channel.h>
-#include <pdx/default_transport/client_channel_factory.h>
-#include <pdx/file_handle.h>
-#include <pdx/trace.h>
-
-#define RETRY_EINTR(fnc_call)                 \
-  ([&]() -> decltype(fnc_call) {              \
-    decltype(fnc_call) result;                \
-    do {                                      \
-      result = (fnc_call);                    \
-    } while (result == -1 && errno == EINTR); \
-    return result;                            \
-  })()
-
-using android::pdx::ErrorStatus;
-using android::pdx::LocalChannelHandle;
-using android::pdx::LocalHandle;
-using android::pdx::Status;
-
-namespace android {
-namespace dvr {
-
-namespace {
-
-std::pair<int32_t, int32_t> Unstuff(uint64_t value) {
-  return {static_cast<int32_t>(value >> 32),
-          static_cast<int32_t>(value & ((1ull << 32) - 1))};
-}
-
-uint64_t Stuff(int32_t a, int32_t b) {
-  const uint32_t ua = static_cast<uint32_t>(a);
-  const uint32_t ub = static_cast<uint32_t>(b);
-  return (static_cast<uint64_t>(ua) << 32) | static_cast<uint64_t>(ub);
-}
-
-}  // anonymous namespace
-
-BufferHubQueue::BufferHubQueue(LocalChannelHandle channel_handle)
-    : Client{pdx::default_transport::ClientChannel::Create(
-          std::move(channel_handle))} {
-  Initialize();
-}
-
-BufferHubQueue::BufferHubQueue(const std::string& endpoint_path)
-    : Client{
-          pdx::default_transport::ClientChannelFactory::Create(endpoint_path)} {
-  Initialize();
-}
-
-void BufferHubQueue::Initialize() {
-  int ret = epoll_fd_.Create();
-  if (ret < 0) {
-    ALOGE("BufferHubQueue::BufferHubQueue: Failed to create epoll fd: %s",
-          strerror(-ret));
-    return;
-  }
-
-  epoll_event event = {
-      .events = EPOLLIN | EPOLLET,
-      .data = {.u64 = Stuff(-1, BufferHubQueue::kEpollQueueEventIndex)}};
-  ret = epoll_fd_.Control(EPOLL_CTL_ADD, event_fd(), &event);
-  if (ret < 0) {
-    ALOGE("%s: Failed to add event fd to epoll set: %s", __FUNCTION__,
-          strerror(-ret));
-  }
-}
-
-Status<void> BufferHubQueue::ImportQueue() {
-  auto status = InvokeRemoteMethod<BufferHubRPC::GetQueueInfo>();
-  if (!status) {
-    ALOGE("%s: Failed to import queue: %s", __FUNCTION__,
-          status.GetErrorMessage().c_str());
-    return ErrorStatus(status.error());
-  } else {
-    SetupQueue(status.get());
-    return {};
-  }
-}
-
-void BufferHubQueue::SetupQueue(const QueueInfo& queue_info) {
-  is_async_ = queue_info.producer_config.is_async;
-  default_width_ = queue_info.producer_config.default_width;
-  default_height_ = queue_info.producer_config.default_height;
-  default_format_ = queue_info.producer_config.default_format;
-  user_metadata_size_ = queue_info.producer_config.user_metadata_size;
-  id_ = queue_info.id;
-}
-
-std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() {
-  if (auto status = CreateConsumerQueueHandle(/*silent*/ false))
-    return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
-  else
-    return nullptr;
-}
-
-std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateSilentConsumerQueue() {
-  if (auto status = CreateConsumerQueueHandle(/*silent*/ true))
-    return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
-  else
-    return nullptr;
-}
-
-Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle(
-    bool silent) {
-  auto status = InvokeRemoteMethod<BufferHubRPC::CreateConsumerQueue>(silent);
-  if (!status) {
-    ALOGE(
-        "BufferHubQueue::CreateConsumerQueue: Failed to create consumer queue: "
-        "%s",
-        status.GetErrorMessage().c_str());
-    return ErrorStatus(status.error());
-  }
-
-  return status;
-}
-
-pdx::Status<ConsumerQueueParcelable>
-BufferHubQueue::CreateConsumerQueueParcelable(bool silent) {
-  auto status = CreateConsumerQueueHandle(silent);
-  if (!status)
-    return status.error_status();
-
-  // A temporary consumer queue client to pull its channel parcelable.
-  auto consumer_queue =
-      std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
-  ConsumerQueueParcelable queue_parcelable(
-      consumer_queue->GetChannel()->TakeChannelParcelable());
-
-  if (!queue_parcelable.IsValid()) {
-    ALOGE("%s: Failed to create consumer queue parcelable.", __FUNCTION__);
-    return ErrorStatus(EINVAL);
-  }
-
-  return {std::move(queue_parcelable)};
-}
-
-bool BufferHubQueue::WaitForBuffers(int timeout) {
-  ATRACE_NAME("BufferHubQueue::WaitForBuffers");
-  std::array<epoll_event, kMaxEvents> events;
-
-  // Loop at least once to check for hangups.
-  do {
-    ALOGD_IF(
-        TRACE,
-        "BufferHubQueue::WaitForBuffers: queue_id=%d count=%zu capacity=%zu",
-        id(), count(), capacity());
-
-    // If there is already a buffer then just check for hangup without waiting.
-    const int ret = epoll_fd_.Wait(events.data(), events.size(),
-                                   count() == 0 ? timeout : 0);
-
-    if (ret == 0) {
-      ALOGI_IF(TRACE,
-               "BufferHubQueue::WaitForBuffers: No events before timeout: "
-               "queue_id=%d",
-               id());
-      return count() != 0;
-    }
-
-    if (ret < 0 && ret != -EINTR) {
-      ALOGE("%s: Failed to wait for buffers: %s", __FUNCTION__, strerror(-ret));
-      return false;
-    }
-
-    const int num_events = ret;
-
-    // A BufferQueue's epoll fd tracks N+1 events, where there are N events,
-    // one for each buffer in the queue, and one extra event for the queue
-    // client itself.
-    for (int i = 0; i < num_events; i++) {
-      int32_t event_fd;
-      int32_t index;
-      std::tie(event_fd, index) = Unstuff(events[i].data.u64);
-
-      PDX_TRACE_FORMAT(
-          "epoll_event|queue_id=%d;num_events=%d;event_index=%d;event_fd=%d;"
-          "slot=%d|",
-          id(), num_events, i, event_fd, index);
-
-      ALOGD_IF(TRACE,
-               "BufferHubQueue::WaitForBuffers: event %d: event_fd=%d index=%d",
-               i, event_fd, index);
-
-      if (is_buffer_event_index(index)) {
-        HandleBufferEvent(static_cast<size_t>(index), event_fd,
-                          events[i].events);
-      } else if (is_queue_event_index(index)) {
-        HandleQueueEvent(events[i].events);
-      } else {
-        ALOGW(
-            "BufferHubQueue::WaitForBuffers: Unknown event type event_fd=%d "
-            "index=%d",
-            event_fd, index);
-      }
-    }
-  } while (count() == 0 && capacity() > 0 && !hung_up());
-
-  return count() != 0;
-}
-
-Status<void> BufferHubQueue::HandleBufferEvent(size_t slot, int event_fd,
-                                               int poll_events) {
-  ATRACE_NAME("BufferHubQueue::HandleBufferEvent");
-  if (!buffers_[slot]) {
-    ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot);
-    return ErrorStatus(ENOENT);
-  }
-
-  auto status = buffers_[slot]->GetEventMask(poll_events);
-  if (!status) {
-    ALOGW("BufferHubQueue::HandleBufferEvent: Failed to get event mask: %s",
-          status.GetErrorMessage().c_str());
-    return status.error_status();
-  }
-
-  const int events = status.get();
-  PDX_TRACE_FORMAT(
-      "buffer|queue_id=%d;buffer_id=%d;slot=%zu;event_fd=%d;poll_events=%x;"
-      "events=%d|",
-      id(), buffers_[slot]->id(), slot, event_fd, poll_events, events);
-
-  if (events & EPOLLIN) {
-    return Enqueue({buffers_[slot], slot, buffers_[slot]->GetQueueIndex()});
-  } else if (events & EPOLLHUP) {
-    ALOGW(
-        "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP event: slot=%zu "
-        "event_fd=%d buffer_id=%d",
-        slot, buffers_[slot]->event_fd(), buffers_[slot]->id());
-    return RemoveBuffer(slot);
-  } else {
-    ALOGW(
-        "BufferHubQueue::HandleBufferEvent: Unknown event, slot=%zu, epoll "
-        "events=%d",
-        slot, events);
-  }
-
-  return {};
-}
-
-Status<void> BufferHubQueue::HandleQueueEvent(int poll_event) {
-  ATRACE_NAME("BufferHubQueue::HandleQueueEvent");
-  auto status = GetEventMask(poll_event);
-  if (!status) {
-    ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s",
-          status.GetErrorMessage().c_str());
-    return status.error_status();
-  }
-
-  const int events = status.get();
-  if (events & EPOLLIN) {
-    // Note that after buffer imports, if |count()| still returns 0, epoll
-    // wait will be tried again to acquire the newly imported buffer.
-    auto buffer_status = OnBufferAllocated();
-    if (!buffer_status) {
-      ALOGE("%s: Failed to import buffer: %s", __FUNCTION__,
-            buffer_status.GetErrorMessage().c_str());
-    }
-  } else if (events & EPOLLHUP) {
-    ALOGD_IF(TRACE, "%s: hang up event!", __FUNCTION__);
-    hung_up_ = true;
-  } else {
-    ALOGW("%s: Unknown epoll events=%x", __FUNCTION__, events);
-  }
-
-  return {};
-}
-
-Status<void> BufferHubQueue::AddBuffer(
-    const std::shared_ptr<BufferHubBase>& buffer, size_t slot) {
-  ALOGD_IF(TRACE, "%s: buffer_id=%d slot=%zu", __FUNCTION__, buffer->id(),
-           slot);
-
-  if (is_full()) {
-    ALOGE("%s: queue is at maximum capacity: %zu", __FUNCTION__, capacity_);
-    return ErrorStatus(E2BIG);
-  }
-
-  if (buffers_[slot]) {
-    // Replace the buffer if the slot is occupied. This could happen when the
-    // producer side replaced the slot with a newly allocated buffer. Remove the
-    // buffer before setting up with the new one.
-    auto remove_status = RemoveBuffer(slot);
-    if (!remove_status)
-      return remove_status.error_status();
-  }
-
-  for (const auto& event_source : buffer->GetEventSources()) {
-    epoll_event event = {.events = event_source.event_mask | EPOLLET,
-                         .data = {.u64 = Stuff(buffer->event_fd(), slot)}};
-    const int ret =
-        epoll_fd_.Control(EPOLL_CTL_ADD, event_source.event_fd, &event);
-    if (ret < 0) {
-      ALOGE("%s: Failed to add buffer to epoll set: %s", __FUNCTION__,
-            strerror(-ret));
-      return ErrorStatus(-ret);
-    }
-  }
-
-  buffers_[slot] = buffer;
-  capacity_++;
-  return {};
-}
-
-Status<void> BufferHubQueue::RemoveBuffer(size_t slot) {
-  ALOGD_IF(TRACE, "%s: slot=%zu", __FUNCTION__, slot);
-
-  if (buffers_[slot]) {
-    for (const auto& event_source : buffers_[slot]->GetEventSources()) {
-      const int ret =
-          epoll_fd_.Control(EPOLL_CTL_DEL, event_source.event_fd, nullptr);
-      if (ret < 0) {
-        ALOGE("%s: Failed to remove buffer from epoll set: %s", __FUNCTION__,
-              strerror(-ret));
-        return ErrorStatus(-ret);
-      }
-    }
-
-    // Trigger OnBufferRemoved callback if registered.
-    if (on_buffer_removed_)
-      on_buffer_removed_(buffers_[slot]);
-
-    buffers_[slot] = nullptr;
-    capacity_--;
-  }
-
-  return {};
-}
-
-Status<void> BufferHubQueue::Enqueue(Entry entry) {
-  if (!is_full()) {
-    // Find and remove the enqueued buffer from unavailable_buffers_slot if
-    // exist.
-    auto enqueued_buffer_iter = std::find_if(
-        unavailable_buffers_slot_.begin(), unavailable_buffers_slot_.end(),
-        [&entry](size_t slot) -> bool { return slot == entry.slot; });
-    if (enqueued_buffer_iter != unavailable_buffers_slot_.end()) {
-      unavailable_buffers_slot_.erase(enqueued_buffer_iter);
-    }
-
-    available_buffers_.push(std::move(entry));
-
-    // Trigger OnBufferAvailable callback if registered.
-    if (on_buffer_available_)
-      on_buffer_available_();
-
-    return {};
-  } else {
-    ALOGE("%s: Buffer queue is full!", __FUNCTION__);
-    return ErrorStatus(E2BIG);
-  }
-}
-
-Status<std::shared_ptr<BufferHubBase>> BufferHubQueue::Dequeue(int timeout,
-                                                               size_t* slot) {
-  ALOGD_IF(TRACE, "%s: count=%zu, timeout=%d", __FUNCTION__, count(), timeout);
-
-  PDX_TRACE_FORMAT("%s|count=%zu|", __FUNCTION__, count());
-
-  if (count() == 0) {
-    if (!WaitForBuffers(timeout))
-      return ErrorStatus(ETIMEDOUT);
-  }
-
-  auto& entry = available_buffers_.top();
-  PDX_TRACE_FORMAT("buffer|buffer_id=%d;slot=%zu|", entry.buffer->id(),
-                   entry.slot);
-
-  std::shared_ptr<BufferHubBase> buffer = std::move(entry.buffer);
-  *slot = entry.slot;
-
-  available_buffers_.pop();
-  unavailable_buffers_slot_.push_back(*slot);
-
-  return {std::move(buffer)};
-}
-
-void BufferHubQueue::SetBufferAvailableCallback(
-    BufferAvailableCallback callback) {
-  on_buffer_available_ = callback;
-}
-
-void BufferHubQueue::SetBufferRemovedCallback(BufferRemovedCallback callback) {
-  on_buffer_removed_ = callback;
-}
-
-pdx::Status<void> BufferHubQueue::FreeAllBuffers() {
-  // Clear all available buffers.
-  while (!available_buffers_.empty())
-    available_buffers_.pop();
-
-  pdx::Status<void> last_error;  // No error.
-  // Clear all buffers this producer queue is tracking.
-  for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
-    if (buffers_[slot] != nullptr) {
-      auto status = RemoveBuffer(slot);
-      if (!status) {
-        ALOGE(
-            "ProducerQueue::FreeAllBuffers: Failed to remove buffer at "
-            "slot=%zu.",
-            slot);
-        last_error = status.error_status();
-      }
-    }
-  }
-
-  return last_error;
-}
-
-ProducerQueue::ProducerQueue(LocalChannelHandle handle)
-    : BASE(std::move(handle)) {
-  auto status = ImportQueue();
-  if (!status) {
-    ALOGE("ProducerQueue::ProducerQueue: Failed to import queue: %s",
-          status.GetErrorMessage().c_str());
-    Close(-status.error());
-  }
-}
-
-ProducerQueue::ProducerQueue(const ProducerQueueConfig& config,
-                             const UsagePolicy& usage)
-    : BASE(BufferHubRPC::kClientPath) {
-  auto status =
-      InvokeRemoteMethod<BufferHubRPC::CreateProducerQueue>(config, usage);
-  if (!status) {
-    ALOGE("ProducerQueue::ProducerQueue: Failed to create producer queue: %s",
-          status.GetErrorMessage().c_str());
-    Close(-status.error());
-    return;
-  }
-
-  SetupQueue(status.get());
-}
-
-Status<std::vector<size_t>> ProducerQueue::AllocateBuffers(
-    uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
-    uint64_t usage, size_t buffer_count) {
-  if (buffer_count == 0) {
-    return {std::vector<size_t>()};
-  }
-
-  if (capacity() + buffer_count > kMaxQueueCapacity) {
-    ALOGE(
-        "ProducerQueue::AllocateBuffers: queue is at capacity: %zu, cannot "
-        "allocate %zu more buffer(s).",
-        capacity(), buffer_count);
-    return ErrorStatus(E2BIG);
-  }
-
-  Status<std::vector<std::pair<LocalChannelHandle, size_t>>> status =
-      InvokeRemoteMethod<BufferHubRPC::ProducerQueueAllocateBuffers>(
-          width, height, layer_count, format, usage, buffer_count);
-  if (!status) {
-    ALOGE("ProducerQueue::AllocateBuffers: failed to allocate buffers: %s",
-          status.GetErrorMessage().c_str());
-    return status.error_status();
-  }
-
-  auto buffer_handle_slots = status.take();
-  LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != buffer_count,
-                      "BufferHubRPC::ProducerQueueAllocateBuffers should "
-                      "return %zu buffer handle(s), but returned %zu instead.",
-                      buffer_count, buffer_handle_slots.size());
-
-  std::vector<size_t> buffer_slots;
-  buffer_slots.reserve(buffer_count);
-
-  // Bookkeeping for each buffer.
-  for (auto& hs : buffer_handle_slots) {
-    auto& buffer_handle = hs.first;
-    size_t buffer_slot = hs.second;
-
-    // Note that import might (though very unlikely) fail. If so, buffer_handle
-    // will be closed and included in returned buffer_slots.
-    if (AddBuffer(ProducerBuffer::Import(std::move(buffer_handle)),
-                  buffer_slot)) {
-      ALOGD_IF(TRACE, "ProducerQueue::AllocateBuffers: new buffer at slot: %zu",
-               buffer_slot);
-      buffer_slots.push_back(buffer_slot);
-    }
-  }
-
-  if (buffer_slots.size() != buffer_count) {
-    // Error out if the count of imported buffer(s) is not correct.
-    ALOGE(
-        "ProducerQueue::AllocateBuffers: requested to import %zu "
-        "buffers, but actually imported %zu buffers.",
-        buffer_count, buffer_slots.size());
-    return ErrorStatus(ENOMEM);
-  }
-
-  return {std::move(buffer_slots)};
-}
-
-Status<size_t> ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
-                                             uint32_t layer_count,
-                                             uint32_t format, uint64_t usage) {
-  // We only allocate one buffer at a time.
-  constexpr size_t buffer_count = 1;
-  auto status =
-      AllocateBuffers(width, height, layer_count, format, usage, buffer_count);
-  if (!status) {
-    ALOGE("ProducerQueue::AllocateBuffer: Failed to allocate buffer: %s",
-          status.GetErrorMessage().c_str());
-    return status.error_status();
-  }
-
-  return {status.get()[0]};
-}
-
-Status<void> ProducerQueue::AddBuffer(
-    const std::shared_ptr<ProducerBuffer>& buffer, size_t slot) {
-  ALOGD_IF(TRACE, "ProducerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
-           id(), buffer->id(), slot);
-  // For producer buffer, we need to enqueue the newly added buffer
-  // immediately. Producer queue starts with all buffers in available state.
-  auto status = BufferHubQueue::AddBuffer(buffer, slot);
-  if (!status)
-    return status;
-
-  return BufferHubQueue::Enqueue({buffer, slot, 0ULL});
-}
-
-Status<size_t> ProducerQueue::InsertBuffer(
-    const std::shared_ptr<ProducerBuffer>& buffer) {
-  if (buffer == nullptr ||
-      !BufferHubDefs::isClientGained(buffer->buffer_state(),
-                                     buffer->client_state_mask())) {
-    ALOGE(
-        "ProducerQueue::InsertBuffer: Can only insert a buffer when it's in "
-        "gained state.");
-    return ErrorStatus(EINVAL);
-  }
-
-  auto status_or_slot =
-      InvokeRemoteMethod<BufferHubRPC::ProducerQueueInsertBuffer>(
-          buffer->cid());
-  if (!status_or_slot) {
-    ALOGE(
-        "ProducerQueue::InsertBuffer: Failed to insert producer buffer: "
-        "buffer_cid=%d, error: %s.",
-        buffer->cid(), status_or_slot.GetErrorMessage().c_str());
-    return status_or_slot.error_status();
-  }
-
-  size_t slot = status_or_slot.get();
-
-  // Note that we are calling AddBuffer() from the base class to explicitly
-  // avoid Enqueue() the ProducerBuffer.
-  auto status = BufferHubQueue::AddBuffer(buffer, slot);
-  if (!status) {
-    ALOGE("ProducerQueue::InsertBuffer: Failed to add buffer: %s.",
-          status.GetErrorMessage().c_str());
-    return status.error_status();
-  }
-  return {slot};
-}
-
-Status<void> ProducerQueue::RemoveBuffer(size_t slot) {
-  auto status =
-      InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot);
-  if (!status) {
-    ALOGE("%s: Failed to remove producer buffer: %s", __FUNCTION__,
-          status.GetErrorMessage().c_str());
-    return status.error_status();
-  }
-
-  return BufferHubQueue::RemoveBuffer(slot);
-}
-
-Status<std::shared_ptr<ProducerBuffer>> ProducerQueue::Dequeue(
-    int timeout, size_t* slot, LocalHandle* release_fence) {
-  DvrNativeBufferMetadata canonical_meta;
-  return Dequeue(timeout, slot, &canonical_meta, release_fence);
-}
-
-pdx::Status<std::shared_ptr<ProducerBuffer>> ProducerQueue::Dequeue(
-    int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
-    pdx::LocalHandle* release_fence, bool gain_posted_buffer) {
-  ATRACE_NAME("ProducerQueue::Dequeue");
-  if (slot == nullptr || out_meta == nullptr || release_fence == nullptr) {
-    ALOGE("%s: Invalid parameter.", __FUNCTION__);
-    return ErrorStatus(EINVAL);
-  }
-
-  std::shared_ptr<ProducerBuffer> buffer;
-  Status<std::shared_ptr<BufferHubBase>> dequeue_status =
-      BufferHubQueue::Dequeue(timeout, slot);
-  if (dequeue_status.ok()) {
-    buffer = std::static_pointer_cast<ProducerBuffer>(dequeue_status.take());
-  } else {
-    if (gain_posted_buffer) {
-      Status<std::shared_ptr<ProducerBuffer>> dequeue_unacquired_status =
-          ProducerQueue::DequeueUnacquiredBuffer(slot);
-      if (!dequeue_unacquired_status.ok()) {
-        ALOGE("%s: DequeueUnacquiredBuffer returned error: %d", __FUNCTION__,
-              dequeue_unacquired_status.error());
-        return dequeue_unacquired_status.error_status();
-      }
-      buffer = dequeue_unacquired_status.take();
-    } else {
-      return dequeue_status.error_status();
-    }
-  }
-  const int ret =
-      buffer->GainAsync(out_meta, release_fence, gain_posted_buffer);
-  if (ret < 0 && ret != -EALREADY)
-    return ErrorStatus(-ret);
-
-  return {std::move(buffer)};
-}
-
-Status<std::shared_ptr<ProducerBuffer>> ProducerQueue::DequeueUnacquiredBuffer(
-    size_t* slot) {
-  if (unavailable_buffers_slot_.size() < 1) {
-    ALOGE(
-        "%s: Failed to dequeue un-acquired buffer. All buffer(s) are in "
-        "acquired state if exist.",
-        __FUNCTION__);
-    return ErrorStatus(ENOMEM);
-  }
-
-  // Find the first buffer that is not in acquired state from
-  // unavailable_buffers_slot_.
-  for (auto iter = unavailable_buffers_slot_.begin();
-       iter != unavailable_buffers_slot_.end(); iter++) {
-    std::shared_ptr<ProducerBuffer> buffer = ProducerQueue::GetBuffer(*iter);
-    if (buffer == nullptr) {
-      ALOGE("%s failed. Buffer slot %d is  null.", __FUNCTION__,
-            static_cast<int>(*slot));
-      return ErrorStatus(EIO);
-    }
-    if (!BufferHubDefs::isAnyClientAcquired(buffer->buffer_state())) {
-      *slot = *iter;
-      unavailable_buffers_slot_.erase(iter);
-      unavailable_buffers_slot_.push_back(*slot);
-      ALOGD("%s: Producer queue dequeue unacquired buffer in slot %d",
-            __FUNCTION__, static_cast<int>(*slot));
-      return {std::move(buffer)};
-    }
-  }
-  ALOGE(
-      "%s: Failed to dequeue un-acquired buffer. No un-acquired buffer exist.",
-      __FUNCTION__);
-  return ErrorStatus(EBUSY);
-}
-
-pdx::Status<ProducerQueueParcelable> ProducerQueue::TakeAsParcelable() {
-  if (capacity() != 0) {
-    ALOGE(
-        "%s: producer queue can only be taken out as a parcelable when empty. "
-        "Current queue capacity: %zu",
-        __FUNCTION__, capacity());
-    return ErrorStatus(EINVAL);
-  }
-
-  std::unique_ptr<pdx::ClientChannel> channel = TakeChannel();
-  ProducerQueueParcelable queue_parcelable(channel->TakeChannelParcelable());
-
-  // Here the queue parcelable is returned and holds the underlying system
-  // resources backing the queue; while the original client channel of this
-  // producer queue is destroyed in place so that this client can no longer
-  // provide producer operations.
-  return {std::move(queue_parcelable)};
-}
-
-/*static */
-std::unique_ptr<ConsumerQueue> ConsumerQueue::Import(
-    LocalChannelHandle handle) {
-  return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(std::move(handle)));
-}
-
-ConsumerQueue::ConsumerQueue(LocalChannelHandle handle)
-    : BufferHubQueue(std::move(handle)) {
-  auto status = ImportQueue();
-  if (!status) {
-    ALOGE("%s: Failed to import queue: %s", __FUNCTION__,
-          status.GetErrorMessage().c_str());
-    Close(-status.error());
-  }
-
-  auto import_status = ImportBuffers();
-  if (import_status) {
-    ALOGI("%s: Imported %zu buffers.", __FUNCTION__, import_status.get());
-  } else {
-    ALOGE("%s: Failed to import buffers: %s", __FUNCTION__,
-          import_status.GetErrorMessage().c_str());
-  }
-}
-
-Status<size_t> ConsumerQueue::ImportBuffers() {
-  auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>();
-  if (!status) {
-    if (status.error() == EBADR) {
-      ALOGI("%s: Queue is silent, no buffers imported.", __FUNCTION__);
-      return {0};
-    } else {
-      ALOGE("%s: Failed to import consumer buffer: %s", __FUNCTION__,
-            status.GetErrorMessage().c_str());
-      return status.error_status();
-    }
-  }
-
-  int ret;
-  Status<void> last_error;
-  size_t imported_buffers_count = 0;
-
-  auto buffer_handle_slots = status.take();
-  for (auto& buffer_handle_slot : buffer_handle_slots) {
-    ALOGD_IF(TRACE, ": buffer_handle=%d", __FUNCTION__,
-             buffer_handle_slot.first.value());
-
-    std::unique_ptr<ConsumerBuffer> consumer_buffer =
-        ConsumerBuffer::Import(std::move(buffer_handle_slot.first));
-    if (!consumer_buffer) {
-      ALOGE("%s: Failed to import buffer: slot=%zu", __FUNCTION__,
-            buffer_handle_slot.second);
-      last_error = ErrorStatus(EPIPE);
-      continue;
-    }
-
-    auto add_status =
-        AddBuffer(std::move(consumer_buffer), buffer_handle_slot.second);
-    if (!add_status) {
-      ALOGE("%s: Failed to add buffer: %s", __FUNCTION__,
-            add_status.GetErrorMessage().c_str());
-      last_error = add_status;
-    } else {
-      imported_buffers_count++;
-    }
-  }
-
-  if (imported_buffers_count > 0)
-    return {imported_buffers_count};
-  else
-    return last_error.error_status();
-}
-
-Status<void> ConsumerQueue::AddBuffer(
-    const std::shared_ptr<ConsumerBuffer>& buffer, size_t slot) {
-  ALOGD_IF(TRACE, "%s: queue_id=%d buffer_id=%d slot=%zu", __FUNCTION__, id(),
-           buffer->id(), slot);
-  return BufferHubQueue::AddBuffer(buffer, slot);
-}
-
-Status<std::shared_ptr<ConsumerBuffer>> ConsumerQueue::Dequeue(
-    int timeout, size_t* slot, void* meta, size_t user_metadata_size,
-    LocalHandle* acquire_fence) {
-  if (user_metadata_size != user_metadata_size_) {
-    ALOGE(
-        "%s: Metadata size (%zu) for the dequeuing buffer does not match "
-        "metadata size (%zu) for the queue.",
-        __FUNCTION__, user_metadata_size, user_metadata_size_);
-    return ErrorStatus(EINVAL);
-  }
-
-  DvrNativeBufferMetadata canonical_meta;
-  auto status = Dequeue(timeout, slot, &canonical_meta, acquire_fence);
-  if (!status)
-    return status.error_status();
-
-  if (meta && user_metadata_size) {
-    void* metadata_src =
-        reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
-    if (metadata_src) {
-      memcpy(meta, metadata_src, user_metadata_size);
-    } else {
-      ALOGW("%s: no user-defined metadata.", __FUNCTION__);
-    }
-  }
-
-  return status;
-}
-
-Status<std::shared_ptr<ConsumerBuffer>> ConsumerQueue::Dequeue(
-    int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
-    pdx::LocalHandle* acquire_fence) {
-  ATRACE_NAME("ConsumerQueue::Dequeue");
-  if (slot == nullptr || out_meta == nullptr || acquire_fence == nullptr) {
-    ALOGE("%s: Invalid parameter.", __FUNCTION__);
-    return ErrorStatus(EINVAL);
-  }
-
-  auto status = BufferHubQueue::Dequeue(timeout, slot);
-  if (!status)
-    return status.error_status();
-
-  auto buffer = std::static_pointer_cast<ConsumerBuffer>(status.take());
-  const int ret = buffer->AcquireAsync(out_meta, acquire_fence);
-  if (ret < 0)
-    return ErrorStatus(-ret);
-
-  return {std::move(buffer)};
-}
-
-Status<void> ConsumerQueue::OnBufferAllocated() {
-  ALOGD_IF(TRACE, "%s: queue_id=%d", __FUNCTION__, id());
-
-  auto status = ImportBuffers();
-  if (!status) {
-    ALOGE("%s: Failed to import buffers: %s", __FUNCTION__,
-          status.GetErrorMessage().c_str());
-    return ErrorStatus(status.error());
-  } else if (status.get() == 0) {
-    ALOGW("%s: No new buffers allocated!", __FUNCTION__);
-    return ErrorStatus(ENOBUFS);
-  } else {
-    ALOGD_IF(TRACE, "%s: Imported %zu consumer buffers.", __FUNCTION__,
-             status.get());
-    return {};
-  }
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp
deleted file mode 100644
index f705749..0000000
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_parcelable.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#include "include/private/dvr/buffer_hub_queue_parcelable.h"
-
-#include <binder/Parcel.h>
-#include <pdx/default_transport/channel_parcelable.h>
-
-namespace android {
-namespace dvr {
-
-template <BufferHubQueueParcelableMagic Magic>
-bool BufferHubQueueParcelable<Magic>::IsValid() const {
-  return !!channel_parcelable_ && channel_parcelable_->IsValid();
-}
-
-template <BufferHubQueueParcelableMagic Magic>
-pdx::LocalChannelHandle BufferHubQueueParcelable<Magic>::TakeChannelHandle() {
-  if (!IsValid()) {
-    ALOGE(
-        "BufferHubQueueParcelable::TakeChannelHandle: Invalid channel parcel.");
-    return {};  // Returns an empty channel handle.
-  }
-
-  // Take channel handle out of the parcelable and reset the parcelable.
-  pdx::LocalChannelHandle handle = channel_parcelable_->TakeChannelHandle();
-  // Now channel_parcelable_ should already be invalid, but reset it to release
-  // the invalid parcelable object from unique_ptr.
-  channel_parcelable_ = nullptr;
-  return handle;
-}
-
-template <BufferHubQueueParcelableMagic Magic>
-status_t BufferHubQueueParcelable<Magic>::writeToParcel(Parcel* parcel) const {
-  if (!IsValid()) {
-    ALOGE("BufferHubQueueParcelable::writeToParcel: Invalid channel.");
-    return -EINVAL;
-  }
-
-  status_t res = parcel->writeUint32(Magic);
-  if (res != OK) {
-    ALOGE("BufferHubQueueParcelable::writeToParcel: Cannot write magic.");
-    return res;
-  }
-
-  return channel_parcelable_->writeToParcel(parcel);
-}
-
-template <BufferHubQueueParcelableMagic Magic>
-status_t BufferHubQueueParcelable<Magic>::readFromParcel(const Parcel* parcel) {
-  if (IsValid()) {
-    ALOGE(
-        "BufferHubQueueParcelable::readFromParcel: This parcelable object has "
-        "been initialized already.");
-    return -EINVAL;
-  }
-
-  uint32_t out_magic = 0;
-  status_t res = OK;
-
-  res = parcel->readUint32(&out_magic);
-  if (res != OK)
-    return res;
-
-  if (out_magic != Magic) {
-    ALOGE(
-        "BufferHubQueueParcelable::readFromParcel: Unexpected magic: 0x%x, "
-        "epxected: 0x%x",
-        out_magic, Magic);
-    return -EINVAL;
-  }
-
-  // (Re)Alocate channel parcelable object.
-  channel_parcelable_ =
-      std::make_unique<pdx::default_transport::ChannelParcelable>();
-  return channel_parcelable_->readFromParcel(parcel);
-}
-
-template class BufferHubQueueParcelable<
-    BufferHubQueueParcelableMagic::Producer>;
-template class BufferHubQueueParcelable<
-    BufferHubQueueParcelableMagic::Consumer>;
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
deleted file mode 100644
index 74b4b3d..0000000
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ /dev/null
@@ -1,476 +0,0 @@
-#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
-#define ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
-
-#include <ui/BufferQueueDefs.h>
-
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Weverything"
-#endif
-
-// The following headers are included without checking every warning.
-// TODO(b/72172820): Remove the workaround once we have enforced -Weverything
-// in these headers and their dependencies.
-#include <pdx/client.h>
-#include <pdx/status.h>
-#include <private/dvr/buffer_hub_queue_parcelable.h>
-#include <private/dvr/bufferhub_rpc.h>
-#include <private/dvr/consumer_buffer.h>
-#include <private/dvr/epoll_file_descriptor.h>
-#include <private/dvr/producer_buffer.h>
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-
-#include <memory>
-#include <queue>
-#include <vector>
-
-namespace android {
-namespace dvr {
-
-class ConsumerQueue;
-
-// |BufferHubQueue| manages a queue of |BufferHubBase|s. Buffers are
-// automatically re-requeued when released by the remote side.
-class BufferHubQueue : public pdx::Client {
- public:
-  using BufferAvailableCallback = std::function<void()>;
-  using BufferRemovedCallback =
-      std::function<void(const std::shared_ptr<BufferHubBase>&)>;
-
-  virtual ~BufferHubQueue() {}
-
-  // Creates a new consumer queue that is attached to the producer. Returns
-  // a new consumer queue client or nullptr on failure.
-  std::unique_ptr<ConsumerQueue> CreateConsumerQueue();
-
-  // Creates a new consumer queue that is attached to the producer. This queue
-  // sets each of its imported consumer buffers to the ignored state to avoid
-  // participation in lifecycle events.
-  std::unique_ptr<ConsumerQueue> CreateSilentConsumerQueue();
-
-  // Returns whether the buffer queue is in async mode.
-  bool is_async() const { return is_async_; }
-
-  // Returns the default buffer width of this buffer queue.
-  uint32_t default_width() const { return default_width_; }
-
-  // Returns the default buffer height of this buffer queue.
-  uint32_t default_height() const { return default_height_; }
-
-  // Returns the default buffer format of this buffer queue.
-  uint32_t default_format() const { return default_format_; }
-
-  // Creates a new consumer in handle form for immediate transport over RPC.
-  pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(
-      bool silent = false);
-
-  // Creates a new consumer in parcelable form for immediate transport over
-  // Binder.
-  pdx::Status<ConsumerQueueParcelable> CreateConsumerQueueParcelable(
-      bool silent = false);
-
-  // Returns the number of buffers avaiable for dequeue.
-  size_t count() const { return available_buffers_.size(); }
-
-  // Returns the total number of buffers that the queue is tracking.
-  size_t capacity() const { return capacity_; }
-
-  // Returns the size of metadata structure associated with this queue.
-  size_t metadata_size() const { return user_metadata_size_; }
-
-  // Returns whether the buffer queue is full.
-  bool is_full() const {
-    return available_buffers_.size() >= kMaxQueueCapacity;
-  }
-
-  // Returns whether the buffer queue is connected to bufferhubd.
-  bool is_connected() const { return !!GetChannel(); }
-
-  int GetBufferId(size_t slot) const {
-    return (slot < buffers_.size() && buffers_[slot]) ? buffers_[slot]->id()
-                                                      : -1;
-  }
-
-  std::shared_ptr<BufferHubBase> GetBuffer(size_t slot) const {
-    return buffers_[slot];
-  }
-
-  pdx::Status<int> GetEventMask(int events) {
-    if (auto* client_channel = GetChannel()) {
-      return client_channel->GetEventMask(events);
-    } else {
-      return pdx::ErrorStatus(EINVAL);
-    }
-  }
-
-  // Returns an fd that signals pending queue events using
-  // EPOLLIN/POLLIN/readible. Either HandleQueueEvents or WaitForBuffers may be
-  // called to handle pending queue events.
-  int queue_fd() const { return epoll_fd_.Get(); }
-
-  // Handles any pending events, returning available buffers to the queue and
-  // reaping disconnected buffers. Returns true if successful, false if an error
-  // occurred.
-  bool HandleQueueEvents() { return WaitForBuffers(0); }
-
-  // Set buffer event callbacks, which are std::function wrappers. The caller is
-  // responsible for ensuring the validity of these callbacks' callable targets.
-  void SetBufferAvailableCallback(BufferAvailableCallback callback);
-  void SetBufferRemovedCallback(BufferRemovedCallback callback);
-
-  // The queue tracks at most this many buffers.
-  static constexpr size_t kMaxQueueCapacity =
-      android::BufferQueueDefs::NUM_BUFFER_SLOTS;
-
-  static constexpr int kNoTimeOut = -1;
-
-  int id() const { return id_; }
-  bool hung_up() const { return hung_up_; }
-
- protected:
-  explicit BufferHubQueue(pdx::LocalChannelHandle channel);
-  explicit BufferHubQueue(const std::string& endpoint_path);
-
-  // Imports the queue parameters by querying BufferHub for the parameters for
-  // this channel.
-  pdx::Status<void> ImportQueue();
-
-  // Sets up the queue with the given parameters.
-  void SetupQueue(const QueueInfo& queue_info);
-
-  // Register a buffer for management by the queue. Used by subclasses to add a
-  // buffer to internal bookkeeping.
-  pdx::Status<void> AddBuffer(const std::shared_ptr<BufferHubBase>& buffer,
-                              size_t slot);
-
-  // Called by ProducerQueue::RemoveBuffer and ConsumerQueue::RemoveBuffer only
-  // to deregister a buffer for epoll and internal bookkeeping.
-  virtual pdx::Status<void> RemoveBuffer(size_t slot);
-
-  // Free all buffers that belongs to this queue. Can only be called from
-  // producer side.
-  virtual pdx::Status<void> FreeAllBuffers();
-
-  // Dequeue a buffer from the free queue, blocking until one is available. The
-  // timeout argument specifies the number of milliseconds that |Dequeue()| will
-  // block. Specifying a timeout of -1 causes Dequeue() to block indefinitely,
-  // while specifying a timeout equal to zero cause Dequeue() to return
-  // immediately, even if no buffers are available.
-  pdx::Status<std::shared_ptr<BufferHubBase>> Dequeue(int timeout,
-                                                      size_t* slot);
-
-  // Waits for buffers to become available and adds them to the available queue.
-  bool WaitForBuffers(int timeout);
-
-  pdx::Status<void> HandleBufferEvent(size_t slot, int event_fd,
-                                      int poll_events);
-  pdx::Status<void> HandleQueueEvent(int poll_events);
-
-  // Entry in the priority queue of available buffers that stores related
-  // per-buffer data.
-  struct Entry {
-    Entry() : slot(0) {}
-    Entry(const std::shared_ptr<BufferHubBase>& in_buffer, size_t in_slot,
-          uint64_t in_index)
-        : buffer(in_buffer), slot(in_slot), index(in_index) {}
-    Entry(const std::shared_ptr<BufferHubBase>& in_buffer,
-          std::unique_ptr<uint8_t[]> in_metadata, pdx::LocalHandle in_fence,
-          size_t in_slot)
-        : buffer(in_buffer),
-          metadata(std::move(in_metadata)),
-          fence(std::move(in_fence)),
-          slot(in_slot) {}
-    Entry(Entry&&) = default;
-    Entry& operator=(Entry&&) = default;
-
-    std::shared_ptr<BufferHubBase> buffer;
-    std::unique_ptr<uint8_t[]> metadata;
-    pdx::LocalHandle fence;
-    size_t slot;
-    uint64_t index;
-  };
-
-  struct EntryComparator {
-    bool operator()(const Entry& lhs, const Entry& rhs) {
-      return lhs.index > rhs.index;
-    }
-  };
-
-  // Enqueues a buffer to the available list (Gained for producer or Acquireed
-  // for consumer).
-  pdx::Status<void> Enqueue(Entry entry);
-
-  // Called when a buffer is allocated remotely.
-  virtual pdx::Status<void> OnBufferAllocated() { return {}; }
-
-  // Size of the metadata that buffers in this queue cary.
-  size_t user_metadata_size_{0};
-
-  // Buffers and related data that are available for dequeue.
-  std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
-      available_buffers_;
-
-  // Slot of the buffers that are not available for normal dequeue. For example,
-  // the slot of posted or acquired buffers in the perspective of a producer.
-  std::vector<size_t> unavailable_buffers_slot_;
-
- private:
-  void Initialize();
-
-  // Special epoll data field indicating that the epoll event refers to the
-  // queue.
-  static constexpr int64_t kEpollQueueEventIndex = -1;
-
-  static constexpr size_t kMaxEvents = 128;
-
-  // The u64 data field of an epoll event is interpreted as int64_t:
-  // When |index| >= 0 and |index| < kMaxQueueCapacity it refers to a specific
-  // element of |buffers_| as a direct index;
-  static bool is_buffer_event_index(int64_t index) {
-    return index >= 0 &&
-           index < static_cast<int64_t>(BufferHubQueue::kMaxQueueCapacity);
-  }
-
-  // When |index| == kEpollQueueEventIndex it refers to the queue itself.
-  static bool is_queue_event_index(int64_t index) {
-    return index == BufferHubQueue::kEpollQueueEventIndex;
-  }
-
-  // Whether the buffer queue is operating in Async mode.
-  // From GVR's perspective of view, this means a buffer can be acquired
-  // asynchronously by the compositor.
-  // From Android Surface's perspective of view, this is equivalent to
-  // IGraphicBufferProducer's async mode. When in async mode, a producer
-  // will never block even if consumer is running slow.
-  bool is_async_{false};
-
-  // Default buffer width that is set during ProducerQueue's creation.
-  uint32_t default_width_{1};
-
-  // Default buffer height that is set during ProducerQueue's creation.
-  uint32_t default_height_{1};
-
-  // Default buffer format that is set during ProducerQueue's creation.
-  uint32_t default_format_{1};  // PIXEL_FORMAT_RGBA_8888
-
-  // Tracks the buffers belonging to this queue. Buffers are stored according to
-  // "slot" in this vector. Each slot is a logical id of the buffer within this
-  // queue regardless of its queue position or presence in the ring buffer.
-  std::array<std::shared_ptr<BufferHubBase>, kMaxQueueCapacity> buffers_;
-
-  // Keeps track with how many buffers have been added into the queue.
-  size_t capacity_{0};
-
-  // Epoll fd used to manage buffer events.
-  EpollFileDescriptor epoll_fd_;
-
-  // Flag indicating that the other side hung up. For ProducerQueues this
-  // triggers when BufferHub dies or explicitly closes the queue channel. For
-  // ConsumerQueues this can either mean the same or that the ProducerQueue on
-  // the other end hung up.
-  bool hung_up_{false};
-
-  // Global id for the queue that is consistent across processes.
-  int id_{-1};
-
-  // Buffer event callbacks
-  BufferAvailableCallback on_buffer_available_;
-  BufferRemovedCallback on_buffer_removed_;
-
-  BufferHubQueue(const BufferHubQueue&) = delete;
-  void operator=(BufferHubQueue&) = delete;
-};
-
-class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> {
- public:
-  // Usage bits in |usage_set_mask| will be automatically masked on. Usage bits
-  // in |usage_clear_mask| will be automatically masked off. Note that
-  // |usage_set_mask| and |usage_clear_mask| may conflict with each other, but
-  // |usage_set_mask| takes precedence over |usage_clear_mask|. All buffer
-  // allocation through this producer queue shall not have any of the usage bits
-  // in |usage_deny_set_mask| set. Allocation calls violating this will be
-  // rejected. All buffer allocation through this producer queue must have all
-  // the usage bits in |usage_deny_clear_mask| set. Allocation calls violating
-  // this will be rejected. Note that |usage_deny_set_mask| and
-  // |usage_deny_clear_mask| shall not conflict with each other. Such
-  // configuration will be treated as invalid input on creation.
-  static std::unique_ptr<ProducerQueue> Create(
-      const ProducerQueueConfig& config, const UsagePolicy& usage) {
-    return BASE::Create(config, usage);
-  }
-
-  // Import a ProducerQueue from a channel handle.
-  static std::unique_ptr<ProducerQueue> Import(pdx::LocalChannelHandle handle) {
-    return BASE::Create(std::move(handle));
-  }
-
-  // Get a producer buffer. Note that the method doesn't check whether the
-  // buffer slot has a valid buffer that has been allocated already. When no
-  // buffer has been imported before it returns nullptr; otherwise it returns
-  // a shared pointer to a ProducerBuffer.
-  std::shared_ptr<ProducerBuffer> GetBuffer(size_t slot) const {
-    return std::static_pointer_cast<ProducerBuffer>(
-        BufferHubQueue::GetBuffer(slot));
-  }
-
-  // Batch allocate buffers. Once allocated, producer buffers are automatically
-  // enqueue'd into the ProducerQueue and available to use (i.e. in GAINED
-  // state). Upon success, returns a list of slots for each buffer allocated.
-  pdx::Status<std::vector<size_t>> AllocateBuffers(
-      uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
-      uint64_t usage, size_t buffer_count);
-
-  // Allocate producer buffer to populate the queue. Once allocated, a producer
-  // buffer is automatically enqueue'd into the ProducerQueue and available to
-  // use (i.e. in GAINED state). Upon success, returns the slot number for the
-  // buffer allocated.
-  pdx::Status<size_t> AllocateBuffer(uint32_t width, uint32_t height,
-                                     uint32_t layer_count, uint32_t format,
-                                     uint64_t usage);
-
-  // Add a producer buffer to populate the queue. Once added, a producer buffer
-  // is available to use (i.e. in GAINED state).
-  pdx::Status<void> AddBuffer(const std::shared_ptr<ProducerBuffer>& buffer,
-                              size_t slot);
-
-  // Inserts a ProducerBuffer into the queue. On success, the method returns the
-  // |slot| number where the new buffer gets inserted. Note that the buffer
-  // being inserted should be in Gain'ed state prior to the call and it's
-  // considered as already Dequeued when the function returns.
-  pdx::Status<size_t> InsertBuffer(
-      const std::shared_ptr<ProducerBuffer>& buffer);
-
-  // Remove producer buffer from the queue.
-  pdx::Status<void> RemoveBuffer(size_t slot) override;
-
-  // Free all buffers on this producer queue.
-  pdx::Status<void> FreeAllBuffers() override {
-    return BufferHubQueue::FreeAllBuffers();
-  }
-
-  // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
-  // and caller should call Post() once it's done writing to release the buffer
-  // to the consumer side.
-  // @return a buffer in gained state, which was originally in released state.
-  pdx::Status<std::shared_ptr<ProducerBuffer>> Dequeue(
-      int timeout, size_t* slot, pdx::LocalHandle* release_fence);
-
-  // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
-  // and caller should call Post() once it's done writing to release the buffer
-  // to the consumer side.
-  //
-  // @param timeout to dequeue a buffer.
-  // @param slot is the slot of the output ProducerBuffer.
-  // @param release_fence for gaining a buffer.
-  // @param out_meta metadata of the output buffer.
-  // @param gain_posted_buffer whether to gain posted buffer if no released
-  //     buffer is available to gain.
-  // @return a buffer in gained state, which was originally in released state if
-  //     gain_posted_buffer is false, or in posted/released state if
-  //     gain_posted_buffer is true.
-  // TODO(b/112007999): gain_posted_buffer true is only used to prevent
-  // libdvrtracking from starving when there are non-responding clients. This
-  // gain_posted_buffer param can be removed once libdvrtracking start to use
-  // the new AHardwareBuffer API.
-  pdx::Status<std::shared_ptr<ProducerBuffer>> Dequeue(
-      int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
-      pdx::LocalHandle* release_fence, bool gain_posted_buffer = false);
-
-  // Enqueues a producer buffer in the queue.
-  pdx::Status<void> Enqueue(const std::shared_ptr<ProducerBuffer>& buffer,
-                            size_t slot, uint64_t index) {
-    return BufferHubQueue::Enqueue({buffer, slot, index});
-  }
-
-  // Takes out the current producer queue as a binder parcelable object. Note
-  // that the queue must be empty to be exportable. After successful export, the
-  // producer queue client should no longer be used.
-  pdx::Status<ProducerQueueParcelable> TakeAsParcelable();
-
- private:
-  friend BASE;
-
-  // Constructors are automatically exposed through ProducerQueue::Create(...)
-  // static template methods inherited from ClientBase, which take the same
-  // arguments as the constructors.
-  explicit ProducerQueue(pdx::LocalChannelHandle handle);
-  ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage);
-
-  // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
-  // and caller should call Post() once it's done writing to release the buffer
-  // to the consumer side.
-  //
-  // @param slot the slot of the returned buffer.
-  // @return a buffer in gained state, which was originally in posted state or
-  //     released state.
-  pdx::Status<std::shared_ptr<ProducerBuffer>> DequeueUnacquiredBuffer(
-      size_t* slot);
-};
-
-class ConsumerQueue : public BufferHubQueue {
- public:
-  // Get a consumer buffer. Note that the method doesn't check whether the
-  // buffer slot has a valid buffer that has been imported already. When no
-  // buffer has been imported before it returns nullptr; otherwise returns a
-  // shared pointer to a ConsumerBuffer.
-  std::shared_ptr<ConsumerBuffer> GetBuffer(size_t slot) const {
-    return std::static_pointer_cast<ConsumerBuffer>(
-        BufferHubQueue::GetBuffer(slot));
-  }
-
-  // Import a ConsumerQueue from a channel handle. |ignore_on_import| controls
-  // whether or not buffers are set to be ignored when imported. This may be
-  // used to avoid participation in the buffer lifecycle by a consumer queue
-  // that is only used to spawn other consumer queues, such as in an
-  // intermediate service.
-  static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle);
-
-  // Import newly created buffers from the service side.
-  // Returns number of buffers successfully imported or an error.
-  pdx::Status<size_t> ImportBuffers();
-
-  // Dequeue a consumer buffer to read. The returned buffer in |Acquired|'ed
-  // mode, and caller should call Releasse() once it's done writing to release
-  // the buffer to the producer side. |meta| is passed along from BufferHub,
-  // The user of ProducerBuffer is responsible with making sure that the
-  // Dequeue() is done with the corect metadata type and size with those used
-  // when the buffer is orignally created.
-  template <typename Meta>
-  pdx::Status<std::shared_ptr<ConsumerBuffer>> Dequeue(
-      int timeout, size_t* slot, Meta* meta, pdx::LocalHandle* acquire_fence) {
-    return Dequeue(timeout, slot, meta, sizeof(*meta), acquire_fence);
-  }
-  pdx::Status<std::shared_ptr<ConsumerBuffer>> Dequeue(
-      int timeout, size_t* slot, pdx::LocalHandle* acquire_fence) {
-    return Dequeue(timeout, slot, nullptr, 0, acquire_fence);
-  }
-
-  pdx::Status<std::shared_ptr<ConsumerBuffer>> Dequeue(
-      int timeout, size_t* slot, void* meta, size_t user_metadata_size,
-      pdx::LocalHandle* acquire_fence);
-  pdx::Status<std::shared_ptr<ConsumerBuffer>> Dequeue(
-      int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
-      pdx::LocalHandle* acquire_fence);
-
- private:
-  friend BufferHubQueue;
-
-  explicit ConsumerQueue(pdx::LocalChannelHandle handle);
-
-  // Add a consumer buffer to populate the queue. Once added, a consumer buffer
-  // is NOT available to use until the producer side |Post| it. |WaitForBuffers|
-  // will catch the |Post| and |Acquire| the buffer to make it available for
-  // consumer.
-  pdx::Status<void> AddBuffer(const std::shared_ptr<ConsumerBuffer>& buffer,
-                              size_t slot);
-
-  pdx::Status<void> OnBufferAllocated() override;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
deleted file mode 100644
index 36ab5f6..0000000
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
-#define ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
-
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Weverything"
-#endif
-
-// The following headers are included without checking every warning.
-// TODO(b/72172820): Remove the workaround once we have enforced -Weverything
-// in these headers and their dependencies.
-#include <pdx/channel_parcelable.h>
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-
-namespace android {
-namespace dvr {
-
-enum BufferHubQueueParcelableMagic : uint32_t {
-  Producer = 0x62687170,  // 'bhqp'
-  Consumer = 0x62687163,  // 'bhqc'
-};
-
-template <BufferHubQueueParcelableMagic Magic>
-class BufferHubQueueParcelable : public Parcelable {
- public:
-  BufferHubQueueParcelable() = default;
-
-  BufferHubQueueParcelable(BufferHubQueueParcelable&& other) noexcept = default;
-  BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) noexcept {
-    channel_parcelable_ = std::move(other.channel_parcelable_);
-    return *this;
-  }
-
-  // Constructs an parcelable contains the channel parcelable.
-  explicit BufferHubQueueParcelable(
-      std::unique_ptr<pdx::ChannelParcelable> channel_parcelable)
-      : channel_parcelable_(std::move(channel_parcelable)) {}
-
-  BufferHubQueueParcelable(const BufferHubQueueParcelable&) = delete;
-  void operator=(const BufferHubQueueParcelable&) = delete;
-
-  bool IsValid() const;
-
-  // Returns a channel handle constructed from this parcelable object and takes
-  // the ownership of all resources from the parcelable object.
-  pdx::LocalChannelHandle TakeChannelHandle();
-
-  // Serializes the queue parcelable into the given parcel. Note that no system
-  // resources are getting duplicated, nor did the parcel takes ownership of the
-  // queue parcelable. Thus, the parcelable object must remain valid for the
-  // lifetime of the parcel.
-  status_t writeToParcel(Parcel* parcel) const override;
-
-  // Deserialize the queue parcelable from the given parcel. Note that system
-  // resources are duplicated from the parcel into the queue parcelable. Returns
-  // error if the targeting parcelable object is already valid.
-  status_t readFromParcel(const Parcel* parcel) override;
-
- private:
-  std::unique_ptr<pdx::ChannelParcelable> channel_parcelable_;
-};
-
-using ProducerQueueParcelable =
-    BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Producer>;
-using ConsumerQueueParcelable =
-    BufferHubQueueParcelable<BufferHubQueueParcelableMagic::Consumer>;
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_BUFFER_HUB_QUEUE_PARCELABLE_H_
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
deleted file mode 100644
index 2f14f7c..0000000
--- a/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
-#define ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
-
-#include <android-base/unique_fd.h>
-#include <log/log.h>
-#include <sys/epoll.h>
-
-namespace android {
-namespace dvr {
-
-class EpollFileDescriptor {
- public:
-  static const int CTL_ADD = EPOLL_CTL_ADD;
-  static const int CTL_MOD = EPOLL_CTL_MOD;
-  static const int CTL_DEL = EPOLL_CTL_DEL;
-
-  EpollFileDescriptor() : fd_(-1) {}
-
-  // Constructs an EpollFileDescriptor from an integer file descriptor and
-  // takes ownership.
-  explicit EpollFileDescriptor(int fd) : fd_(fd) {}
-
-  bool IsValid() const { return fd_.get() >= 0; }
-
-  int Create() {
-    if (IsValid()) {
-      ALOGW("epoll fd has already been created.");
-      return -EALREADY;
-    }
-
-    fd_.reset(epoll_create1(EPOLL_CLOEXEC));
-
-    if (fd_.get() < 0)
-      return -errno;
-    else
-      return 0;
-  }
-
-  int Control(int op, int target_fd, epoll_event* ev) {
-    if (epoll_ctl(fd_.get(), op, target_fd, ev) < 0)
-      return -errno;
-    else
-      return 0;
-  }
-
-  int Wait(epoll_event* events, int maxevents, int timeout) {
-    int ret = epoll_wait(fd_.get(), events, maxevents, timeout);
-
-    if (ret < 0)
-      return -errno;
-    else
-      return ret;
-  }
-
-  int Get() const { return fd_.get(); }
-
- private:
-  base::unique_fd fd_;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
deleted file mode 100644
index 33a0d75..0000000
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ /dev/null
@@ -1,66 +0,0 @@
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_native_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_native_license"],
-}
-
-header_libraries = [
-    "libdvr_headers",
-]
-
-shared_libraries = [
-    "libbase",
-    "libbinder",
-    "libbufferhubqueue",
-    "libcutils",
-    "libgui",
-    "liblog",
-    "libhardware",
-    "libui",
-    "libutils",
-    "libnativewindow",
-    "libpdx_default_transport",
-]
-
-static_libraries = [
-    "libchrome",
-    "libdvrcommon",
-    "libperformance",
-]
-
-cc_test {
-    srcs: ["buffer_hub_queue-test.cpp"],
-    header_libs: header_libraries,
-    static_libs: static_libraries,
-    shared_libs: shared_libraries,
-    cflags: [
-        "-DLOG_TAG=\"buffer_hub_queue-test\"",
-        "-DTRACE=0",
-        "-O0",
-        "-g",
-        "-Wall",
-        "-Werror",
-        "-Wno-error=sign-compare", // to fix later
-    ],
-    name: "buffer_hub_queue-test",
-}
-
-cc_test {
-    srcs: ["buffer_hub_queue_producer-test.cpp"],
-    header_libs: header_libraries,
-    static_libs: static_libraries,
-    shared_libs: shared_libraries,
-    cflags: [
-        "-DLOG_TAG=\"buffer_hub_queue_producer-test\"",
-        "-DTRACE=0",
-        "-O0",
-        "-g",
-        "-Wall",
-        "-Werror",
-    ],
-    name: "buffer_hub_queue_producer-test",
-}
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
deleted file mode 100644
index 6ae603b..0000000
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ /dev/null
@@ -1,1083 +0,0 @@
-#include <base/logging.h>
-#include <binder/Parcel.h>
-#include <dvr/dvr_api.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/consumer_buffer.h>
-#include <private/dvr/producer_buffer.h>
-
-#include <gtest/gtest.h>
-#include <poll.h>
-#include <sys/eventfd.h>
-
-#include <vector>
-
-// Enable/disable debug logging.
-#define TRACE 0
-
-namespace android {
-namespace dvr {
-
-using pdx::LocalChannelHandle;
-using pdx::LocalHandle;
-
-namespace {
-
-constexpr uint32_t kBufferWidth = 100;
-constexpr uint32_t kBufferHeight = 1;
-constexpr uint32_t kBufferLayerCount = 1;
-constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
-constexpr int kTimeoutMs = 100;
-constexpr int kNoTimeout = 0;
-
-class BufferHubQueueTest : public ::testing::Test {
- public:
-  bool CreateProducerQueue(const ProducerQueueConfig& config,
-                           const UsagePolicy& usage) {
-    producer_queue_ = ProducerQueue::Create(config, usage);
-    return producer_queue_ != nullptr;
-  }
-
-  bool CreateConsumerQueue() {
-    if (producer_queue_) {
-      consumer_queue_ = producer_queue_->CreateConsumerQueue();
-      return consumer_queue_ != nullptr;
-    } else {
-      return false;
-    }
-  }
-
-  bool CreateQueues(const ProducerQueueConfig& config,
-                    const UsagePolicy& usage) {
-    return CreateProducerQueue(config, usage) && CreateConsumerQueue();
-  }
-
-  void AllocateBuffer(size_t* slot_out = nullptr) {
-    // Create producer buffer.
-    auto status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
-                                                  kBufferLayerCount,
-                                                  kBufferFormat, kBufferUsage);
-
-    ASSERT_TRUE(status.ok());
-    size_t slot = status.take();
-    if (slot_out)
-      *slot_out = slot;
-  }
-
-  bool WaitAndHandleOnce(BufferHubQueue* queue, int timeout_ms) {
-    pollfd pfd{queue->queue_fd(), POLLIN, 0};
-    int ret;
-    do {
-      ret = poll(&pfd, 1, timeout_ms);
-    } while (ret == -1 && errno == EINTR);
-
-    if (ret < 0) {
-      ALOGW("Failed to poll queue %d's event fd, error: %s.", queue->id(),
-            strerror(errno));
-      return false;
-    } else if (ret == 0) {
-      return false;
-    }
-    return queue->HandleQueueEvents();
-  }
-
- protected:
-  ProducerQueueConfigBuilder config_builder_;
-  std::unique_ptr<ProducerQueue> producer_queue_;
-  std::unique_ptr<ConsumerQueue> consumer_queue_;
-};
-
-TEST_F(BufferHubQueueTest, TestDequeue) {
-  const int64_t nb_dequeue_times = 16;
-
-  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
-  // Allocate only one buffer.
-  AllocateBuffer();
-
-  // But dequeue multiple times.
-  for (int64_t i = 0; i < nb_dequeue_times; i++) {
-    size_t slot;
-    LocalHandle fence;
-    DvrNativeBufferMetadata mi, mo;
-
-    // Producer gains a buffer.
-    auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-    EXPECT_TRUE(p1_status.ok());
-    auto p1 = p1_status.take();
-    ASSERT_NE(p1, nullptr);
-
-    // Producer posts the buffer.
-    mi.index = i;
-    EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
-
-    // Consumer acquires a buffer.
-    auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-    EXPECT_TRUE(c1_status.ok()) << c1_status.GetErrorMessage();
-    auto c1 = c1_status.take();
-    ASSERT_NE(c1, nullptr);
-    EXPECT_EQ(mi.index, i);
-    EXPECT_EQ(mo.index, i);
-
-    // Consumer releases the buffer.
-    EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0);
-  }
-}
-
-TEST_F(BufferHubQueueTest,
-       TestDequeuePostedBufferIfNoAvailableReleasedBuffer_withConsumerBuffer) {
-  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
-  // Allocate 3 buffers to use.
-  const size_t test_queue_capacity = 3;
-  for (int64_t i = 0; i < test_queue_capacity; i++) {
-    AllocateBuffer();
-  }
-  EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity);
-
-  size_t producer_slot, consumer_slot;
-  LocalHandle fence;
-  DvrNativeBufferMetadata mi, mo;
-
-  // Producer posts 2 buffers and remember their posted sequence.
-  std::deque<size_t> posted_slots;
-  for (int64_t i = 0; i < 2; i++) {
-    auto p1_status =
-        producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
-    EXPECT_TRUE(p1_status.ok());
-    auto p1 = p1_status.take();
-    ASSERT_NE(p1, nullptr);
-
-    // Producer should not be gaining posted buffer when there are still
-    // available buffers to gain.
-    auto found_iter =
-        std::find(posted_slots.begin(), posted_slots.end(), producer_slot);
-    EXPECT_EQ(found_iter, posted_slots.end());
-    posted_slots.push_back(producer_slot);
-
-    // Producer posts the buffer.
-    mi.index = i;
-    EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
-  }
-
-  // Consumer acquires one buffer.
-  auto c1_status =
-      consumer_queue_->Dequeue(kTimeoutMs, &consumer_slot, &mo, &fence);
-  EXPECT_TRUE(c1_status.ok());
-  auto c1 = c1_status.take();
-  ASSERT_NE(c1, nullptr);
-  // Consumer should get the oldest posted buffer. No checks here.
-  // posted_slots[0] should be in acquired state now.
-  EXPECT_EQ(mo.index, 0);
-  // Consumer releases the buffer.
-  EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0);
-  // posted_slots[0] should be in released state now.
-
-  // Producer gain and post 2 buffers.
-  for (int64_t i = 0; i < 2; i++) {
-    auto p1_status =
-        producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
-    EXPECT_TRUE(p1_status.ok());
-    auto p1 = p1_status.take();
-    ASSERT_NE(p1, nullptr);
-
-    // The gained buffer should be the one in released state or the one haven't
-    // been use.
-    EXPECT_NE(posted_slots[1], producer_slot);
-
-    mi.index = i + 2;
-    EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
-  }
-
-  // Producer gains a buffer.
-  auto p1_status =
-      producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
-  EXPECT_TRUE(p1_status.ok());
-  auto p1 = p1_status.take();
-  ASSERT_NE(p1, nullptr);
-
-  // The gained buffer should be the oldest posted buffer.
-  EXPECT_EQ(posted_slots[1], producer_slot);
-
-  // Producer posts the buffer.
-  mi.index = 4;
-  EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
-}
-
-TEST_F(BufferHubQueueTest,
-       TestDequeuePostedBufferIfNoAvailableReleasedBuffer_noConsumerBuffer) {
-  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
-  // Allocate 4 buffers to use.
-  const size_t test_queue_capacity = 4;
-  for (int64_t i = 0; i < test_queue_capacity; i++) {
-    AllocateBuffer();
-  }
-  EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity);
-
-  // Post all allowed buffers and remember their posted sequence.
-  std::deque<size_t> posted_slots;
-  for (int64_t i = 0; i < test_queue_capacity; i++) {
-    size_t slot;
-    LocalHandle fence;
-    DvrNativeBufferMetadata mi, mo;
-
-    // Producer gains a buffer.
-    auto p1_status =
-        producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true);
-    EXPECT_TRUE(p1_status.ok());
-    auto p1 = p1_status.take();
-    ASSERT_NE(p1, nullptr);
-
-    // Producer should not be gaining posted buffer when there are still
-    // available buffers to gain.
-    auto found_iter = std::find(posted_slots.begin(), posted_slots.end(), slot);
-    EXPECT_EQ(found_iter, posted_slots.end());
-    posted_slots.push_back(slot);
-
-    // Producer posts the buffer.
-    mi.index = i;
-    EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
-  }
-
-  // Gain posted buffers in sequence.
-  const int64_t nb_dequeue_all_times = 2;
-  for (int j = 0; j < nb_dequeue_all_times; ++j) {
-    for (int i = 0; i < test_queue_capacity; ++i) {
-      size_t slot;
-      LocalHandle fence;
-      DvrNativeBufferMetadata mi, mo;
-
-      // Producer gains a buffer.
-      auto p1_status =
-          producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true);
-      EXPECT_TRUE(p1_status.ok());
-      auto p1 = p1_status.take();
-      ASSERT_NE(p1, nullptr);
-
-      // The gained buffer should be the oldest posted buffer.
-      EXPECT_EQ(posted_slots[i], slot);
-
-      // Producer posts the buffer.
-      mi.index = i + test_queue_capacity * (j + 1);
-      EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
-    }
-  }
-}
-
-TEST_F(BufferHubQueueTest, TestProducerConsumer) {
-  const size_t kBufferCount = 16;
-  size_t slot;
-  DvrNativeBufferMetadata mi, mo;
-  LocalHandle fence;
-
-  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
-  for (size_t i = 0; i < kBufferCount; i++) {
-    AllocateBuffer();
-
-    // Producer queue has all the available buffers on initialize.
-    ASSERT_EQ(producer_queue_->count(), i + 1);
-    ASSERT_EQ(producer_queue_->capacity(), i + 1);
-
-    // Consumer queue has no avaiable buffer on initialize.
-    ASSERT_EQ(consumer_queue_->count(), 0U);
-    // Consumer queue does not import buffers until a dequeue is issued.
-    ASSERT_EQ(consumer_queue_->capacity(), i);
-    // Dequeue returns timeout since no buffer is ready to consumer, but
-    // this implicitly triggers buffer import and bump up |capacity|.
-    auto status = consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence);
-    ASSERT_FALSE(status.ok());
-    ASSERT_EQ(ETIMEDOUT, status.error());
-    ASSERT_EQ(consumer_queue_->capacity(), i + 1);
-  }
-
-  // Use eventfd as a stand-in for a fence.
-  LocalHandle post_fence(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
-
-  for (size_t i = 0; i < kBufferCount; i++) {
-    // First time there is no buffer available to dequeue.
-    auto consumer_status =
-        consumer_queue_->Dequeue(kNoTimeout, &slot, &mo, &fence);
-    ASSERT_FALSE(consumer_status.ok());
-    ASSERT_EQ(consumer_status.error(), ETIMEDOUT);
-
-    // Make sure Producer buffer is POSTED so that it's ready to Accquire
-    // in the consumer's Dequeue() function.
-    auto producer_status =
-        producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-    ASSERT_TRUE(producer_status.ok());
-    auto producer = producer_status.take();
-    ASSERT_NE(nullptr, producer);
-
-    mi.index = static_cast<int64_t>(i);
-    ASSERT_EQ(producer->PostAsync(&mi, post_fence), 0);
-
-    // Second time the just the POSTED buffer should be dequeued.
-    consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-    ASSERT_TRUE(consumer_status.ok());
-    EXPECT_TRUE(fence.IsValid());
-
-    auto consumer = consumer_status.take();
-    ASSERT_NE(nullptr, consumer);
-    ASSERT_EQ(mi.index, mo.index);
-  }
-}
-
-TEST_F(BufferHubQueueTest, TestInsertBuffer) {
-  ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
-
-  consumer_queue_ = producer_queue_->CreateConsumerQueue();
-  ASSERT_TRUE(consumer_queue_ != nullptr);
-  EXPECT_EQ(producer_queue_->capacity(), 0);
-  EXPECT_EQ(consumer_queue_->capacity(), 0);
-
-  std::shared_ptr<ProducerBuffer> p1 = ProducerBuffer::Create(
-      kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage, 0);
-  ASSERT_TRUE(p1 != nullptr);
-  ASSERT_EQ(p1->GainAsync(), 0);
-
-  // Inserting a posted buffer will fail.
-  DvrNativeBufferMetadata meta;
-  EXPECT_EQ(p1->PostAsync(&meta, LocalHandle()), 0);
-  auto status_or_slot = producer_queue_->InsertBuffer(p1);
-  EXPECT_FALSE(status_or_slot.ok());
-  EXPECT_EQ(status_or_slot.error(), EINVAL);
-
-  // Inserting a gained buffer will succeed.
-  std::shared_ptr<ProducerBuffer> p2 = ProducerBuffer::Create(
-      kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage);
-  ASSERT_EQ(p2->GainAsync(), 0);
-  ASSERT_TRUE(p2 != nullptr);
-  status_or_slot = producer_queue_->InsertBuffer(p2);
-  EXPECT_TRUE(status_or_slot.ok()) << status_or_slot.GetErrorMessage();
-  // This is the first buffer inserted, should take slot 0.
-  size_t slot = status_or_slot.get();
-  EXPECT_EQ(slot, 0);
-
-  // Wait and expect the consumer to kick up the newly inserted buffer.
-  WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs);
-  EXPECT_EQ(consumer_queue_->capacity(), 1ULL);
-}
-
-TEST_F(BufferHubQueueTest, TestRemoveBuffer) {
-  ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
-  DvrNativeBufferMetadata mo;
-
-  // Allocate buffers.
-  const size_t kBufferCount = 4u;
-  for (size_t i = 0; i < kBufferCount; i++) {
-    AllocateBuffer();
-  }
-  ASSERT_EQ(kBufferCount, producer_queue_->count());
-  ASSERT_EQ(kBufferCount, producer_queue_->capacity());
-
-  consumer_queue_ = producer_queue_->CreateConsumerQueue();
-  ASSERT_NE(nullptr, consumer_queue_);
-
-  // Check that buffers are correctly imported on construction.
-  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
-  EXPECT_EQ(0u, consumer_queue_->count());
-
-  // Dequeue all the buffers and keep track of them in an array. This prevents
-  // the producer queue ring buffer ref counts from interfering with the tests.
-  struct Entry {
-    std::shared_ptr<ProducerBuffer> buffer;
-    LocalHandle fence;
-    size_t slot;
-  };
-  std::array<Entry, kBufferCount> buffers;
-
-  for (size_t i = 0; i < kBufferCount; i++) {
-    Entry* entry = &buffers[i];
-    auto producer_status =
-        producer_queue_->Dequeue(kTimeoutMs, &entry->slot, &mo, &entry->fence);
-    ASSERT_TRUE(producer_status.ok());
-    entry->buffer = producer_status.take();
-    ASSERT_NE(nullptr, entry->buffer);
-  }
-
-  // Remove a buffer and make sure both queues reflect the change.
-  ASSERT_TRUE(producer_queue_->RemoveBuffer(buffers[0].slot));
-  EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity());
-
-  // As long as the removed buffer is still alive the consumer queue won't know
-  // its gone.
-  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
-  EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
-  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
-
-  // Release the removed buffer.
-  buffers[0].buffer = nullptr;
-
-  // Now the consumer queue should know it's gone.
-  EXPECT_FALSE(WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs));
-  ASSERT_EQ(kBufferCount - 1, consumer_queue_->capacity());
-
-  // Allocate a new buffer. This should take the first empty slot.
-  size_t slot;
-  AllocateBuffer(&slot);
-  ALOGE_IF(TRACE, "ALLOCATE %zu", slot);
-  EXPECT_EQ(buffers[0].slot, slot);
-  EXPECT_EQ(kBufferCount, producer_queue_->capacity());
-
-  // The consumer queue should pick up the new buffer.
-  EXPECT_EQ(kBufferCount - 1, consumer_queue_->capacity());
-  EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
-  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
-
-  // Remove and allocate a buffer.
-  ASSERT_TRUE(producer_queue_->RemoveBuffer(buffers[1].slot));
-  EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity());
-  buffers[1].buffer = nullptr;
-
-  AllocateBuffer(&slot);
-  ALOGE_IF(TRACE, "ALLOCATE %zu", slot);
-  EXPECT_EQ(buffers[1].slot, slot);
-  EXPECT_EQ(kBufferCount, producer_queue_->capacity());
-
-  // The consumer queue should pick up the new buffer but the count shouldn't
-  // change.
-  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
-  EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
-  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
-
-  // Remove and allocate a buffer, but don't free the buffer right away.
-  ASSERT_TRUE(producer_queue_->RemoveBuffer(buffers[2].slot));
-  EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity());
-
-  AllocateBuffer(&slot);
-  ALOGE_IF(TRACE, "ALLOCATE %zu", slot);
-  EXPECT_EQ(buffers[2].slot, slot);
-  EXPECT_EQ(kBufferCount, producer_queue_->capacity());
-
-  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
-  EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
-  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
-
-  // Release the producer buffer to trigger a POLLHUP event for an already
-  // removed buffer.
-  buffers[2].buffer = nullptr;
-  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
-  EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
-  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
-}
-
-TEST_F(BufferHubQueueTest, TestMultipleConsumers) {
-  // ProducerConfigureBuilder doesn't set Metadata{size}, which means there
-  // is no metadata associated with this BufferQueue's buffer.
-  ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
-
-  // Allocate buffers.
-  const size_t kBufferCount = 4u;
-  for (size_t i = 0; i < kBufferCount; i++) {
-    AllocateBuffer();
-  }
-  ASSERT_EQ(kBufferCount, producer_queue_->count());
-
-  // Build a silent consumer queue to test multi-consumer queue features.
-  auto silent_queue = producer_queue_->CreateSilentConsumerQueue();
-  ASSERT_NE(nullptr, silent_queue);
-
-  // Check that silent queue doesn't import buffers on creation.
-  EXPECT_EQ(silent_queue->capacity(), 0U);
-
-  // Dequeue and post a buffer.
-  size_t slot;
-  LocalHandle fence;
-  DvrNativeBufferMetadata mi, mo;
-  auto producer_status =
-      producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-  EXPECT_TRUE(producer_status.ok());
-  auto producer_buffer = producer_status.take();
-  ASSERT_NE(producer_buffer, nullptr);
-  EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0);
-  // After post, check the number of remaining available buffers.
-  EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
-
-  // Currently we expect no buffer to be available prior to calling
-  // WaitForBuffers/HandleQueueEvents.
-  // TODO(eieio): Note this behavior may change in the future.
-  EXPECT_EQ(silent_queue->count(), 0U);
-  EXPECT_FALSE(silent_queue->HandleQueueEvents());
-  EXPECT_EQ(silent_queue->count(), 0U);
-
-  // Build a new consumer queue to test multi-consumer queue features.
-  consumer_queue_ = silent_queue->CreateConsumerQueue();
-  ASSERT_NE(consumer_queue_, nullptr);
-
-  // Check that buffers are correctly imported on construction.
-  EXPECT_EQ(consumer_queue_->capacity(), kBufferCount);
-  // Buffers are only imported, but their availability is not checked until
-  // first call to Dequeue().
-  EXPECT_EQ(consumer_queue_->count(), 0U);
-
-  // Reclaim released/ignored buffers.
-  EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
-
-  usleep(10000);
-  WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs);
-  EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
-
-  // Post another buffer.
-  producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-  EXPECT_TRUE(producer_status.ok());
-  producer_buffer = producer_status.take();
-  ASSERT_NE(producer_buffer, nullptr);
-  EXPECT_EQ(producer_buffer->PostAsync(&mi, {}), 0);
-
-  // Verify that the consumer queue receives it.
-  size_t consumer_queue_count = consumer_queue_->count();
-  WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs);
-  EXPECT_GT(consumer_queue_->count(), consumer_queue_count);
-
-  // Save the current consumer queue buffer count to compare after the dequeue.
-  consumer_queue_count = consumer_queue_->count();
-
-  // Dequeue and acquire/release (discard) buffers on the consumer end.
-  auto consumer_status =
-      consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-  EXPECT_TRUE(consumer_status.ok());
-  auto consumer_buffer = consumer_status.take();
-  ASSERT_NE(consumer_buffer, nullptr);
-  consumer_buffer->Discard();
-
-  // Buffer should be returned to the producer queue without being handled by
-  // the silent consumer queue.
-  EXPECT_LT(consumer_queue_->count(), consumer_queue_count);
-  EXPECT_EQ(producer_queue_->count(), kBufferCount - 2);
-
-  WaitAndHandleOnce(producer_queue_.get(), kTimeoutMs);
-  EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
-}
-
-struct TestUserMetadata {
-  char a;
-  int32_t b;
-  int64_t c;
-};
-
-constexpr uint64_t kUserMetadataSize =
-    static_cast<uint64_t>(sizeof(TestUserMetadata));
-
-TEST_F(BufferHubQueueTest, TestUserMetadata) {
-  ASSERT_TRUE(CreateQueues(
-      config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{}));
-
-  AllocateBuffer();
-
-  std::vector<TestUserMetadata> user_metadata_list = {
-      {'0', 0, 0}, {'1', 10, 3333}, {'@', 123, 1000000000}};
-
-  for (auto user_metadata : user_metadata_list) {
-    size_t slot;
-    LocalHandle fence;
-    DvrNativeBufferMetadata mi, mo;
-
-    auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-    EXPECT_TRUE(p1_status.ok());
-    auto p1 = p1_status.take();
-    ASSERT_NE(p1, nullptr);
-
-    // TODO(b/69469185): Test against metadata from consumer once we implement
-    // release metadata properly.
-    // EXPECT_EQ(mo.user_metadata_ptr, 0U);
-    // EXPECT_EQ(mo.user_metadata_size, 0U);
-
-    mi.user_metadata_size = kUserMetadataSize;
-    mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata);
-    EXPECT_EQ(p1->PostAsync(&mi, {}), 0);
-    auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-    EXPECT_TRUE(c1_status.ok()) << c1_status.GetErrorMessage();
-    auto c1 = c1_status.take();
-    ASSERT_NE(c1, nullptr);
-
-    EXPECT_EQ(mo.user_metadata_size, kUserMetadataSize);
-    auto out_user_metadata =
-        reinterpret_cast<TestUserMetadata*>(mo.user_metadata_ptr);
-    EXPECT_EQ(user_metadata.a, out_user_metadata->a);
-    EXPECT_EQ(user_metadata.b, out_user_metadata->b);
-    EXPECT_EQ(user_metadata.c, out_user_metadata->c);
-
-    // When release, empty metadata is also legit.
-    mi.user_metadata_size = 0U;
-    mi.user_metadata_ptr = 0U;
-    c1->ReleaseAsync(&mi, {});
-  }
-}
-
-TEST_F(BufferHubQueueTest, TestUserMetadataMismatch) {
-  ASSERT_TRUE(CreateQueues(
-      config_builder_.SetMetadata<TestUserMetadata>().Build(), UsagePolicy{}));
-
-  AllocateBuffer();
-
-  TestUserMetadata user_metadata;
-  size_t slot;
-  LocalHandle fence;
-  DvrNativeBufferMetadata mi, mo;
-  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-  EXPECT_TRUE(p1_status.ok());
-  auto p1 = p1_status.take();
-  ASSERT_NE(p1, nullptr);
-
-  // Post with mismatched user metadata size will fail. But the producer buffer
-  // itself should stay untouched.
-  mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata);
-  mi.user_metadata_size = kUserMetadataSize + 1;
-  EXPECT_EQ(p1->PostAsync(&mi, {}), -E2BIG);
-  // Post with the exact same user metdata size can success.
-  mi.user_metadata_ptr = reinterpret_cast<uint64_t>(&user_metadata);
-  mi.user_metadata_size = kUserMetadataSize;
-  EXPECT_EQ(p1->PostAsync(&mi, {}), 0);
-}
-
-TEST_F(BufferHubQueueTest, TestEnqueue) {
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
-                           UsagePolicy{}));
-  AllocateBuffer();
-
-  size_t slot;
-  LocalHandle fence;
-  DvrNativeBufferMetadata mo;
-  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-  ASSERT_TRUE(p1_status.ok());
-  auto p1 = p1_status.take();
-  ASSERT_NE(nullptr, p1);
-
-  producer_queue_->Enqueue(p1, slot, 0ULL);
-  auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-  ASSERT_FALSE(c1_status.ok());
-}
-
-TEST_F(BufferHubQueueTest, TestAllocateBuffer) {
-  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
-  size_t ps1;
-  AllocateBuffer();
-  LocalHandle fence;
-  DvrNativeBufferMetadata mi, mo;
-  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &ps1, &mo, &fence);
-  ASSERT_TRUE(p1_status.ok());
-  auto p1 = p1_status.take();
-  ASSERT_NE(p1, nullptr);
-
-  // producer queue is exhausted
-  size_t ps2;
-  auto p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence);
-  ASSERT_FALSE(p2_status.ok());
-  ASSERT_EQ(ETIMEDOUT, p2_status.error());
-
-  // dynamically add buffer.
-  AllocateBuffer();
-  ASSERT_EQ(producer_queue_->count(), 1U);
-  ASSERT_EQ(producer_queue_->capacity(), 2U);
-
-  // now we can dequeue again
-  p2_status = producer_queue_->Dequeue(kTimeoutMs, &ps2, &mo, &fence);
-  ASSERT_TRUE(p2_status.ok());
-  auto p2 = p2_status.take();
-  ASSERT_NE(p2, nullptr);
-  ASSERT_EQ(producer_queue_->count(), 0U);
-  // p1 and p2 should have different slot number
-  ASSERT_NE(ps1, ps2);
-
-  // Consumer queue does not import buffers until |Dequeue| or |ImportBuffers|
-  // are called. So far consumer_queue_ should be empty.
-  ASSERT_EQ(consumer_queue_->count(), 0U);
-
-  int64_t seq = 1;
-  mi.index = seq;
-  ASSERT_EQ(p1->PostAsync(&mi, {}), 0);
-
-  size_t cs1, cs2;
-  auto c1_status = consumer_queue_->Dequeue(kTimeoutMs, &cs1, &mo, &fence);
-  ASSERT_TRUE(c1_status.ok()) << c1_status.GetErrorMessage();
-  auto c1 = c1_status.take();
-  ASSERT_NE(c1, nullptr);
-  ASSERT_EQ(consumer_queue_->count(), 0U);
-  ASSERT_EQ(consumer_queue_->capacity(), 2U);
-  ASSERT_EQ(cs1, ps1);
-
-  ASSERT_EQ(p2->PostAsync(&mi, {}), 0);
-  auto c2_status = consumer_queue_->Dequeue(kTimeoutMs, &cs2, &mo, &fence);
-  ASSERT_TRUE(c2_status.ok());
-  auto c2 = c2_status.take();
-  ASSERT_NE(c2, nullptr);
-  ASSERT_EQ(cs2, ps2);
-}
-
-TEST_F(BufferHubQueueTest, TestAllocateTwoBuffers) {
-  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-  ASSERT_EQ(producer_queue_->capacity(), 0);
-  auto status = producer_queue_->AllocateBuffers(
-      kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-      kBufferUsage, /*buffer_count=*/2);
-  ASSERT_TRUE(status.ok());
-  std::vector<size_t> buffer_slots = status.take();
-  ASSERT_EQ(buffer_slots.size(), 2);
-  ASSERT_EQ(producer_queue_->capacity(), 2);
-}
-
-TEST_F(BufferHubQueueTest, TestAllocateZeroBuffers) {
-  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-  ASSERT_EQ(producer_queue_->capacity(), 0);
-  auto status = producer_queue_->AllocateBuffers(
-      kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-      kBufferUsage, /*buffer_count=*/0);
-  ASSERT_TRUE(status.ok());
-  std::vector<size_t> buffer_slots = status.take();
-  ASSERT_EQ(buffer_slots.size(), 0);
-  ASSERT_EQ(producer_queue_->capacity(), 0);
-}
-
-TEST_F(BufferHubQueueTest, TestUsageSetMask) {
-  const uint32_t set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  ASSERT_TRUE(
-      CreateQueues(config_builder_.Build(), UsagePolicy{set_mask, 0, 0, 0}));
-
-  // When allocation, leave out |set_mask| from usage bits on purpose.
-  auto status = producer_queue_->AllocateBuffer(
-      kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-      kBufferUsage & ~set_mask);
-  ASSERT_TRUE(status.ok());
-
-  LocalHandle fence;
-  size_t slot;
-  DvrNativeBufferMetadata mo;
-  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-  ASSERT_TRUE(p1_status.ok());
-  auto p1 = p1_status.take();
-  ASSERT_EQ(p1->usage() & set_mask, set_mask);
-}
-
-TEST_F(BufferHubQueueTest, TestUsageClearMask) {
-  const uint32_t clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  ASSERT_TRUE(
-      CreateQueues(config_builder_.Build(), UsagePolicy{0, clear_mask, 0, 0}));
-
-  // When allocation, add |clear_mask| into usage bits on purpose.
-  auto status = producer_queue_->AllocateBuffer(
-      kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-      kBufferUsage | clear_mask);
-  ASSERT_TRUE(status.ok());
-
-  LocalHandle fence;
-  size_t slot;
-  DvrNativeBufferMetadata mo;
-  auto p1_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-  ASSERT_TRUE(p1_status.ok());
-  auto p1 = p1_status.take();
-  ASSERT_EQ(p1->usage() & clear_mask, 0U);
-}
-
-TEST_F(BufferHubQueueTest, TestUsageDenySetMask) {
-  const uint32_t deny_set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
-                           UsagePolicy{0, 0, deny_set_mask, 0}));
-
-  // Now that |deny_set_mask| is illegal, allocation without those bits should
-  // be able to succeed.
-  auto status = producer_queue_->AllocateBuffer(
-      kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-      kBufferUsage & ~deny_set_mask);
-  ASSERT_TRUE(status.ok());
-
-  // While allocation with those bits should fail.
-  status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
-                                           kBufferLayerCount, kBufferFormat,
-                                           kBufferUsage | deny_set_mask);
-  ASSERT_FALSE(status.ok());
-  ASSERT_EQ(EINVAL, status.error());
-}
-
-TEST_F(BufferHubQueueTest, TestUsageDenyClearMask) {
-  const uint32_t deny_clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
-                           UsagePolicy{0, 0, 0, deny_clear_mask}));
-
-  // Now that clearing |deny_clear_mask| is illegal (i.e. setting these bits are
-  // mandatory), allocation with those bits should be able to succeed.
-  auto status = producer_queue_->AllocateBuffer(
-      kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-      kBufferUsage | deny_clear_mask);
-  ASSERT_TRUE(status.ok());
-
-  // While allocation without those bits should fail.
-  status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
-                                           kBufferLayerCount, kBufferFormat,
-                                           kBufferUsage & ~deny_clear_mask);
-  ASSERT_FALSE(status.ok());
-  ASSERT_EQ(EINVAL, status.error());
-}
-
-TEST_F(BufferHubQueueTest, TestQueueInfo) {
-  static const bool kIsAsync = true;
-  ASSERT_TRUE(CreateQueues(config_builder_.SetIsAsync(kIsAsync)
-                               .SetDefaultWidth(kBufferWidth)
-                               .SetDefaultHeight(kBufferHeight)
-                               .SetDefaultFormat(kBufferFormat)
-                               .Build(),
-                           UsagePolicy{}));
-
-  EXPECT_EQ(producer_queue_->default_width(), kBufferWidth);
-  EXPECT_EQ(producer_queue_->default_height(), kBufferHeight);
-  EXPECT_EQ(producer_queue_->default_format(), kBufferFormat);
-  EXPECT_EQ(producer_queue_->is_async(), kIsAsync);
-
-  EXPECT_EQ(consumer_queue_->default_width(), kBufferWidth);
-  EXPECT_EQ(consumer_queue_->default_height(), kBufferHeight);
-  EXPECT_EQ(consumer_queue_->default_format(), kBufferFormat);
-  EXPECT_EQ(consumer_queue_->is_async(), kIsAsync);
-}
-
-TEST_F(BufferHubQueueTest, TestFreeAllBuffers) {
-  constexpr size_t kBufferCount = 2;
-
-#define CHECK_NO_BUFFER_THEN_ALLOCATE(num_buffers)  \
-  EXPECT_EQ(consumer_queue_->count(), 0U);          \
-  EXPECT_EQ(consumer_queue_->capacity(), 0U);       \
-  EXPECT_EQ(producer_queue_->count(), 0U);          \
-  EXPECT_EQ(producer_queue_->capacity(), 0U);       \
-  for (size_t i = 0; i < num_buffers; i++) {        \
-    AllocateBuffer();                               \
-  }                                                 \
-  EXPECT_EQ(producer_queue_->count(), num_buffers); \
-  EXPECT_EQ(producer_queue_->capacity(), num_buffers);
-
-  size_t slot;
-  LocalHandle fence;
-  pdx::Status<void> status;
-  pdx::Status<std::shared_ptr<ConsumerBuffer>> consumer_status;
-  pdx::Status<std::shared_ptr<ProducerBuffer>> producer_status;
-  std::shared_ptr<ConsumerBuffer> consumer_buffer;
-  std::shared_ptr<ProducerBuffer> producer_buffer;
-  DvrNativeBufferMetadata mi, mo;
-
-  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
-  // Free all buffers when buffers are avaible for dequeue.
-  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
-  status = producer_queue_->FreeAllBuffers();
-  EXPECT_TRUE(status.ok());
-
-  // Free all buffers when one buffer is dequeued.
-  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
-  producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-  ASSERT_TRUE(producer_status.ok());
-  status = producer_queue_->FreeAllBuffers();
-  EXPECT_TRUE(status.ok());
-
-  // Free all buffers when all buffers are dequeued.
-  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
-  for (size_t i = 0; i < kBufferCount; i++) {
-    producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-    ASSERT_TRUE(producer_status.ok());
-  }
-  status = producer_queue_->FreeAllBuffers();
-  EXPECT_TRUE(status.ok());
-
-  // Free all buffers when one buffer is posted.
-  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
-  producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-  ASSERT_TRUE(producer_status.ok());
-  producer_buffer = producer_status.take();
-  ASSERT_NE(nullptr, producer_buffer);
-  ASSERT_EQ(0, producer_buffer->PostAsync(&mi, fence));
-  status = producer_queue_->FreeAllBuffers();
-  EXPECT_TRUE(status.ok());
-
-  // Free all buffers when all buffers are posted.
-  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
-  for (size_t i = 0; i < kBufferCount; i++) {
-    producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-    ASSERT_TRUE(producer_status.ok());
-    producer_buffer = producer_status.take();
-    ASSERT_NE(producer_buffer, nullptr);
-    ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0);
-  }
-  status = producer_queue_->FreeAllBuffers();
-  EXPECT_TRUE(status.ok());
-
-  // Free all buffers when all buffers are acquired.
-  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
-  for (size_t i = 0; i < kBufferCount; i++) {
-    producer_status = producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-    ASSERT_TRUE(producer_status.ok());
-    producer_buffer = producer_status.take();
-    ASSERT_NE(producer_buffer, nullptr);
-    ASSERT_EQ(producer_buffer->PostAsync(&mi, fence), 0);
-    consumer_status = consumer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence);
-    ASSERT_TRUE(consumer_status.ok()) << consumer_status.GetErrorMessage();
-  }
-
-  status = producer_queue_->FreeAllBuffers();
-  EXPECT_TRUE(status.ok());
-
-  // In addition to FreeAllBuffers() from the queue, it is also required to
-  // delete all references to the ProducerBuffer (i.e. the PDX client).
-  producer_buffer = nullptr;
-
-  // Crank consumer queue events to pickup EPOLLHUP events on the queue.
-  consumer_queue_->HandleQueueEvents();
-
-  // One last check.
-  CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
-
-#undef CHECK_NO_BUFFER_THEN_ALLOCATE
-}
-
-TEST_F(BufferHubQueueTest, TestProducerToParcelableNotEmpty) {
-  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
-                           UsagePolicy{}));
-
-  // Allocate only one buffer.
-  AllocateBuffer();
-
-  // Export should fail as the queue is not empty.
-  auto status = producer_queue_->TakeAsParcelable();
-  EXPECT_FALSE(status.ok());
-}
-
-TEST_F(BufferHubQueueTest, TestProducerExportToParcelable) {
-  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
-
-  auto s1 = producer_queue_->TakeAsParcelable();
-  EXPECT_TRUE(s1.ok());
-
-  ProducerQueueParcelable output_parcelable = s1.take();
-  EXPECT_TRUE(output_parcelable.IsValid());
-
-  Parcel parcel;
-  status_t res;
-  res = output_parcelable.writeToParcel(&parcel);
-  EXPECT_EQ(res, OK);
-
-  // After written into parcelable, the output_parcelable is still valid has
-  // keeps the producer channel alive.
-  EXPECT_TRUE(output_parcelable.IsValid());
-
-  // Creating producer buffer should fail.
-  auto s2 = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
-                                            kBufferLayerCount, kBufferFormat,
-                                            kBufferUsage);
-  ASSERT_FALSE(s2.ok());
-
-  // Reset the data position so that we can read back from the same parcel
-  // without doing actually Binder IPC.
-  parcel.setDataPosition(0);
-  producer_queue_ = nullptr;
-
-  // Recreate the producer queue from the parcel.
-  ProducerQueueParcelable input_parcelable;
-  EXPECT_FALSE(input_parcelable.IsValid());
-
-  res = input_parcelable.readFromParcel(&parcel);
-  EXPECT_EQ(res, OK);
-  EXPECT_TRUE(input_parcelable.IsValid());
-
-  EXPECT_EQ(producer_queue_, nullptr);
-  producer_queue_ = ProducerQueue::Import(input_parcelable.TakeChannelHandle());
-  EXPECT_FALSE(input_parcelable.IsValid());
-  ASSERT_NE(producer_queue_, nullptr);
-
-  // Newly created queue from the parcel can allocate buffer, post buffer to
-  // consumer.
-  EXPECT_NO_FATAL_FAILURE(AllocateBuffer());
-  EXPECT_EQ(producer_queue_->count(), 1U);
-  EXPECT_EQ(producer_queue_->capacity(), 1U);
-
-  size_t slot;
-  DvrNativeBufferMetadata producer_meta;
-  DvrNativeBufferMetadata consumer_meta;
-  LocalHandle fence;
-  auto s3 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence);
-  EXPECT_TRUE(s3.ok());
-
-  std::shared_ptr<ProducerBuffer> p1 = s3.take();
-  ASSERT_NE(p1, nullptr);
-
-  producer_meta.timestamp = 42;
-  EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0);
-
-  // Make sure the buffer can be dequeued from consumer side.
-  auto s4 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence);
-  EXPECT_TRUE(s4.ok()) << s4.GetErrorMessage();
-  EXPECT_EQ(consumer_queue_->capacity(), 1U);
-
-  auto consumer = s4.take();
-  ASSERT_NE(consumer, nullptr);
-  EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp);
-}
-
-TEST_F(BufferHubQueueTest, TestCreateConsumerParcelable) {
-  ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
-
-  auto s1 = producer_queue_->CreateConsumerQueueParcelable();
-  EXPECT_TRUE(s1.ok());
-  ConsumerQueueParcelable output_parcelable = s1.take();
-  EXPECT_TRUE(output_parcelable.IsValid());
-
-  // Write to a Parcel new object.
-  Parcel parcel;
-  status_t res;
-  res = output_parcelable.writeToParcel(&parcel);
-
-  // Reset the data position so that we can read back from the same parcel
-  // without doing actually Binder IPC.
-  parcel.setDataPosition(0);
-
-  // No consumer queue created yet.
-  EXPECT_EQ(consumer_queue_, nullptr);
-
-  // If the parcel contains a consumer queue, read into a
-  // ProducerQueueParcelable should fail.
-  ProducerQueueParcelable wrongly_typed_parcelable;
-  EXPECT_FALSE(wrongly_typed_parcelable.IsValid());
-  res = wrongly_typed_parcelable.readFromParcel(&parcel);
-  EXPECT_EQ(res, -EINVAL);
-  parcel.setDataPosition(0);
-
-  // Create the consumer queue from the parcel.
-  ConsumerQueueParcelable input_parcelable;
-  EXPECT_FALSE(input_parcelable.IsValid());
-
-  res = input_parcelable.readFromParcel(&parcel);
-  EXPECT_EQ(res, OK);
-  EXPECT_TRUE(input_parcelable.IsValid());
-
-  consumer_queue_ = ConsumerQueue::Import(input_parcelable.TakeChannelHandle());
-  EXPECT_FALSE(input_parcelable.IsValid());
-  ASSERT_NE(consumer_queue_, nullptr);
-
-  EXPECT_NO_FATAL_FAILURE(AllocateBuffer());
-  EXPECT_EQ(producer_queue_->count(), 1U);
-  EXPECT_EQ(producer_queue_->capacity(), 1U);
-
-  size_t slot;
-  DvrNativeBufferMetadata producer_meta;
-  DvrNativeBufferMetadata consumer_meta;
-  LocalHandle fence;
-  auto s2 = producer_queue_->Dequeue(0, &slot, &producer_meta, &fence);
-  EXPECT_TRUE(s2.ok());
-
-  std::shared_ptr<ProducerBuffer> p1 = s2.take();
-  ASSERT_NE(p1, nullptr);
-
-  producer_meta.timestamp = 42;
-  EXPECT_EQ(p1->PostAsync(&producer_meta, LocalHandle()), 0);
-
-  // Make sure the buffer can be dequeued from consumer side.
-  auto s3 = consumer_queue_->Dequeue(kTimeoutMs, &slot, &consumer_meta, &fence);
-  EXPECT_TRUE(s3.ok()) << s3.GetErrorMessage();
-  EXPECT_EQ(consumer_queue_->capacity(), 1U);
-
-  auto consumer = s3.take();
-  ASSERT_NE(consumer, nullptr);
-  EXPECT_EQ(producer_meta.timestamp, consumer_meta.timestamp);
-}
-
-}  // namespace
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
deleted file mode 100644
index fab1097..0000000
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
+++ /dev/null
@@ -1,603 +0,0 @@
-#include <base/logging.h>
-#include <gui/BufferHubProducer.h>
-#include <gui/IProducerListener.h>
-#include <gui/Surface.h>
-#include <pdx/default_transport/channel_parcelable.h>
-
-#include <gtest/gtest.h>
-
-namespace android {
-namespace dvr {
-
-using pdx::LocalHandle;
-
-namespace {
-
-// Default dimensions before setDefaultBufferSize is called by the consumer.
-constexpr uint32_t kDefaultWidth = 1;
-constexpr uint32_t kDefaultHeight = 1;
-
-// Default format before setDefaultBufferFormat is called by the consumer.
-constexpr PixelFormat kDefaultFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-constexpr int kDefaultConsumerUsageBits = 0;
-
-// Default transform hint before setTransformHint is called by the consumer.
-constexpr uint32_t kDefaultTransformHint = 0;
-
-constexpr int kTestApi = NATIVE_WINDOW_API_CPU;
-constexpr int kTestApiOther = NATIVE_WINDOW_API_EGL;
-constexpr int kTestApiInvalid = 0xDEADBEEF;
-constexpr int kTestProducerUsageBits = 0;
-constexpr bool kTestControlledByApp = true;
-
-// Builder pattern to slightly vary *almost* correct input
-// -- avoids copying and pasting
-struct QueueBufferInputBuilder {
-  IGraphicBufferProducer::QueueBufferInput build() {
-    return IGraphicBufferProducer::QueueBufferInput(
-        mTimestamp, mIsAutoTimestamp, mDataSpace, mCrop, mScalingMode,
-        mTransform, mFence);
-  }
-
-  QueueBufferInputBuilder& setTimestamp(int64_t timestamp) {
-    this->mTimestamp = timestamp;
-    return *this;
-  }
-
-  QueueBufferInputBuilder& setIsAutoTimestamp(bool isAutoTimestamp) {
-    this->mIsAutoTimestamp = isAutoTimestamp;
-    return *this;
-  }
-
-  QueueBufferInputBuilder& setDataSpace(android_dataspace dataSpace) {
-    this->mDataSpace = dataSpace;
-    return *this;
-  }
-
-  QueueBufferInputBuilder& setCrop(Rect crop) {
-    this->mCrop = crop;
-    return *this;
-  }
-
-  QueueBufferInputBuilder& setScalingMode(int scalingMode) {
-    this->mScalingMode = scalingMode;
-    return *this;
-  }
-
-  QueueBufferInputBuilder& setTransform(uint32_t transform) {
-    this->mTransform = transform;
-    return *this;
-  }
-
-  QueueBufferInputBuilder& setFence(sp<Fence> fence) {
-    this->mFence = fence;
-    return *this;
-  }
-
- private:
-  int64_t mTimestamp{1384888611};
-  bool mIsAutoTimestamp{false};
-  android_dataspace mDataSpace{HAL_DATASPACE_UNKNOWN};
-  Rect mCrop{Rect(kDefaultWidth, kDefaultHeight)};
-  int mScalingMode{0};
-  uint32_t mTransform{0};
-  sp<Fence> mFence{Fence::NO_FENCE};
-};
-
-// This is a test that covers our implementation of bufferhubqueue-based
-// IGraphicBufferProducer.
-class BufferHubQueueProducerTest : public ::testing::Test {
- protected:
-  virtual void SetUp() {
-    const ::testing::TestInfo* const testInfo =
-        ::testing::UnitTest::GetInstance()->current_test_info();
-    ALOGD_IF(TRACE, "Begin test: %s.%s", testInfo->test_case_name(),
-             testInfo->name());
-
-    auto config = ProducerQueueConfigBuilder().Build();
-    auto queue = ProducerQueue::Create(config, UsagePolicy{});
-    ASSERT_TRUE(queue != nullptr);
-
-    mProducer = BufferHubProducer::Create(std::move(queue));
-    ASSERT_TRUE(mProducer != nullptr);
-    mSurface = new Surface(mProducer, true);
-    ASSERT_TRUE(mSurface != nullptr);
-  }
-
-  // Connect to a producer in a 'correct' fashion.
-  void ConnectProducer() {
-    IGraphicBufferProducer::QueueBufferOutput output;
-    // Can connect the first time.
-    ASSERT_EQ(OK, mProducer->connect(kStubListener, kTestApi,
-                                     kTestControlledByApp, &output));
-  }
-
-  // Dequeue a buffer in a 'correct' fashion.
-  //   Precondition: Producer is connected.
-  void DequeueBuffer(int* outSlot) {
-    sp<Fence> fence;
-    ASSERT_NO_FATAL_FAILURE(DequeueBuffer(outSlot, &fence));
-  }
-
-  void DequeueBuffer(int* outSlot, sp<Fence>* outFence) {
-    ASSERT_NE(nullptr, outSlot);
-    ASSERT_NE(nullptr, outFence);
-
-    int ret = mProducer->dequeueBuffer(
-        outSlot, outFence, kDefaultWidth, kDefaultHeight, kDefaultFormat,
-        kTestProducerUsageBits, nullptr, nullptr);
-    // BUFFER_NEEDS_REALLOCATION can be either on or off.
-    ASSERT_EQ(0, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & ret);
-
-    // Slot number should be in boundary.
-    ASSERT_LE(0, *outSlot);
-    ASSERT_GT(BufferQueueDefs::NUM_BUFFER_SLOTS, *outSlot);
-  }
-
-  // Create a generic "valid" input for queueBuffer
-  // -- uses the default buffer format, width, etc.
-  static IGraphicBufferProducer::QueueBufferInput CreateBufferInput() {
-    return QueueBufferInputBuilder().build();
-  }
-
-  const sp<IProducerListener> kStubListener{new StubProducerListener};
-
-  sp<BufferHubProducer> mProducer;
-  sp<Surface> mSurface;
-};
-
-TEST_F(BufferHubQueueProducerTest, ConnectFirst_ReturnsError) {
-  IGraphicBufferProducer::QueueBufferOutput output;
-
-  // NULL output returns BAD_VALUE
-  EXPECT_EQ(BAD_VALUE, mProducer->connect(kStubListener, kTestApi,
-                                          kTestControlledByApp, nullptr));
-
-  // Invalid API returns bad value
-  EXPECT_EQ(BAD_VALUE, mProducer->connect(kStubListener, kTestApiInvalid,
-                                          kTestControlledByApp, &output));
-}
-
-TEST_F(BufferHubQueueProducerTest, ConnectAgain_ReturnsError) {
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
-  // Can't connect when there is already a producer connected.
-  IGraphicBufferProducer::QueueBufferOutput output;
-  EXPECT_EQ(BAD_VALUE, mProducer->connect(kStubListener, kTestApi,
-                                          kTestControlledByApp, &output));
-}
-
-TEST_F(BufferHubQueueProducerTest, Disconnect_Succeeds) {
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
-  ASSERT_EQ(OK, mProducer->disconnect(kTestApi));
-}
-
-TEST_F(BufferHubQueueProducerTest, Disconnect_ReturnsError) {
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
-  // Must disconnect with same API number
-  EXPECT_EQ(BAD_VALUE, mProducer->disconnect(kTestApiOther));
-  // API must not be out of range
-  EXPECT_EQ(BAD_VALUE, mProducer->disconnect(kTestApiInvalid));
-}
-
-TEST_F(BufferHubQueueProducerTest, Query_Succeeds) {
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
-  int32_t value = -1;
-  EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_WIDTH, &value));
-  EXPECT_EQ(kDefaultWidth, static_cast<uint32_t>(value));
-
-  EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_HEIGHT, &value));
-  EXPECT_EQ(kDefaultHeight, static_cast<uint32_t>(value));
-
-  EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_FORMAT, &value));
-  EXPECT_EQ(kDefaultFormat, value);
-
-  EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &value));
-  EXPECT_LE(0, value);
-  EXPECT_GE(BufferQueueDefs::NUM_BUFFER_SLOTS, value);
-
-  EXPECT_EQ(OK,
-            mProducer->query(NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value));
-  EXPECT_FALSE(value);  // Can't run behind when we haven't touched the queue
-
-  EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &value));
-  EXPECT_EQ(kDefaultConsumerUsageBits, value);
-}
-
-TEST_F(BufferHubQueueProducerTest, Query_ReturnsError) {
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
-  // One past the end of the last 'query' enum value. Update this if we add more
-  // enums.
-  const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_BUFFER_AGE + 1;
-
-  int value;
-  // What was out of range
-  EXPECT_EQ(BAD_VALUE, mProducer->query(/*what*/ -1, &value));
-  EXPECT_EQ(BAD_VALUE, mProducer->query(/*what*/ 0xDEADBEEF, &value));
-  EXPECT_EQ(BAD_VALUE,
-            mProducer->query(NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE, &value));
-
-  // Some enums from window.h are 'invalid'
-  EXPECT_EQ(BAD_VALUE,
-            mProducer->query(NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &value));
-  EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_CONCRETE_TYPE, &value));
-  EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_DEFAULT_WIDTH, &value));
-  EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_DEFAULT_HEIGHT, &value));
-  EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_TRANSFORM_HINT, &value));
-
-  // Value was NULL
-  EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_FORMAT, /*value*/ NULL));
-}
-
-TEST_F(BufferHubQueueProducerTest, Queue_Succeeds) {
-  int slot = -1;
-
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-
-  // Request the buffer (pre-requisite for queueing)
-  sp<GraphicBuffer> buffer;
-  ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-
-  // A generic "valid" input
-  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
-  IGraphicBufferProducer::QueueBufferOutput output;
-
-  // Queue the buffer back into the BQ
-  ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
-
-  EXPECT_EQ(kDefaultWidth, output.width);
-  EXPECT_EQ(kDefaultHeight, output.height);
-  EXPECT_EQ(kDefaultTransformHint, output.transformHint);
-
-  // BufferHubQueue delivers buffers to consumer immediately.
-  EXPECT_EQ(0u, output.numPendingBuffers);
-
-  // Note that BufferHubQueue doesn't support nextFrameNumber as it seems to
-  // be a SurfaceFlinger specific optimization.
-  EXPECT_EQ(0u, output.nextFrameNumber);
-
-  // Buffer was not in the dequeued state
-  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
-}
-
-// Test invalid slot number
-TEST_F(BufferHubQueueProducerTest, QueueInvalidSlot_ReturnsError) {
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
-  // A generic "valid" input
-  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
-  IGraphicBufferProducer::QueueBufferOutput output;
-
-  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(/*slot*/ -1, input, &output));
-  EXPECT_EQ(BAD_VALUE,
-            mProducer->queueBuffer(/*slot*/ 0xDEADBEEF, input, &output));
-  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(BufferQueueDefs::NUM_BUFFER_SLOTS,
-                                              input, &output));
-}
-
-// Slot was not in the dequeued state (all slots start out in Free state)
-TEST_F(BufferHubQueueProducerTest, QueueNotDequeued_ReturnsError) {
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
-  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
-  IGraphicBufferProducer::QueueBufferOutput output;
-
-  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(/*slot*/ 0, input, &output));
-}
-
-// Slot was enqueued without requesting a buffer
-TEST_F(BufferHubQueueProducerTest, QueueNotRequested_ReturnsError) {
-  int slot = -1;
-
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-
-  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
-  IGraphicBufferProducer::QueueBufferOutput output;
-
-  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
-}
-
-// Test when fence was NULL
-TEST_F(BufferHubQueueProducerTest, QueueNoFence_ReturnsError) {
-  int slot = -1;
-
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-
-  sp<GraphicBuffer> buffer;
-  ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-
-  sp<Fence> nullFence = NULL;
-
-  IGraphicBufferProducer::QueueBufferInput input =
-      QueueBufferInputBuilder().setFence(nullFence).build();
-  IGraphicBufferProducer::QueueBufferOutput output;
-
-  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
-}
-
-// Test scaling mode was invalid
-TEST_F(BufferHubQueueProducerTest, QueueTestInvalidScalingMode_ReturnsError) {
-  int slot = -1;
-
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-
-  sp<GraphicBuffer> buffer;
-  ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-
-  IGraphicBufferProducer::QueueBufferInput input =
-      QueueBufferInputBuilder().setScalingMode(-1).build();
-  IGraphicBufferProducer::QueueBufferOutput output;
-
-  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
-
-  input = QueueBufferInputBuilder().setScalingMode(0xDEADBEEF).build();
-
-  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
-}
-
-// Test crop rect is out of bounds of the buffer dimensions
-TEST_F(BufferHubQueueProducerTest, QueueCropOutOfBounds_ReturnsError) {
-  int slot = -1;
-
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-
-  sp<GraphicBuffer> buffer;
-  ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-
-  IGraphicBufferProducer::QueueBufferInput input =
-      QueueBufferInputBuilder()
-          .setCrop(Rect(kDefaultWidth + 1, kDefaultHeight + 1))
-          .build();
-  IGraphicBufferProducer::QueueBufferOutput output;
-
-  EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(slot, input, &output));
-}
-
-TEST_F(BufferHubQueueProducerTest, CancelBuffer_Succeeds) {
-  int slot = -1;
-  sp<Fence> fence;
-
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot, &fence));
-
-  // Should be able to cancel buffer after a dequeue.
-  EXPECT_EQ(OK, mProducer->cancelBuffer(slot, fence));
-}
-
-TEST_F(BufferHubQueueProducerTest, SetMaxDequeuedBufferCount_Succeeds) {
-  return;
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
-  int minUndequeuedBuffers;
-  ASSERT_EQ(OK, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-                                 &minUndequeuedBuffers));
-
-  const int minBuffers = 1;
-  const int maxBuffers =
-      BufferQueueDefs::NUM_BUFFER_SLOTS - minUndequeuedBuffers;
-
-  ASSERT_EQ(OK, mProducer->setAsyncMode(false)) << "async mode: " << false;
-  ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(minBuffers))
-      << "bufferCount: " << minBuffers;
-
-  // Should now be able to dequeue up to minBuffers times
-  // Should now be able to dequeue up to maxBuffers times
-  int slot = -1;
-  for (int i = 0; i < minBuffers; ++i) {
-    ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-  }
-
-  ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(maxBuffers));
-
-  // queue the first buffer to enable max dequeued buffer count checking
-  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
-  IGraphicBufferProducer::QueueBufferOutput output;
-  sp<GraphicBuffer> buffer;
-  ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-  ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
-
-  sp<Fence> fence;
-  for (int i = 0; i < maxBuffers; ++i) {
-    ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot, &fence));
-  }
-
-  // Cancel a buffer, so we can decrease the buffer count
-  ASSERT_EQ(OK, mProducer->cancelBuffer(slot, fence));
-
-  // Should now be able to decrease the max dequeued count by 1
-  ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(maxBuffers - 1));
-}
-
-TEST_F(BufferHubQueueProducerTest, SetMaxDequeuedBufferCount_Fails) {
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-
-  int minUndequeuedBuffers;
-  ASSERT_EQ(OK, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-                                 &minUndequeuedBuffers));
-
-  const int minBuffers = 1;
-  const int maxBuffers =
-      BufferQueueDefs::NUM_BUFFER_SLOTS - minUndequeuedBuffers;
-
-  ASSERT_EQ(OK, mProducer->setAsyncMode(false)) << "async mode: " << false;
-  // Buffer count was out of range
-  EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(0))
-      << "bufferCount: " << 0;
-  EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(maxBuffers + 1))
-      << "bufferCount: " << maxBuffers + 1;
-
-  // Set max dequeue count to 2
-  ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(2));
-  // Dequeue 2 buffers
-  int slot = -1;
-  sp<Fence> fence;
-  for (int i = 0; i < 2; i++) {
-    ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
-                      (mProducer->dequeueBuffer(&slot, &fence, kDefaultWidth,
-                                                kDefaultHeight, kDefaultFormat,
-                                                kTestProducerUsageBits,
-                                                nullptr, nullptr)))
-        << "slot: " << slot;
-  }
-
-  // Client has too many buffers dequeued
-  EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(1))
-      << "bufferCount: " << minBuffers;
-}
-
-TEST_F(BufferHubQueueProducerTest,
-       DisconnectedProducerReturnsError_dequeueBuffer) {
-  int slot = -1;
-  sp<Fence> fence;
-
-  ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, kDefaultWidth,
-                                              kDefaultHeight, kDefaultFormat,
-                                              kTestProducerUsageBits,
-                                              nullptr, nullptr));
-}
-
-TEST_F(BufferHubQueueProducerTest,
-       DisconnectedProducerReturnsError_requestBuffer) {
-  int slot = -1;
-  sp<GraphicBuffer> buffer;
-
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-
-  // Shouldn't be able to request buffer after disconnect.
-  ASSERT_EQ(OK, mProducer->disconnect(kTestApi));
-  ASSERT_EQ(NO_INIT, mProducer->requestBuffer(slot, &buffer));
-}
-
-TEST_F(BufferHubQueueProducerTest,
-       DisconnectedProducerReturnsError_queueBuffer) {
-  int slot = -1;
-  sp<GraphicBuffer> buffer;
-
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-  ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-
-  // A generic "valid" input
-  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
-  IGraphicBufferProducer::QueueBufferOutput output;
-
-  // Shouldn't be able to queue buffer after disconnect.
-  ASSERT_EQ(OK, mProducer->disconnect(kTestApi));
-  ASSERT_EQ(NO_INIT, mProducer->queueBuffer(slot, input, &output));
-}
-
-TEST_F(BufferHubQueueProducerTest,
-       DisconnectedProducerReturnsError_cancelBuffer) {
-  int slot = -1;
-  sp<GraphicBuffer> buffer;
-
-  ASSERT_NO_FATAL_FAILURE(ConnectProducer());
-  ASSERT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-  ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-
-  // Shouldn't be able to cancel buffer after disconnect.
-  ASSERT_EQ(OK, mProducer->disconnect(kTestApi));
-  ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, Fence::NO_FENCE));
-}
-
-TEST_F(BufferHubQueueProducerTest, ConnectDisconnectReconnect) {
-  int slot = -1;
-  sp<GraphicBuffer> buffer;
-  IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
-  IGraphicBufferProducer::QueueBufferOutput output;
-
-  EXPECT_NO_FATAL_FAILURE(ConnectProducer());
-
-  constexpr int maxDequeuedBuffers = 1;
-  int minUndequeuedBuffers;
-  EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-                                 &minUndequeuedBuffers));
-  EXPECT_EQ(OK, mProducer->setAsyncMode(false));
-  EXPECT_EQ(OK, mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers));
-
-  int maxCapacity = maxDequeuedBuffers + minUndequeuedBuffers;
-
-  // Dequeue, request, and queue all buffers.
-  for (int i = 0; i < maxCapacity; i++) {
-    EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-    EXPECT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-    EXPECT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
-  }
-
-  // Disconnect then reconnect.
-  EXPECT_EQ(OK, mProducer->disconnect(kTestApi));
-  EXPECT_NO_FATAL_FAILURE(ConnectProducer());
-
-  // Dequeue, request, and queue all buffers.
-  for (int i = 0; i < maxCapacity; i++) {
-    EXPECT_NO_FATAL_FAILURE(DequeueBuffer(&slot));
-    EXPECT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
-    EXPECT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
-  }
-
-  EXPECT_EQ(OK, mProducer->disconnect(kTestApi));
-}
-
-TEST_F(BufferHubQueueProducerTest, TakeAsParcelable) {
-  // Connected producer cannot be taken out as a parcelable.
-  EXPECT_NO_FATAL_FAILURE(ConnectProducer());
-  ProducerQueueParcelable producer_parcelable;
-  EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), BAD_VALUE);
-
-  // Create a valid fake producer parcelable.
-  auto fake_channel_parcelable =
-      std::make_unique<pdx::default_transport::ChannelParcelable>(
-          LocalHandle(0), LocalHandle(0), LocalHandle(0));
-  EXPECT_TRUE(fake_channel_parcelable->IsValid());
-  ProducerQueueParcelable fake_producer_parcelable(
-      std::move(fake_channel_parcelable));
-  EXPECT_TRUE(fake_producer_parcelable.IsValid());
-
-  // Disconnect producer can be taken out, but only to an invalid parcelable.
-  ASSERT_EQ(mProducer->disconnect(kTestApi), OK);
-  EXPECT_EQ(mProducer->TakeAsParcelable(&fake_producer_parcelable), BAD_VALUE);
-  EXPECT_FALSE(producer_parcelable.IsValid());
-  EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), OK);
-  EXPECT_TRUE(producer_parcelable.IsValid());
-
-  // Should still be able to query buffer dimension after disconnect.
-  int32_t value = -1;
-  EXPECT_EQ(OK, mProducer->query(NATIVE_WINDOW_WIDTH, &value));
-  EXPECT_EQ(static_cast<uint32_t>(value), kDefaultWidth);
-
-  EXPECT_EQ(mProducer->query(NATIVE_WINDOW_HEIGHT, &value), OK);
-  EXPECT_EQ(static_cast<uint32_t>(value), kDefaultHeight);
-
-  EXPECT_EQ(mProducer->query(NATIVE_WINDOW_FORMAT, &value), OK);
-  EXPECT_EQ(value, kDefaultFormat);
-
-  // But connect to API will fail.
-  IGraphicBufferProducer::QueueBufferOutput output;
-  EXPECT_EQ(mProducer->connect(kStubListener, kTestApi, kTestControlledByApp,
-                               &output),
-            BAD_VALUE);
-
-  // Create a new producer from the parcelable and connect to kTestApi should
-  // succeed.
-  sp<BufferHubProducer> new_producer =
-      BufferHubProducer::Create(std::move(producer_parcelable));
-  ASSERT_TRUE(new_producer != nullptr);
-  EXPECT_EQ(new_producer->connect(kStubListener, kTestApi, kTestControlledByApp,
-                                  &output),
-            OK);
-}
-
-}  // namespace
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
deleted file mode 100644
index b0ed950..0000000
--- a/libs/vr/libdisplay/Android.bp
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_native_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_native_license"],
-}
-
-sourceFiles = [
-    "display_client.cpp",
-    "display_manager_client.cpp",
-    "display_protocol.cpp",
-    "shared_buffer_helpers.cpp",
-    "vsync_service.cpp",
-]
-
-localIncludeFiles = [
-    "include",
-]
-
-sharedLibraries = [
-    "libbase",
-    "libbinder",
-    "libbufferhubqueue",
-    "libcutils",
-    "liblog",
-    "libutils",
-    "libui",
-    "libgui",
-    "libhardware",
-    "libsync",
-    "libnativewindow",
-    "libpdx_default_transport",
-]
-
-staticLibraries = [
-    "libdvrcommon",
-    "libbroadcastring",
-]
-
-headerLibraries = [
-    "vulkan_headers",
-    "libdvr_headers",
-]
-
-cc_library {
-    srcs: sourceFiles,
-    cflags: ["-DLOG_TAG=\"libdisplay\"",
-        "-DTRACE=0",
-        "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
-        "-DGL_GLEXT_PROTOTYPES",
-        "-DEGL_EGLEXT_PROTOTYPES",
-        "-Wall",
-        "-Werror",
-    ],  // + [ "-UNDEBUG", "-DDEBUG", "-O0", "-g" ],
-    export_include_dirs: localIncludeFiles,
-    shared_libs: sharedLibraries,
-    static_libs: staticLibraries,
-    header_libs: headerLibraries,
-    export_header_lib_headers: headerLibraries,
-
-    name: "libdisplay",
-}
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
deleted file mode 100644
index 62856df..0000000
--- a/libs/vr/libdisplay/display_client.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-#include "include/private/dvr/display_client.h"
-
-#include <cutils/native_handle.h>
-#include <log/log.h>
-#include <pdx/default_transport/client_channel.h>
-#include <pdx/default_transport/client_channel_factory.h>
-#include <pdx/status.h>
-
-#include <mutex>
-
-#include <private/dvr/display_protocol.h>
-
-using android::pdx::ErrorStatus;
-using android::pdx::LocalHandle;
-using android::pdx::LocalChannelHandle;
-using android::pdx::Status;
-using android::pdx::Transaction;
-using android::pdx::rpc::IfAnyOf;
-
-namespace android {
-namespace dvr {
-namespace display {
-
-Surface::Surface(LocalChannelHandle channel_handle, int* error)
-    : BASE{pdx::default_transport::ClientChannel::Create(
-          std::move(channel_handle))} {
-  auto status = InvokeRemoteMethod<DisplayProtocol::GetSurfaceInfo>();
-  if (!status) {
-    ALOGE("Surface::Surface: Failed to get surface info: %s",
-          status.GetErrorMessage().c_str());
-    Close(status.error());
-    if (error)
-      *error = status.error();
-  }
-
-  surface_id_ = status.get().surface_id;
-  z_order_ = status.get().z_order;
-  visible_ = status.get().visible;
-}
-
-Surface::Surface(const SurfaceAttributes& attributes, int* error)
-    : BASE{pdx::default_transport::ClientChannelFactory::Create(
-               DisplayProtocol::kClientPath),
-           kInfiniteTimeout} {
-  auto status = InvokeRemoteMethod<DisplayProtocol::CreateSurface>(attributes);
-  if (!status) {
-    ALOGE("Surface::Surface: Failed to create display surface: %s",
-          status.GetErrorMessage().c_str());
-    Close(status.error());
-    if (error)
-      *error = status.error();
-  }
-
-  surface_id_ = status.get().surface_id;
-  z_order_ = status.get().z_order;
-  visible_ = status.get().visible;
-}
-
-Status<void> Surface::SetVisible(bool visible) {
-  return SetAttributes(
-      {{SurfaceAttribute::Visible, SurfaceAttributeValue{visible}}});
-}
-
-Status<void> Surface::SetZOrder(int z_order) {
-  return SetAttributes(
-      {{SurfaceAttribute::ZOrder, SurfaceAttributeValue{z_order}}});
-}
-
-Status<void> Surface::SetAttributes(const SurfaceAttributes& attributes) {
-  auto status = InvokeRemoteMethod<DisplayProtocol::SetAttributes>(attributes);
-  if (!status) {
-    ALOGE(
-        "Surface::SetAttributes: Failed to set display surface "
-        "attributes: %s",
-        status.GetErrorMessage().c_str());
-    return status.error_status();
-  }
-
-  // Set the local cached copies of the attributes we care about from the full
-  // set of attributes sent to the display service.
-  for (const auto& attribute : attributes) {
-    const auto& key = attribute.first;
-    const auto* variant = &attribute.second;
-    bool invalid_value = false;
-    switch (key) {
-      case SurfaceAttribute::Visible:
-        invalid_value =
-            !IfAnyOf<int32_t, int64_t, bool>::Get(variant, &visible_);
-        break;
-      case SurfaceAttribute::ZOrder:
-        invalid_value = !IfAnyOf<int32_t>::Get(variant, &z_order_);
-        break;
-    }
-
-    if (invalid_value) {
-      ALOGW(
-          "Surface::SetAttributes: Failed to set display surface "
-          "attribute %d because of incompatible type: %d",
-          key, variant->index());
-    }
-  }
-
-  return {};
-}
-
-Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(
-    uint32_t width, uint32_t height, uint32_t format, size_t metadata_size) {
-  ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue.");
-  auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(
-      ProducerQueueConfigBuilder()
-          .SetDefaultWidth(width)
-          .SetDefaultHeight(height)
-          .SetDefaultFormat(format)
-          .SetMetadataSize(metadata_size)
-          .Build());
-  if (!status) {
-    ALOGE("Surface::CreateQueue: Failed to create queue: %s",
-          status.GetErrorMessage().c_str());
-    return status.error_status();
-  }
-
-  auto producer_queue = ProducerQueue::Import(status.take());
-  if (!producer_queue) {
-    ALOGE("Surface::CreateQueue: Failed to import producer queue!");
-    return ErrorStatus(ENOMEM);
-  }
-
-  return {std::move(producer_queue)};
-}
-
-Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(
-    uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
-    uint64_t usage, size_t capacity, size_t metadata_size) {
-  ALOGD_IF(TRACE,
-           "Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u "
-           "usage=%" PRIx64 " capacity=%zu",
-           width, height, layer_count, format, usage, capacity);
-  auto status = CreateQueue(width, height, format, metadata_size);
-  if (!status)
-    return status.error_status();
-
-  auto producer_queue = status.take();
-
-  ALOGD_IF(TRACE, "Surface::CreateQueue: Allocating %zu buffers...", capacity);
-  auto allocate_status = producer_queue->AllocateBuffers(
-      width, height, layer_count, format, usage, capacity);
-  if (!allocate_status) {
-    ALOGE("Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s",
-          producer_queue->id(), allocate_status.GetErrorMessage().c_str());
-    return allocate_status.error_status();
-  }
-
-  return {std::move(producer_queue)};
-}
-
-DisplayClient::DisplayClient(int* error)
-    : BASE(pdx::default_transport::ClientChannelFactory::Create(
-               DisplayProtocol::kClientPath),
-           kInfiniteTimeout) {
-  if (error)
-    *error = Client::error();
-}
-
-Status<Metrics> DisplayClient::GetDisplayMetrics() {
-  return InvokeRemoteMethod<DisplayProtocol::GetMetrics>();
-}
-
-Status<std::string> DisplayClient::GetConfigurationData(
-    ConfigFileType config_type) {
-  auto status =
-      InvokeRemoteMethod<DisplayProtocol::GetConfigurationData>(config_type);
-  if (!status && status.error() != ENOENT) {
-    ALOGE(
-        "DisplayClient::GetConfigurationData: Unable to get"
-        "configuration data. Error: %s",
-        status.GetErrorMessage().c_str());
-  }
-  return status;
-}
-
-Status<uint8_t> DisplayClient::GetDisplayIdentificationPort() {
-  return InvokeRemoteMethod<DisplayProtocol::GetDisplayIdentificationPort>();
-}
-
-Status<std::unique_ptr<Surface>> DisplayClient::CreateSurface(
-    const SurfaceAttributes& attributes) {
-  int error;
-  if (auto client = Surface::Create(attributes, &error))
-    return {std::move(client)};
-  else
-    return ErrorStatus(error);
-}
-
-pdx::Status<std::unique_ptr<IonBuffer>> DisplayClient::SetupGlobalBuffer(
-    DvrGlobalBufferKey key, size_t size, uint64_t usage) {
-  auto status =
-      InvokeRemoteMethod<DisplayProtocol::SetupGlobalBuffer>(key, size, usage);
-  if (!status) {
-    ALOGE(
-        "DisplayClient::SetupGlobalBuffer: Failed to create the global buffer "
-        "%s",
-        status.GetErrorMessage().c_str());
-    return status.error_status();
-  }
-
-  auto ion_buffer = std::make_unique<IonBuffer>();
-  auto native_buffer_handle = status.take();
-  const int ret = native_buffer_handle.Import(ion_buffer.get());
-  if (ret < 0) {
-    ALOGE(
-        "DisplayClient::GetGlobalBuffer: Failed to import global buffer: "
-        "key=%d; error=%s",
-        key, strerror(-ret));
-    return ErrorStatus(-ret);
-  }
-
-  return {std::move(ion_buffer)};
-}
-
-pdx::Status<void> DisplayClient::DeleteGlobalBuffer(DvrGlobalBufferKey key) {
-  auto status = InvokeRemoteMethod<DisplayProtocol::DeleteGlobalBuffer>(key);
-  if (!status) {
-    ALOGE("DisplayClient::DeleteGlobalBuffer Failed: %s",
-          status.GetErrorMessage().c_str());
-  }
-
-  return status;
-}
-
-Status<std::unique_ptr<IonBuffer>> DisplayClient::GetGlobalBuffer(
-    DvrGlobalBufferKey key) {
-  auto status = InvokeRemoteMethod<DisplayProtocol::GetGlobalBuffer>(key);
-  if (!status) {
-    ALOGE(
-        "DisplayClient::GetGlobalBuffer: Failed to get named buffer: key=%d; "
-        "error=%s",
-        key, status.GetErrorMessage().c_str());
-    return status.error_status();
-  }
-
-  auto ion_buffer = std::make_unique<IonBuffer>();
-  auto native_buffer_handle = status.take();
-  const int ret = native_buffer_handle.Import(ion_buffer.get());
-  if (ret < 0) {
-    ALOGE(
-        "DisplayClient::GetGlobalBuffer: Failed to import global buffer: "
-        "key=%d; error=%s",
-        key, strerror(-ret));
-    return ErrorStatus(-ret);
-  }
-
-  return {std::move(ion_buffer)};
-}
-
-Status<bool> DisplayClient::IsVrAppRunning() {
-  return InvokeRemoteMethod<DisplayProtocol::IsVrAppRunning>();
-}
-
-}  // namespace display
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp
deleted file mode 100644
index fdeeb70..0000000
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "include/private/dvr/display_manager_client.h"
-
-#include <pdx/default_transport/client_channel_factory.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/display_protocol.h>
-#include <utils/Log.h>
-
-using android::pdx::ErrorStatus;
-using android::pdx::LocalChannelHandle;
-using android::pdx::Transaction;
-
-namespace android {
-namespace dvr {
-namespace display {
-
-DisplayManagerClient::DisplayManagerClient()
-    : BASE(pdx::default_transport::ClientChannelFactory::Create(
-          DisplayManagerProtocol::kClientPath)) {}
-
-DisplayManagerClient::~DisplayManagerClient() {}
-
-pdx::Status<std::vector<display::SurfaceState>>
-DisplayManagerClient::GetSurfaceState() {
-  auto status = InvokeRemoteMethod<DisplayManagerProtocol::GetSurfaceState>();
-  if (!status) {
-    ALOGE(
-        "DisplayManagerClient::GetSurfaceState: Failed to get surface info: %s",
-        status.GetErrorMessage().c_str());
-  }
-
-  return status;
-}
-
-pdx::Status<std::unique_ptr<ConsumerQueue>>
-DisplayManagerClient::GetSurfaceQueue(int surface_id, int queue_id) {
-  auto status = InvokeRemoteMethod<DisplayManagerProtocol::GetSurfaceQueue>(
-      surface_id, queue_id);
-  if (!status) {
-    ALOGE(
-        "DisplayManagerClient::GetSurfaceQueue: Failed to get queue for "
-        "surface_id=%d queue_id=%d: %s",
-        surface_id, queue_id, status.GetErrorMessage().c_str());
-    return status.error_status();
-  }
-
-  return {ConsumerQueue::Import(status.take())};
-}
-
-}  // namespace display
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libdisplay/display_protocol.cpp b/libs/vr/libdisplay/display_protocol.cpp
deleted file mode 100644
index 773f9a5..0000000
--- a/libs/vr/libdisplay/display_protocol.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "include/private/dvr/display_protocol.h"
-
-namespace android {
-namespace dvr {
-namespace display {
-
-constexpr char DisplayProtocol::kClientPath[];
-constexpr char DisplayManagerProtocol::kClientPath[];
-constexpr char VSyncProtocol::kClientPath[];
-
-}  // namespace display
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libdisplay/include/CPPLINT.cfg b/libs/vr/libdisplay/include/CPPLINT.cfg
deleted file mode 100644
index 2f8a3c0..0000000
--- a/libs/vr/libdisplay/include/CPPLINT.cfg
+++ /dev/null
@@ -1 +0,0 @@
-filter=-build/header_guard
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
deleted file mode 100644
index 81546ac..0000000
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ /dev/null
@@ -1,100 +0,0 @@
-#ifndef ANDROID_DVR_DISPLAY_CLIENT_H_
-#define ANDROID_DVR_DISPLAY_CLIENT_H_
-
-#include <dvr/dvr_api.h>
-#include <hardware/hwcomposer.h>
-#include <pdx/client.h>
-#include <pdx/file_handle.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/display_protocol.h>
-
-namespace android {
-namespace dvr {
-namespace display {
-
-class Surface : public pdx::ClientBase<Surface> {
- public:
-  // Utility named constructor. This can be removed once ClientBase::Create is
-  // refactored to return Status<T> types.
-  static pdx::Status<std::unique_ptr<Surface>> CreateSurface(
-      const SurfaceAttributes& attributes) {
-    int error;
-    pdx::Status<std::unique_ptr<Surface>> status;
-    if (auto surface = Create(attributes, &error))
-      status.SetValue(std::move(surface));
-    else
-      status.SetError(error);
-    return status;
-  }
-
-  int surface_id() const { return surface_id_; }
-  int z_order() const { return z_order_; }
-  bool visible() const { return visible_; }
-
-  pdx::Status<void> SetVisible(bool visible);
-  pdx::Status<void> SetZOrder(int z_order);
-  pdx::Status<void> SetAttributes(const SurfaceAttributes& attributes);
-
-  // Creates an empty queue.
-  pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue(uint32_t width,
-                                                          uint32_t height,
-                                                          uint32_t format,
-                                                          size_t metadata_size);
-
-  // Creates a queue and populates it with |capacity| buffers of the specified
-  // parameters.
-  pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue(uint32_t width,
-                                                          uint32_t height,
-                                                          uint32_t layer_count,
-                                                          uint32_t format,
-                                                          uint64_t usage,
-                                                          size_t capacity,
-                                                          size_t metadata_size);
-
- private:
-  friend BASE;
-
-  int surface_id_ = -1;
-  int z_order_ = 0;
-  bool visible_ = false;
-
-  // TODO(eieio,avakulenko): Remove error param once pdx::ClientBase::Create()
-  // returns Status<T>.
-  explicit Surface(const SurfaceAttributes& attributes, int* error = nullptr);
-  explicit Surface(pdx::LocalChannelHandle channel_handle,
-                   int* error = nullptr);
-
-  Surface(const Surface&) = delete;
-  void operator=(const Surface&) = delete;
-};
-
-class DisplayClient : public pdx::ClientBase<DisplayClient> {
- public:
-  pdx::Status<Metrics> GetDisplayMetrics();
-  pdx::Status<std::string> GetConfigurationData(ConfigFileType config_type);
-  pdx::Status<uint8_t> GetDisplayIdentificationPort();
-  pdx::Status<std::unique_ptr<IonBuffer>> SetupGlobalBuffer(
-      DvrGlobalBufferKey key, size_t size, uint64_t usage);
-  pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key);
-  pdx::Status<std::unique_ptr<IonBuffer>> GetGlobalBuffer(
-      DvrGlobalBufferKey key);
-  pdx::Status<std::unique_ptr<Surface>> CreateSurface(
-      const SurfaceAttributes& attributes);
-
-  // Temporary query for current VR status. Will be removed later.
-  pdx::Status<bool> IsVrAppRunning();
-
- private:
-  friend BASE;
-
-  explicit DisplayClient(int* error = nullptr);
-
-  DisplayClient(const DisplayClient&) = delete;
-  void operator=(const DisplayClient&) = delete;
-};
-
-}  // namespace display
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_DISPLAY_CLIENT_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
deleted file mode 100644
index 45aef51..0000000
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef ANDROID_DVR_DISPLAY_MANAGER_CLIENT_H_
-#define ANDROID_DVR_DISPLAY_MANAGER_CLIENT_H_
-
-#include <string>
-#include <vector>
-
-#include <pdx/client.h>
-#include <pdx/status.h>
-#include <private/dvr/display_protocol.h>
-
-namespace android {
-namespace dvr {
-
-class IonBuffer;
-class ConsumerQueue;
-
-namespace display {
-
-class DisplayManagerClient : public pdx::ClientBase<DisplayManagerClient> {
- public:
-  ~DisplayManagerClient() override;
-
-  pdx::Status<std::vector<SurfaceState>> GetSurfaceState();
-  pdx::Status<std::unique_ptr<ConsumerQueue>> GetSurfaceQueue(int surface_id,
-                                                              int queue_id);
-
-  using Client::event_fd;
-
-  pdx::Status<int> GetEventMask(int events) {
-    if (auto* client_channel = GetChannel())
-      return client_channel->GetEventMask(events);
-    else
-      return pdx::ErrorStatus(EINVAL);
-  }
-
- private:
-  friend BASE;
-
-  DisplayManagerClient();
-
-  DisplayManagerClient(const DisplayManagerClient&) = delete;
-  void operator=(const DisplayManagerClient&) = delete;
-};
-
-}  // namespace display
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_DISPLAY_MANAGER_CLIENT_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
deleted file mode 100644
index 9f4cc4a..0000000
--- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h
+++ /dev/null
@@ -1,304 +0,0 @@
-#ifndef ANDROID_DVR_DISPLAY_PROTOCOL_H_
-#define ANDROID_DVR_DISPLAY_PROTOCOL_H_
-
-#include <sys/types.h>
-
-#include <array>
-#include <map>
-
-#include <dvr/dvr_display_types.h>
-
-#include <dvr/dvr_api.h>
-#include <pdx/rpc/buffer_wrapper.h>
-#include <pdx/rpc/remote_method.h>
-#include <pdx/rpc/serializable.h>
-#include <pdx/rpc/variant.h>
-#include <private/dvr/bufferhub_rpc.h>
-
-// RPC protocol definitions for DVR display services (VrFlinger).
-
-namespace android {
-namespace dvr {
-namespace display {
-
-// Native display metrics.
-struct Metrics {
-  // Basic display properties.
-  uint32_t display_width;
-  uint32_t display_height;
-  uint32_t display_x_dpi;
-  uint32_t display_y_dpi;
-  uint32_t vsync_period_ns;
-
-  // HMD metrics.
-  // TODO(eieio): Determine how these fields should be populated. On phones
-  // these values are determined at runtime by VrCore based on which headset the
-  // phone is in. On dedicated hardware this needs to come from somewhere else.
-  // Perhaps these should be moved to a separate structure that is returned by a
-  // separate runtime call.
-  uint32_t distorted_width;
-  uint32_t distorted_height;
-  uint32_t hmd_ipd_mm;
-  float inter_lens_distance_m;
-  std::array<float, 4> left_fov_lrbt;
-  std::array<float, 4> right_fov_lrbt;
-
- private:
-  PDX_SERIALIZABLE_MEMBERS(Metrics, display_width, display_height,
-                           display_x_dpi, display_y_dpi, vsync_period_ns,
-                           distorted_width, distorted_height, hmd_ipd_mm,
-                           inter_lens_distance_m, left_fov_lrbt,
-                           right_fov_lrbt);
-};
-
-// Serializable base type for enum structs. Enum structs are easier to use than
-// enum classes, especially for bitmasks. This base type provides common
-// utilities for flags types.
-template <typename Integer>
-class Flags {
- public:
-  using Base = Flags<Integer>;
-  using Type = Integer;
-
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  Flags(const Integer& value) : value_{value} {}
-  Flags(const Flags&) = default;
-  Flags& operator=(const Flags&) = default;
-
-  Integer value() const { return value_; }
-  // NOLINTNEXTLINE(google-explicit-constructor)
-  operator Integer() const { return value_; }
-
-  bool IsSet(Integer bits) const { return (value_ & bits) == bits; }
-  bool IsClear(Integer bits) const { return (value_ & bits) == 0; }
-
-  void Set(Integer bits) { value_ |= bits; }
-  void Clear(Integer bits) { value_ &= ~bits; }
-
-  Integer operator|(Integer bits) const { return value_ | bits; }
-  Integer operator&(Integer bits) const { return value_ & bits; }
-
-  Flags& operator|=(Integer bits) {
-    value_ |= bits;
-    return *this;
-  }
-  Flags& operator&=(Integer bits) {
-    value_ &= bits;
-    return *this;
-  }
-
- private:
-  Integer value_;
-
-  PDX_SERIALIZABLE_MEMBERS(Flags<Integer>, value_);
-};
-
-// Flags indicating what changed since last update.
-struct SurfaceUpdateFlags : public Flags<uint32_t> {
-  enum : Type {
-    None = DVR_SURFACE_UPDATE_FLAGS_NONE,
-    NewSurface = DVR_SURFACE_UPDATE_FLAGS_NEW_SURFACE,
-    BuffersChanged = DVR_SURFACE_UPDATE_FLAGS_BUFFERS_CHANGED,
-    VisibilityChanged = DVR_SURFACE_UPDATE_FLAGS_VISIBILITY_CHANGED,
-    AttributesChanged = DVR_SURFACE_UPDATE_FLAGS_ATTRIBUTES_CHANGED,
-  };
-
-  SurfaceUpdateFlags() : Base{None} {}
-  using Base::Base;
-};
-
-// Surface attribute key/value types.
-using SurfaceAttributeKey = int32_t;
-using SurfaceAttributeValue =
-    pdx::rpc::Variant<int32_t, int64_t, bool, float, std::array<float, 2>,
-                      std::array<float, 3>, std::array<float, 4>,
-                      std::array<float, 8>, std::array<float, 16>>;
-
-// Defined surface attribute keys.
-struct SurfaceAttribute : public Flags<SurfaceAttributeKey> {
-  enum : Type {
-    // Keys in the negative integer space are interpreted by VrFlinger for
-    // direct surfaces.
-    Direct = DVR_SURFACE_ATTRIBUTE_DIRECT,
-    ZOrder = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
-    Visible = DVR_SURFACE_ATTRIBUTE_VISIBLE,
-
-    // Invalid key. May be used to terminate C style lists in public API code.
-    Invalid = DVR_SURFACE_ATTRIBUTE_INVALID,
-
-    // Positive keys are interpreted by the compositor only.
-    FirstUserKey = DVR_SURFACE_ATTRIBUTE_FIRST_USER_KEY,
-  };
-
-  SurfaceAttribute() : Base{Invalid} {}
-  using Base::Base;
-};
-
-// Collection of surface attribute key/value pairs.
-using SurfaceAttributes = std::map<SurfaceAttributeKey, SurfaceAttributeValue>;
-
-struct SurfaceState {
-  int32_t surface_id;
-  int32_t process_id;
-  int32_t user_id;
-
-  SurfaceAttributes surface_attributes;
-  SurfaceUpdateFlags update_flags;
-  std::vector<int32_t> queue_ids;
-
-  // Convenience accessors.
-  bool GetVisible() const {
-    bool bool_value = false;
-    GetAttribute(SurfaceAttribute::Visible, &bool_value,
-                 ValidTypes<int32_t, int64_t, bool, float>{});
-    return bool_value;
-  }
-
-  int GetZOrder() const {
-    int int_value = 0;
-    GetAttribute(SurfaceAttribute::ZOrder, &int_value,
-                 ValidTypes<int32_t, int64_t, float>{});
-    return int_value;
-  }
-
- private:
-  template <typename... Types>
-  struct ValidTypes {};
-
-  template <typename ReturnType, typename... Types>
-  bool GetAttribute(SurfaceAttributeKey key, ReturnType* out_value,
-                    ValidTypes<Types...>) const {
-    auto search = surface_attributes.find(key);
-    if (search != surface_attributes.end())
-      return pdx::rpc::IfAnyOf<Types...>::Get(&search->second, out_value);
-    else
-      return false;
-  }
-
-  PDX_SERIALIZABLE_MEMBERS(SurfaceState, surface_id, process_id,
-                           surface_attributes, update_flags, queue_ids);
-};
-
-struct SurfaceInfo {
-  int surface_id;
-  bool visible;
-  int z_order;
-
- private:
-  PDX_SERIALIZABLE_MEMBERS(SurfaceInfo, surface_id, visible, z_order);
-};
-
-enum class ConfigFileType : uint32_t {
-  kLensMetrics,
-  kDeviceMetrics,
-  kDeviceConfiguration,
-  kDeviceEdid
-};
-
-struct DisplayProtocol {
-  // Service path.
-  static constexpr char kClientPath[] = "system/vr/display/client";
-
-  // Op codes.
-  enum {
-    kOpGetMetrics = 0,
-    kOpGetConfigurationData,
-    kOpSetupGlobalBuffer,
-    kOpDeleteGlobalBuffer,
-    kOpGetGlobalBuffer,
-    kOpIsVrAppRunning,
-    kOpCreateSurface,
-    kOpGetSurfaceInfo,
-    kOpCreateQueue,
-    kOpSetAttributes,
-    kOpGetDisplayIdentificationPort,
-  };
-
-  // Aliases.
-  using LocalChannelHandle = pdx::LocalChannelHandle;
-  using Void = pdx::rpc::Void;
-
-  // Methods.
-  PDX_REMOTE_METHOD(GetMetrics, kOpGetMetrics, Metrics(Void));
-  PDX_REMOTE_METHOD(GetConfigurationData, kOpGetConfigurationData,
-                    std::string(ConfigFileType config_type));
-  PDX_REMOTE_METHOD(GetDisplayIdentificationPort,
-                    kOpGetDisplayIdentificationPort, uint8_t(Void));
-  PDX_REMOTE_METHOD(SetupGlobalBuffer, kOpSetupGlobalBuffer,
-                    LocalNativeBufferHandle(DvrGlobalBufferKey key, size_t size,
-                                            uint64_t usage));
-  PDX_REMOTE_METHOD(DeleteGlobalBuffer, kOpDeleteGlobalBuffer,
-                    void(DvrGlobalBufferKey key));
-  PDX_REMOTE_METHOD(GetGlobalBuffer, kOpGetGlobalBuffer,
-                    LocalNativeBufferHandle(DvrGlobalBufferKey key));
-  PDX_REMOTE_METHOD(IsVrAppRunning, kOpIsVrAppRunning, bool(Void));
-  PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface,
-                    SurfaceInfo(const SurfaceAttributes& attributes));
-  PDX_REMOTE_METHOD(GetSurfaceInfo, kOpGetSurfaceInfo, SurfaceInfo(Void));
-  PDX_REMOTE_METHOD(
-      CreateQueue, kOpCreateQueue,
-      LocalChannelHandle(const ProducerQueueConfig& producer_config));
-  PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes,
-                    void(const SurfaceAttributes& attributes));
-};
-
-struct DisplayManagerProtocol {
-  // Service path.
-  static constexpr char kClientPath[] = "system/vr/display/manager";
-
-  // Op codes.
-  enum {
-    kOpGetSurfaceState = 0,
-    kOpGetSurfaceQueue,
-  };
-
-  // Aliases.
-  using LocalChannelHandle = pdx::LocalChannelHandle;
-  using Void = pdx::rpc::Void;
-
-  // Methods.
-  PDX_REMOTE_METHOD(GetSurfaceState, kOpGetSurfaceState,
-                    std::vector<SurfaceState>(Void));
-  PDX_REMOTE_METHOD(GetSurfaceQueue, kOpGetSurfaceQueue,
-                    LocalChannelHandle(int surface_id, int queue_id));
-};
-
-struct VSyncSchedInfo {
-  int64_t vsync_period_ns;
-  int64_t timestamp_ns;
-  uint32_t next_vsync_count;
-
- private:
-  PDX_SERIALIZABLE_MEMBERS(VSyncSchedInfo, vsync_period_ns, timestamp_ns,
-                           next_vsync_count);
-};
-
-struct VSyncProtocol {
-  // Service path.
-  static constexpr char kClientPath[] = "system/vr/display/vsync";
-
-  // Op codes.
-  enum {
-    kOpWait = 0,
-    kOpAck,
-    kOpGetLastTimestamp,
-    kOpGetSchedInfo,
-    kOpAcknowledge,
-  };
-
-  // Aliases.
-  using Void = pdx::rpc::Void;
-  using Timestamp = int64_t;
-
-  // Methods.
-  PDX_REMOTE_METHOD(Wait, kOpWait, Timestamp(Void));
-  PDX_REMOTE_METHOD(GetLastTimestamp, kOpGetLastTimestamp, Timestamp(Void));
-  PDX_REMOTE_METHOD(GetSchedInfo, kOpGetSchedInfo, VSyncSchedInfo(Void));
-  PDX_REMOTE_METHOD(Acknowledge, kOpAcknowledge, void(Void));
-};
-
-}  // namespace display
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_DISPLAY_PROTOCOL_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h b/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
deleted file mode 100644
index 20541a6..0000000
--- a/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
+++ /dev/null
@@ -1,146 +0,0 @@
-#ifndef ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
-#define ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
-
-#include <assert.h>
-#include <tuple>
-
-#include <libbroadcastring/broadcast_ring.h>
-#include <private/dvr/display_client.h>
-
-namespace android {
-namespace dvr {
-
-// The buffer usage type for mapped shared buffers.
-enum class CPUUsageMode { READ_OFTEN, READ_RARELY, WRITE_OFTEN, WRITE_RARELY };
-
-// Holds the memory for the mapped shared buffer. Unlocks and releases the
-// underlying IonBuffer in destructor.
-class CPUMappedBuffer {
- public:
-  // This constructor will create a display client and get the buffer from it.
-  CPUMappedBuffer(DvrGlobalBufferKey key, CPUUsageMode mode);
-
-  // If you already have the IonBuffer, use this. It will take ownership.
-  CPUMappedBuffer(std::unique_ptr<IonBuffer> buffer, CPUUsageMode mode);
-
-  // Use this if you do not want to take ownership.
-  CPUMappedBuffer(IonBuffer* buffer, CPUUsageMode mode);
-
-  ~CPUMappedBuffer();
-
-  // Getters.
-  size_t Size() const { return size_; }
-  void* Address() const { return address_; }
-  bool IsMapped() const { return Address() != nullptr; }
-
-  // Attempt mapping this buffer to the CPU addressable space.
-  // This will create a display client and see if the buffer exists.
-  // If the buffer has not been setup yet, you will need to try again later.
-  void TryMapping();
-
- protected:
-  // The memory area if we managed to map it.
-  size_t size_ = 0;
-  void* address_ = nullptr;
-
-  // If we are polling the display client, the buffer key here.
-  DvrGlobalBufferKey buffer_key_;
-
-  // If we just own the IonBuffer outright, it's here.
-  std::unique_ptr<IonBuffer> owned_buffer_ = nullptr;
-
-  // The last time we connected to the display service.
-  int64_t last_display_service_connection_ns_ = 0;
-
-  // If we do not own the IonBuffer, it's here
-  IonBuffer* buffer_ = nullptr;
-
-  // The usage mode.
-  CPUUsageMode usage_mode_ = CPUUsageMode::READ_OFTEN;
-};
-
-// Represents a broadcast ring inside a mapped shared memory buffer.
-// If has the same set of constructors as CPUMappedBuffer.
-// The template argument is the concrete BroadcastRing class that this buffer
-// holds.
-template <class RingType>
-class CPUMappedBroadcastRing : public CPUMappedBuffer {
- public:
-  CPUMappedBroadcastRing(DvrGlobalBufferKey key, CPUUsageMode mode)
-      : CPUMappedBuffer(key, mode) {}
-
-  CPUMappedBroadcastRing(std::unique_ptr<IonBuffer> buffer, CPUUsageMode mode)
-      : CPUMappedBuffer(std::move(buffer), mode) {}
-
-  CPUMappedBroadcastRing(IonBuffer* buffer, CPUUsageMode mode)
-      : CPUMappedBuffer(buffer, mode) {}
-
-  // Helper function for publishing records in the ring.
-  void Publish(const typename RingType::Record& record) {
-    assert((usage_mode_ == CPUUsageMode::WRITE_OFTEN) ||
-           (usage_mode_ == CPUUsageMode::WRITE_RARELY));
-
-    auto ring = Ring();
-    if (ring) {
-      ring->Put(record);
-    }
-  }
-
-  // Helper function for getting records from the ring.
-  // Returns true if we were able to retrieve the latest.
-  bool GetNewest(typename RingType::Record* record) {
-    assert((usage_mode_ == CPUUsageMode::READ_OFTEN) ||
-           (usage_mode_ == CPUUsageMode::READ_RARELY));
-
-    auto ring = Ring();
-    if (ring) {
-      return ring->GetNewest(&sequence_, record);
-    }
-
-    return false;
-  }
-
-  // Try obtaining the ring. If the named buffer has not been created yet, it
-  // will return nullptr.
-  RingType* Ring() {
-    // No ring created yet?
-    if (ring_ == nullptr) {
-      // Not mapped the memory yet?
-      if (IsMapped() == false) {
-        TryMapping();
-      }
-
-      // If have the memory mapped, allocate the ring.
-      if (IsMapped()) {
-        switch (usage_mode_) {
-          case CPUUsageMode::READ_OFTEN:
-          case CPUUsageMode::READ_RARELY: {
-            RingType ring;
-            bool import_ok;
-            std::tie(ring, import_ok) = RingType::Import(address_, size_);
-            if (import_ok) {
-              ring_ = std::make_unique<RingType>(ring);
-            }
-          } break;
-          case CPUUsageMode::WRITE_OFTEN:
-          case CPUUsageMode::WRITE_RARELY:
-            ring_ =
-                std::make_unique<RingType>(RingType::Create(address_, size_));
-            break;
-        }
-      }
-    }
-
-    return ring_.get();
-  }
-
- protected:
-  std::unique_ptr<RingType> ring_ = nullptr;
-
-  uint32_t sequence_ = 0;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/vsync_service.h b/libs/vr/libdisplay/include/private/dvr/vsync_service.h
deleted file mode 100644
index 152464a..0000000
--- a/libs/vr/libdisplay/include/private/dvr/vsync_service.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef ANDROID_DVR_VSYNC_SERVICE_H_
-#define ANDROID_DVR_VSYNC_SERVICE_H_
-
-#include <binder/IInterface.h>
-
-namespace android {
-namespace dvr {
-
-class IVsyncCallback : public IInterface {
- public:
-  DECLARE_META_INTERFACE(VsyncCallback)
-
-  enum {
-    ON_VSYNC = IBinder::FIRST_CALL_TRANSACTION
-  };
-
-  virtual status_t onVsync(int64_t vsync_timestamp) = 0;
-};
-
-class BnVsyncCallback : public BnInterface<IVsyncCallback> {
- public:
-  virtual status_t onTransact(uint32_t code, const Parcel& data,
-                              Parcel* reply, uint32_t flags = 0);
-};
-
-// Register a callback with IVsyncService to be notified of vsync events and
-// timestamps. There's also a shared memory vsync buffer defined in
-// dvr_shared_buffers.h. IVsyncService has advantages over the vsync shared
-// memory buffer that make it preferable in certain situations:
-//
-// 1. The shared memory buffer lifetime is controlled by VrCore. IVsyncService
-// is always available as long as surface flinger is running.
-//
-// 2. IVsyncService will make a binder callback when a vsync event occurs. This
-// allows the client to not write code to implement periodic "get the latest
-// vsync" calls, which is necessary with the vsync shared memory buffer.
-//
-// 3. The IVsyncService provides the real vsync timestamp reported by hardware
-// composer, whereas the vsync shared memory buffer only has predicted vsync
-// times.
-class IVsyncService : public IInterface {
-public:
-  DECLARE_META_INTERFACE(VsyncService)
-
-  static const char* GetServiceName() { return "vrflinger_vsync"; }
-
-  enum {
-    REGISTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
-    UNREGISTER_CALLBACK
-  };
-
-  virtual status_t registerCallback(const sp<IVsyncCallback> callback) = 0;
-  virtual status_t unregisterCallback(const sp<IVsyncCallback> callback) = 0;
-};
-
-class BnVsyncService : public BnInterface<IVsyncService> {
- public:
-  virtual status_t onTransact(uint32_t code, const Parcel& data,
-                              Parcel* reply, uint32_t flags = 0);
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_VSYNC_SERVICE_H_
diff --git a/libs/vr/libdisplay/shared_buffer_helpers.cpp b/libs/vr/libdisplay/shared_buffer_helpers.cpp
deleted file mode 100644
index 6ebf487..0000000
--- a/libs/vr/libdisplay/shared_buffer_helpers.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-#include <private/dvr/clock_ns.h>
-#include <private/dvr/shared_buffer_helpers.h>
-
-namespace android {
-namespace dvr {
-namespace {
-
-// We will not poll the display service for buffers more frequently than this.
-constexpr size_t kDisplayServiceTriesPerSecond = 2;
-}  // namespace
-
-CPUMappedBuffer::CPUMappedBuffer(DvrGlobalBufferKey key, CPUUsageMode mode)
-    : buffer_key_(key), usage_mode_(mode) {
-  TryMapping();
-}
-
-CPUMappedBuffer::CPUMappedBuffer(std::unique_ptr<IonBuffer> buffer,
-                                 CPUUsageMode mode)
-    : owned_buffer_(std::move(buffer)),
-      buffer_(owned_buffer_.get()),
-      usage_mode_(mode) {
-  TryMapping();
-}
-
-CPUMappedBuffer::CPUMappedBuffer(IonBuffer* buffer, CPUUsageMode mode)
-    : buffer_(buffer), usage_mode_(mode) {
-  TryMapping();
-}
-
-CPUMappedBuffer::~CPUMappedBuffer() {
-  if (IsMapped()) {
-    buffer_->Unlock();
-  }
-}
-
-void CPUMappedBuffer::TryMapping() {
-  // Do we have an IonBuffer for this shared memory object?
-  if (buffer_ == nullptr) {
-    // Has it been too long since we last connected to the display service?
-    const auto current_time_ns = GetSystemClockNs();
-    if ((current_time_ns - last_display_service_connection_ns_) <
-        (1e9 / kDisplayServiceTriesPerSecond)) {
-      // Early exit.
-      return;
-    }
-    last_display_service_connection_ns_ = current_time_ns;
-
-    // Create a display client and get the buffer.
-    auto display_client = display::DisplayClient::Create();
-    if (display_client) {
-      auto get_result = display_client->GetGlobalBuffer(buffer_key_);
-      if (get_result.ok()) {
-        owned_buffer_ = get_result.take();
-        buffer_ = owned_buffer_.get();
-      } else {
-        // The buffer has not been created yet. This is OK, we will keep
-        // retrying.
-      }
-    } else {
-      ALOGE("Unable to create display client for shared buffer access");
-    }
-  }
-
-  if (buffer_) {
-    auto usage = buffer_->usage() & ~GRALLOC_USAGE_SW_READ_MASK &
-                 ~GRALLOC_USAGE_SW_WRITE_MASK;
-
-    // Figure out the usage bits.
-    switch (usage_mode_) {
-      case CPUUsageMode::READ_OFTEN:
-        usage |= GRALLOC_USAGE_SW_READ_OFTEN;
-        break;
-      case CPUUsageMode::READ_RARELY:
-        usage |= GRALLOC_USAGE_SW_READ_RARELY;
-        break;
-      case CPUUsageMode::WRITE_OFTEN:
-        usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
-        break;
-      case CPUUsageMode::WRITE_RARELY:
-        usage |= GRALLOC_USAGE_SW_WRITE_RARELY;
-        break;
-    }
-
-    int width = static_cast<int>(buffer_->width());
-    int height = 1;
-    const auto ret = buffer_->Lock(usage, 0, 0, width, height, &address_);
-
-    if (ret < 0 || !address_) {
-      ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, address_);
-      buffer_->Unlock();
-    } else {
-      size_ = width;
-    }
-  }
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libdisplay/system/CPPLINT.cfg b/libs/vr/libdisplay/system/CPPLINT.cfg
deleted file mode 100644
index 2f8a3c0..0000000
--- a/libs/vr/libdisplay/system/CPPLINT.cfg
+++ /dev/null
@@ -1 +0,0 @@
-filter=-build/header_guard
diff --git a/libs/vr/libdisplay/vsync_service.cpp b/libs/vr/libdisplay/vsync_service.cpp
deleted file mode 100644
index 04d4f30..0000000
--- a/libs/vr/libdisplay/vsync_service.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-#include "include/private/dvr/vsync_service.h"
-
-#include <binder/Parcel.h>
-#include <log/log.h>
-
-namespace android {
-namespace dvr {
-
-status_t BnVsyncCallback::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
-  switch (code) {
-    case ON_VSYNC: {
-      CHECK_INTERFACE(IVsyncCallback, data, reply);
-      int64_t vsync_timestamp = 0;
-      status_t result = data.readInt64(&vsync_timestamp);
-      if (result != OK) {
-        ALOGE("onVsync failed to readInt64: %d", result);
-        return result;
-      }
-      onVsync(vsync_timestamp);
-      return OK;
-    }
-    default: {
-      return BBinder::onTransact(code, data, reply, flags);
-    }
-  }
-}
-
-class BpVsyncCallback : public BpInterface<IVsyncCallback> {
-public:
-  explicit BpVsyncCallback(const sp<IBinder>& impl)
-      : BpInterface<IVsyncCallback>(impl) {}
-  virtual ~BpVsyncCallback() {}
-
-  virtual status_t onVsync(int64_t vsync_timestamp) {
-    Parcel data, reply;
-    status_t result = data.writeInterfaceToken(
-        IVsyncCallback::getInterfaceDescriptor());
-    if (result != OK) {
-      ALOGE("onVsync failed to writeInterfaceToken: %d", result);
-      return result;
-    }
-    result = data.writeInt64(vsync_timestamp);
-    if (result != OK) {
-      ALOGE("onVsync failed to writeInt64: %d", result);
-      return result;
-    }
-    result = remote()->transact(BnVsyncCallback::ON_VSYNC, data, &reply,
-                                IBinder::FLAG_ONEWAY);
-    if (result != OK) {
-      ALOGE("onVsync failed to transact: %d", result);
-      return result;
-    }
-    return result;
-  }
-};
-
-IMPLEMENT_META_INTERFACE(VsyncCallback, "android.dvr.IVsyncCallback");
-
-
-status_t BnVsyncService::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
-  switch (code) {
-    case REGISTER_CALLBACK: {
-      CHECK_INTERFACE(IVsyncService, data, reply);
-      sp<IBinder> callback;
-      status_t result = data.readStrongBinder(&callback);
-      if (result != OK) {
-        ALOGE("registerCallback failed to readStrongBinder: %d", result);
-        return result;
-      }
-      registerCallback(interface_cast<IVsyncCallback>(callback));
-      return OK;
-    }
-    case UNREGISTER_CALLBACK: {
-      CHECK_INTERFACE(IVsyncService, data, reply);
-      sp<IBinder> callback;
-      status_t result = data.readStrongBinder(&callback);
-      if (result != OK) {
-        ALOGE("unregisterCallback failed to readStrongBinder: %d", result);
-        return result;
-      }
-      unregisterCallback(interface_cast<IVsyncCallback>(callback));
-      return OK;
-    }
-    default: {
-      return BBinder::onTransact(code, data, reply, flags);
-    }
-  }
-}
-
-class BpVsyncService : public BpInterface<IVsyncService> {
-public:
-  explicit BpVsyncService(const sp<IBinder>& impl)
-      : BpInterface<IVsyncService>(impl) {}
-  virtual ~BpVsyncService() {}
-
-  virtual status_t registerCallback(const sp<IVsyncCallback> callback) {
-    Parcel data, reply;
-    status_t result = data.writeInterfaceToken(
-        IVsyncService::getInterfaceDescriptor());
-    if (result != OK) {
-      ALOGE("registerCallback failed to writeInterfaceToken: %d", result);
-      return result;
-    }
-    result = data.writeStrongBinder(IInterface::asBinder(callback));
-    if (result != OK) {
-      ALOGE("registerCallback failed to writeStrongBinder: %d", result);
-      return result;
-    }
-    result = remote()->transact(
-        BnVsyncService::REGISTER_CALLBACK, data, &reply);
-    if (result != OK) {
-      ALOGE("registerCallback failed to transact: %d", result);
-      return result;
-    }
-    return result;
-  }
-
-  virtual status_t unregisterCallback(const sp<IVsyncCallback> callback) {
-    Parcel data, reply;
-    status_t result = data.writeInterfaceToken(
-        IVsyncService::getInterfaceDescriptor());
-    if (result != OK) {
-      ALOGE("unregisterCallback failed to writeInterfaceToken: %d", result);
-      return result;
-    }
-    result = data.writeStrongBinder(IInterface::asBinder(callback));
-    if (result != OK) {
-      ALOGE("unregisterCallback failed to writeStrongBinder: %d", result);
-      return result;
-    }
-    result = remote()->transact(
-        BnVsyncService::UNREGISTER_CALLBACK, data, &reply);
-    if (result != OK) {
-      ALOGE("unregisterCallback failed to transact: %d", result);
-      return result;
-    }
-    return result;
-  }
-};
-
-IMPLEMENT_META_INTERFACE(VsyncService, "android.dvr.IVsyncService");
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 96023dd..9dbeacb 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -33,87 +33,3 @@
     ],
     min_sdk_version: "29",
 }
-
-cc_library_headers {
-    name: "libdvr_private_headers",
-    export_include_dirs: ["."],
-    vendor_available: false,
-}
-
-cflags = [
-    "-DDVR_TRACKING_IMPLEMENTED=0",
-    "-DLOG_TAG=\"libdvr\"",
-    "-DTRACE=0",
-    "-Wall",
-    "-Werror",
-]
-
-srcs = [
-    "dvr_api.cpp",
-    "dvr_buffer.cpp",
-    "dvr_buffer_queue.cpp",
-    "dvr_configuration_data.cpp",
-    "dvr_display_manager.cpp",
-    "dvr_hardware_composer_client.cpp",
-    "dvr_performance.cpp",
-    "dvr_pose.cpp",
-    "dvr_surface.cpp",
-    "dvr_tracking.cpp",
-]
-
-static_libs = [
-    "libbroadcastring",
-    "libvrsensor",
-    "libdisplay",
-    "libvirtualtouchpadclient",
-    "libvr_hwc-impl",
-    "libvr_hwc-binder",
-    "libgrallocusage",
-    "libperformance",
-]
-
-shared_libs = [
-    "android.hardware.graphics.bufferqueue@1.0",
-    "android.hidl.token@1.0-utils",
-    "libbase",
-    "libbufferhubqueue",
-    "libbinder",
-    "liblog",
-    "libcutils",
-    "libutils",
-    "libnativewindow",
-    "libgui",
-    "libui",
-    "libpdx_default_transport",
-]
-
-cc_library_shared {
-    name: "libdvr.google",
-    system_ext_specific: true,
-    owner: "google",
-    cflags: cflags,
-    header_libs: ["libdvr_headers"],
-    export_header_lib_headers: ["libdvr_headers"],
-    srcs: srcs,
-    static_libs: static_libs,
-    shared_libs: shared_libs,
-    version_script: "exported_apis.lds",
-}
-
-// Also build a static libdvr for linking into tests. The linker script
-// restricting function access in the shared lib makes it inconvenient to use in
-// test code.
-cc_library_static {
-    name: "libdvr_static.google",
-    owner: "google",
-    cflags: cflags,
-    header_libs: ["libdvr_headers"],
-    export_header_lib_headers: ["libdvr_headers"],
-    srcs: srcs,
-    static_libs: static_libs,
-    shared_libs: shared_libs,
-}
-
-subdirs = [
-    "tests",
-]
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
deleted file mode 100644
index e099f6a..0000000
--- a/libs/vr/libdvr/dvr_api.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "include/dvr/dvr_api.h"
-
-#include <errno.h>
-#include <utils/Log.h>
-
-#include <algorithm>
-
-// Headers from libdvr
-#include <dvr/dvr_buffer.h>
-#include <dvr/dvr_buffer_queue.h>
-#include <dvr/dvr_configuration_data.h>
-#include <dvr/dvr_display_manager.h>
-#include <dvr/dvr_performance.h>
-#include <dvr/dvr_surface.h>
-#include <dvr/dvr_tracking.h>
-#include <dvr/dvr_vsync.h>
-
-// Headers not yet moved into libdvr.
-// TODO(jwcai) Move these once their callers are moved into Google3.
-#include <dvr/dvr_hardware_composer_client.h>
-#include <dvr/pose_client.h>
-#include <dvr/virtual_touchpad_client.h>
-
-extern "C" {
-
-int dvrGetApi(void* api, size_t struct_size, int version) {
-  ALOGI("dvrGetApi: api=%p struct_size=%zu version=%d", api, struct_size,
-        version);
-  if (version == 1) {
-    // New entry points are added at the end. If the caller's struct and
-    // this library have different sizes, we define the entry points in common.
-    // The caller is expected to handle unset entry points if necessary.
-    size_t clamped_struct_size = std::min(struct_size, sizeof(DvrApi_v1));
-    DvrApi_v1* dvr_api = static_cast<DvrApi_v1*>(api);
-
-// Defines an API entry for V1 (no version suffix).
-#define DVR_V1_API_ENTRY(name)                                 \
-  do {                                                         \
-    if ((offsetof(DvrApi_v1, name) + sizeof(dvr_api->name)) <= \
-        clamped_struct_size) {                                 \
-      dvr_api->name = dvr##name;                               \
-    }                                                          \
-  } while (0)
-
-#define DVR_V1_API_ENTRY_DEPRECATED(name)                      \
-  do {                                                         \
-    if ((offsetof(DvrApi_v1, name) + sizeof(dvr_api->name)) <= \
-        clamped_struct_size) {                                 \
-      dvr_api->name = nullptr;                                 \
-    }                                                          \
-  } while (0)
-
-#include "include/dvr/dvr_api_entries.h"
-
-// Undefine macro definitions to play nice with Google3 style rules.
-#undef DVR_V1_API_ENTRY
-#undef DVR_V1_API_ENTRY_DEPRECATED
-
-    return 0;
-  }
-
-  ALOGE("dvrGetApi: Unknown API version=%d", version);
-  return -EINVAL;
-}
-
-}  // extern "C"
diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
deleted file mode 100644
index c11706f..0000000
--- a/libs/vr/libdvr/dvr_buffer.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-#include "include/dvr/dvr_buffer.h"
-
-#include <android/hardware_buffer.h>
-#include <dvr/dvr_shared_buffers.h>
-#include <private/dvr/consumer_buffer.h>
-#include <private/dvr/producer_buffer.h>
-#include <ui/GraphicBuffer.h>
-
-#include "dvr_internal.h"
-
-using namespace android;
-
-namespace android {
-namespace dvr {
-
-DvrBuffer* CreateDvrBufferFromIonBuffer(
-    const std::shared_ptr<IonBuffer>& ion_buffer) {
-  if (!ion_buffer)
-    return nullptr;
-  return new DvrBuffer{std::move(ion_buffer)};
-}
-
-}  // namespace dvr
-}  // namespace android
-
-namespace {
-
-int ConvertToAHardwareBuffer(GraphicBuffer* graphic_buffer,
-                             AHardwareBuffer** hardware_buffer) {
-  if (!hardware_buffer || !graphic_buffer) {
-    return -EINVAL;
-  }
-  *hardware_buffer = reinterpret_cast<AHardwareBuffer*>(graphic_buffer);
-  AHardwareBuffer_acquire(*hardware_buffer);
-  return 0;
-}
-
-}  // anonymous namespace
-
-extern "C" {
-
-void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer) {
-  if (write_buffer != nullptr) {
-    ALOGW_IF(
-        write_buffer->slot != -1,
-        "dvrWriteBufferDestroy: Destroying a buffer associated with a valid "
-        "buffer queue slot. This may indicate possible leaks, buffer_id=%d.",
-        dvrWriteBufferGetId(write_buffer));
-    delete write_buffer;
-  }
-}
-
-int dvrWriteBufferIsValid(DvrWriteBuffer* write_buffer) {
-  return write_buffer && write_buffer->write_buffer;
-}
-
-int dvrWriteBufferGetId(DvrWriteBuffer* write_buffer) {
-  if (!write_buffer || !write_buffer->write_buffer)
-    return -EINVAL;
-
-  return write_buffer->write_buffer->id();
-}
-
-int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* write_buffer,
-                                     AHardwareBuffer** hardware_buffer) {
-  if (!write_buffer || !write_buffer->write_buffer)
-    return -EINVAL;
-
-  return ConvertToAHardwareBuffer(
-      write_buffer->write_buffer->buffer()->buffer().get(), hardware_buffer);
-}
-
-void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) {
-  if (read_buffer != nullptr) {
-    ALOGW_IF(
-        read_buffer->slot != -1,
-        "dvrReadBufferDestroy: Destroying a buffer associated with a valid "
-        "buffer queue slot. This may indicate possible leaks, buffer_id=%d.",
-        dvrReadBufferGetId(read_buffer));
-    delete read_buffer;
-  }
-}
-
-int dvrReadBufferIsValid(DvrReadBuffer* read_buffer) {
-  return read_buffer && read_buffer->read_buffer;
-}
-
-int dvrReadBufferGetId(DvrReadBuffer* read_buffer) {
-  if (!read_buffer || !read_buffer->read_buffer)
-    return -EINVAL;
-
-  return read_buffer->read_buffer->id();
-}
-
-int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* read_buffer,
-                                    AHardwareBuffer** hardware_buffer) {
-  if (!read_buffer || !read_buffer->read_buffer)
-    return -EINVAL;
-
-  return ConvertToAHardwareBuffer(
-      read_buffer->read_buffer->buffer()->buffer().get(), hardware_buffer);
-}
-
-void dvrBufferDestroy(DvrBuffer* buffer) { delete buffer; }
-
-int dvrBufferGetAHardwareBuffer(DvrBuffer* buffer,
-                                AHardwareBuffer** hardware_buffer) {
-  if (!buffer || !buffer->buffer || !hardware_buffer) {
-    return -EINVAL;
-  }
-
-  return ConvertToAHardwareBuffer(buffer->buffer->buffer().get(),
-                                  hardware_buffer);
-}
-
-// Retrieve the shared buffer layout version defined in dvr_shared_buffers.h.
-int dvrBufferGlobalLayoutVersionGet() {
-  return android::dvr::kSharedBufferLayoutVersion;
-}
-
-}  // extern "C"
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
deleted file mode 100644
index 1ca653c..0000000
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ /dev/null
@@ -1,552 +0,0 @@
-#include "include/dvr/dvr_api.h"
-#include "include/dvr/dvr_buffer_queue.h"
-
-#include <android/native_window.h>
-#include <gui/BufferHubProducer.h>
-
-#include "dvr_internal.h"
-#include "dvr_buffer_queue_internal.h"
-
-using namespace android;
-using android::dvr::BufferHubBase;
-using android::dvr::ConsumerBuffer;
-using android::dvr::ConsumerQueue;
-using android::dvr::ProducerBuffer;
-using android::dvr::ProducerQueue;
-using android::dvr::ProducerQueueConfigBuilder;
-using android::dvr::UsagePolicy;
-
-extern "C" {
-
-DvrWriteBufferQueue::DvrWriteBufferQueue(
-    const std::shared_ptr<ProducerQueue>& producer_queue)
-    : producer_queue_(producer_queue),
-      width_(producer_queue->default_width()),
-      height_(producer_queue->default_height()),
-      format_(producer_queue->default_format()) {}
-
-int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) {
-  if (native_window_ == nullptr) {
-    // Lazy creation of |native_window|, as not everyone is using
-    // DvrWriteBufferQueue as an external surface.
-    sp<IGraphicBufferProducer> gbp = BufferHubProducer::Create(producer_queue_);
-    native_window_ = new Surface(gbp, true);
-  }
-
-  *out_window = static_cast<ANativeWindow*>(native_window_.get());
-  return 0;
-}
-
-int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
-  std::unique_ptr<ConsumerQueue> consumer_queue =
-      producer_queue_->CreateConsumerQueue();
-  if (consumer_queue == nullptr) {
-    ALOGE(
-        "DvrWriteBufferQueue::CreateReadQueue: Failed to create consumer queue "
-        "from producer queue: queue_id=%d.", producer_queue_->id());
-    return -ENOMEM;
-  }
-
-  *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
-  return 0;
-}
-
-int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,
-                                 int* out_fence_fd) {
-  DvrNativeBufferMetadata meta;
-  DvrWriteBuffer* buffer = nullptr;
-  int fence_fd = -1;
-  if (const int ret = GainBuffer(timeout, &buffer, &meta, &fence_fd))
-    return ret;
-  if (!buffer)
-    return -ENOMEM;
-
-  write_buffers_[buffer->slot].reset(buffer);
-  write_buffer->write_buffer = std::move(buffer->write_buffer);
-  *out_fence_fd = fence_fd;
-  return 0;
-}
-
-int DvrWriteBufferQueue::GainBuffer(int timeout,
-                                    DvrWriteBuffer** out_write_buffer,
-                                    DvrNativeBufferMetadata* out_meta,
-                                    int* out_fence_fd) {
-  size_t slot;
-  pdx::LocalHandle release_fence;
-
-  // Need to retry N+1 times, where N is total number of buffers in the queue.
-  // As in the worst case, we will dequeue all N buffers and reallocate them, on
-  // the {N+1}th dequeue, we are guaranteed to get a buffer with new dimension.
-  size_t max_retries = 1 + producer_queue_->capacity();
-  size_t retry = 0;
-
-  for (; retry < max_retries; retry++) {
-    auto buffer_status =
-        producer_queue_->Dequeue(timeout, &slot, out_meta, &release_fence);
-    if (!buffer_status) {
-      ALOGE_IF(buffer_status.error() != ETIMEDOUT,
-               "DvrWriteBufferQueue::GainBuffer: Failed to dequeue buffer: %s",
-               buffer_status.GetErrorMessage().c_str());
-      return -buffer_status.error();
-    }
-
-    if (write_buffers_[slot] == nullptr) {
-      // Lazy initialization of a write_buffers_ slot. Note that a slot will
-      // only be dynamically allocated once during the entire cycle life of a
-      // queue.
-      write_buffers_[slot] = std::make_unique<DvrWriteBuffer>();
-      write_buffers_[slot]->slot = slot;
-    }
-
-    LOG_ALWAYS_FATAL_IF(
-        write_buffers_[slot]->write_buffer,
-        "DvrWriteBufferQueue::GainBuffer: Buffer slot is not empty: %zu", slot);
-    write_buffers_[slot]->write_buffer = std::move(buffer_status.take());
-
-    const auto& producer_buffer = write_buffers_[slot]->write_buffer;
-    if (!producer_buffer)
-      return -ENOMEM;
-
-    if (width_ == producer_buffer->width() &&
-        height_ == producer_buffer->height() &&
-        format_ == producer_buffer->format()) {
-      // Producer queue returns a buffer matches the current request.
-      break;
-    }
-
-    // Needs reallocation. Note that if there are already multiple available
-    // buffers in the queue, the next one returned from |queue_->Dequeue| may
-    // still have the old buffer dimension or format. Retry up to N+1 times or
-    // until we dequeued a buffer with new configuration.
-    ALOGD_IF(TRACE,
-             "DvrWriteBufferQueue::Dequeue: requested buffer at slot: %zu "
-             "(w=%u, h=%u, fmt=%u) is different from the buffer returned "
-             "(w=%u, h=%u, fmt=%u). Need re-allocation.",
-             slot, width_, height_, format_, producer_buffer->width(),
-             producer_buffer->height(), producer_buffer->format());
-
-    // Currently, we are not storing |layer_count| and |usage| in queue
-    // configuration. Copy those setup from the last buffer dequeued before we
-    // remove it.
-    uint32_t old_layer_count = producer_buffer->layer_count();
-    uint64_t old_usage = producer_buffer->usage();
-
-    // Allocate a new producer buffer with new buffer configs. Note that if
-    // there are already multiple available buffers in the queue, the next one
-    // returned from |queue_->Dequeue| may still have the old buffer dimension
-    // or format. Retry up to BufferHubQueue::kMaxQueueCapacity times or until
-    // we dequeued a buffer with new configuration.
-    auto remove_status = producer_queue_->RemoveBuffer(slot);
-    if (!remove_status) {
-      ALOGE("DvrWriteBufferQueue::Dequeue: Failed to remove buffer: %s",
-            remove_status.GetErrorMessage().c_str());
-      return -remove_status.error();
-    }
-    // Make sure that the previously allocated buffer is dereferenced from
-    // write_buffers_ array.
-    write_buffers_[slot]->write_buffer = nullptr;
-
-    auto allocate_status = producer_queue_->AllocateBuffer(
-        width_, height_, old_layer_count, format_, old_usage);
-    if (!allocate_status) {
-      ALOGE("DvrWriteBufferQueue::Dequeue: Failed to allocate buffer: %s",
-            allocate_status.GetErrorMessage().c_str());
-      return -allocate_status.error();
-    }
-  }
-
-  if (retry >= max_retries) {
-    ALOGE(
-        "DvrWriteBufferQueue::Dequeue: Failed to re-allocate buffer after "
-        "resizing.");
-    return -ENOMEM;
-  }
-
-  *out_write_buffer = write_buffers_[slot].release();
-  *out_fence_fd = release_fence.Release();
-
-  return 0;
-}
-
-int DvrWriteBufferQueue::PostBuffer(DvrWriteBuffer* write_buffer,
-                                    const DvrNativeBufferMetadata* meta,
-                                    int ready_fence_fd) {
-  // Some basic sanity checks before we put the buffer back into a slot.
-  size_t slot = static_cast<size_t>(write_buffer->slot);
-  LOG_FATAL_IF(
-      (write_buffers->slot < 0 || write_buffers->slot >= write_buffers_.size()),
-      "DvrWriteBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
-
-  if (write_buffers_[slot] != nullptr) {
-    ALOGE("DvrWriteBufferQueue::PostBuffer: Slot is not empty: %zu", slot);
-    return -EINVAL;
-  }
-  if (write_buffer->write_buffer == nullptr) {
-    ALOGE("DvrWriteBufferQueue::PostBuffer: Invalid write buffer.");
-    return -EINVAL;
-  }
-  if (write_buffer->write_buffer->id() != producer_queue_->GetBufferId(slot)) {
-    ALOGE(
-        "DvrWriteBufferQueue::PostBuffer: Buffer to be posted does not "
-        "belong to this buffer queue. Posting buffer: id=%d, buffer in "
-        "queue: id=%d",
-        write_buffer->write_buffer->id(), producer_queue_->GetBufferId(slot));
-    return -EINVAL;
-  }
-
-  write_buffer->write_buffer->SetQueueIndex(next_post_index_++);
-  pdx::LocalHandle fence(ready_fence_fd);
-  const int ret = write_buffer->write_buffer->PostAsync(meta, fence);
-  if (ret < 0) {
-    ALOGE("DvrWriteBufferQueue::PostBuffer: Failed to post buffer, ret=%d",
-          ret);
-    return ret;
-  }
-
-  // Put the DvrWriteBuffer pointer back into its slot for reuse.
-  write_buffers_[slot].reset(write_buffer);
-  // It's import to reset the write buffer client now. It should stay invalid
-  // until next GainBuffer on the same slot.
-  write_buffers_[slot]->write_buffer = nullptr;
-  return 0;
-}
-
-int DvrWriteBufferQueue::ResizeBuffer(uint32_t width, uint32_t height) {
-  if (width == 0 || height == 0) {
-    ALOGE(
-        "DvrWriteBufferQueue::ResizeBuffer: invalid buffer dimension: w=%u, "
-        "h=%u.",
-        width, height);
-    return -EINVAL;
-  }
-
-  width_ = width;
-  height_ = height;
-  return 0;
-}
-
-int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format,
-                              uint32_t layer_count, uint64_t usage,
-                              size_t capacity, size_t metadata_size,
-                              DvrWriteBufferQueue** out_write_queue) {
-  if (!out_write_queue)
-    return -EINVAL;
-
-  auto config_builder = ProducerQueueConfigBuilder()
-                            .SetDefaultWidth(width)
-                            .SetDefaultHeight(height)
-                            .SetDefaultFormat(format)
-                            .SetMetadataSize(metadata_size);
-  std::unique_ptr<ProducerQueue> producer_queue =
-      ProducerQueue::Create(config_builder.Build(), UsagePolicy{});
-  if (!producer_queue) {
-    ALOGE("dvrWriteBufferQueueCreate: Failed to create producer queue.");
-    return -ENOMEM;
-  }
-
-  auto status = producer_queue->AllocateBuffers(width, height, layer_count,
-                                                format, usage, capacity);
-  if (!status.ok()) {
-    ALOGE("dvrWriteBufferQueueCreate: Failed to allocate buffers.");
-    return -ENOMEM;
-  }
-
-  *out_write_queue = new DvrWriteBufferQueue(std::move(producer_queue));
-  return 0;
-}
-
-void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
-  delete write_queue;
-}
-
-ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
-  if (!write_queue)
-    return -EINVAL;
-
-  return write_queue->capacity();
-}
-
-int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) {
-  if (!write_queue)
-    return -EINVAL;
-
-  return write_queue->id();
-}
-
-int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue,
-                                        ANativeWindow** out_window) {
-  if (!write_queue || !out_window)
-    return -EINVAL;
-
-  return write_queue->GetNativeWindow(out_window);
-}
-
-int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
-                                       DvrReadBufferQueue** out_read_queue) {
-  if (!write_queue || !out_read_queue)
-    return -EINVAL;
-
-  return write_queue->CreateReadQueue(out_read_queue);
-}
-
-int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout,
-                                  DvrWriteBuffer** out_write_buffer,
-                                  DvrNativeBufferMetadata* out_meta,
-                                  int* out_fence_fd) {
-  if (!write_queue || !out_write_buffer || !out_meta || !out_fence_fd)
-    return -EINVAL;
-
-  return write_queue->GainBuffer(timeout, out_write_buffer, out_meta,
-                                 out_fence_fd);
-}
-
-int dvrWriteBufferQueuePostBuffer(DvrWriteBufferQueue* write_queue,
-                                  DvrWriteBuffer* write_buffer,
-                                  const DvrNativeBufferMetadata* meta,
-                                  int ready_fence_fd) {
-  if (!write_queue || !write_buffer || !write_buffer->write_buffer || !meta)
-    return -EINVAL;
-
-  return write_queue->PostBuffer(write_buffer, meta, ready_fence_fd);
-}
-
-int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
-                                    uint32_t width, uint32_t height) {
-  if (!write_queue)
-    return -EINVAL;
-
-  return write_queue->ResizeBuffer(width, height);
-}
-
-// ReadBufferQueue
-
-DvrReadBufferQueue::DvrReadBufferQueue(
-    const std::shared_ptr<ConsumerQueue>& consumer_queue)
-    : consumer_queue_(consumer_queue) {}
-
-int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
-  std::unique_ptr<ConsumerQueue> consumer_queue =
-      consumer_queue_->CreateConsumerQueue();
-  if (consumer_queue == nullptr) {
-    ALOGE(
-        "DvrReadBufferQueue::CreateReadQueue: Failed to create consumer queue "
-        "from producer queue: queue_id=%d.", consumer_queue_->id());
-    return -ENOMEM;
-  }
-
-  *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
-  return 0;
-}
-
-int DvrReadBufferQueue::AcquireBuffer(int timeout,
-                                      DvrReadBuffer** out_read_buffer,
-                                      DvrNativeBufferMetadata* out_meta,
-                                      int* out_fence_fd) {
-  size_t slot;
-  pdx::LocalHandle acquire_fence;
-  auto buffer_status =
-      consumer_queue_->Dequeue(timeout, &slot, out_meta, &acquire_fence);
-  if (!buffer_status) {
-    ALOGE_IF(buffer_status.error() != ETIMEDOUT,
-             "DvrReadBufferQueue::AcquireBuffer: Failed to dequeue buffer: %s",
-             buffer_status.GetErrorMessage().c_str());
-    return -buffer_status.error();
-  }
-
-  if (read_buffers_[slot] == nullptr) {
-    // Lazy initialization of a read_buffers_ slot. Note that a slot will only
-    // be dynamically allocated once during the entire cycle life of a queue.
-    read_buffers_[slot] = std::make_unique<DvrReadBuffer>();
-    read_buffers_[slot]->slot = slot;
-  }
-
-  LOG_FATAL_IF(
-      read_buffers_[slot]->read_buffer,
-      "DvrReadBufferQueue::AcquireBuffer: Buffer slot is not empty: %zu", slot);
-  read_buffers_[slot]->read_buffer = std::move(buffer_status.take());
-
-  *out_read_buffer = read_buffers_[slot].release();
-  *out_fence_fd = acquire_fence.Release();
-
-  return 0;
-}
-
-int DvrReadBufferQueue::ReleaseBuffer(DvrReadBuffer* read_buffer,
-                                      const DvrNativeBufferMetadata* meta,
-                                      int release_fence_fd) {
-  // Some basic sanity checks before we put the buffer back into a slot.
-  size_t slot = static_cast<size_t>(read_buffer->slot);
-  LOG_FATAL_IF(
-      (read_buffers->slot < 0 || read_buffers->slot >= read_buffers_size()),
-      "DvrReadBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
-
-  if (read_buffers_[slot] != nullptr) {
-    ALOGE("DvrReadBufferQueue::ReleaseBuffer: Slot is not empty: %zu", slot);
-    return -EINVAL;
-  }
-  if (read_buffer->read_buffer == nullptr) {
-    ALOGE("DvrReadBufferQueue::ReleaseBuffer: Invalid read buffer.");
-    return -EINVAL;
-  }
-  if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) {
-    if (consumer_queue_->GetBufferId(slot) > 0) {
-      ALOGE(
-          "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
-          "belong to this queue (queue_id=%d): attempting to release buffer "
-          "(buffer_id=%d) at slot %d which holds a different buffer "
-          "(buffer_id=%d).",
-          consumer_queue_->id(), read_buffer->read_buffer->id(),
-          static_cast<int>(slot), consumer_queue_->GetBufferId(slot));
-    } else {
-      ALOGI(
-          "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
-          "belong to this queue (queue_id=%d): attempting to release buffer "
-          "(buffer_id=%d) at slot %d which is empty.",
-          consumer_queue_->id(), read_buffer->read_buffer->id(),
-          static_cast<int>(slot));
-    }
-  }
-
-  pdx::LocalHandle fence(release_fence_fd);
-  int ret = read_buffer->read_buffer->ReleaseAsync(meta, fence);
-  if (ret < 0) {
-    ALOGE("DvrReadBufferQueue::ReleaseBuffer: Failed to release buffer, ret=%d",
-          ret);
-    return ret;
-  }
-
-  // Put the DvrReadBuffer pointer back into its slot for reuse.
-  read_buffers_[slot].reset(read_buffer);
-  // It's import to reset the read buffer client now. It should stay invalid
-  // until next AcquireBuffer on the same slot.
-  read_buffers_[slot]->read_buffer = nullptr;
-  return 0;
-}
-
-void DvrReadBufferQueue::SetBufferAvailableCallback(
-    DvrReadBufferQueueBufferAvailableCallback callback, void* context) {
-  if (callback == nullptr) {
-    consumer_queue_->SetBufferAvailableCallback(nullptr);
-  } else {
-    consumer_queue_->SetBufferAvailableCallback(
-        [callback, context]() { callback(context); });
-  }
-}
-
-void DvrReadBufferQueue::SetBufferRemovedCallback(
-    DvrReadBufferQueueBufferRemovedCallback callback, void* context) {
-  if (callback == nullptr) {
-    consumer_queue_->SetBufferRemovedCallback(nullptr);
-  } else {
-    consumer_queue_->SetBufferRemovedCallback(
-        [callback, context](const std::shared_ptr<BufferHubBase>& buffer) {
-          // When buffer is removed from the queue, the slot is already invalid.
-          auto read_buffer = std::make_unique<DvrReadBuffer>();
-          read_buffer->read_buffer =
-              std::static_pointer_cast<ConsumerBuffer>(buffer);
-          callback(read_buffer.release(), context);
-        });
-  }
-}
-
-int DvrReadBufferQueue::HandleEvents() {
-  // TODO(jwcai) Probably should change HandleQueueEvents to return Status.
-  consumer_queue_->HandleQueueEvents();
-  return 0;
-}
-
-void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
-  delete read_queue;
-}
-
-ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
-  if (!read_queue)
-    return -EINVAL;
-
-  return read_queue->capacity();
-}
-
-int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
-  if (!read_queue)
-    return -EINVAL;
-
-  return read_queue->id();
-}
-
-int dvrReadBufferQueueGetEventFd(DvrReadBufferQueue* read_queue) {
-  if (!read_queue)
-    return -EINVAL;
-
-  return read_queue->event_fd();
-}
-
-int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
-                                      DvrReadBufferQueue** out_read_queue) {
-  if (!read_queue || !out_read_queue)
-    return -EINVAL;
-
-  return read_queue->CreateReadQueue(out_read_queue);
-}
-
-int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
-                              DvrReadBuffer* read_buffer, int* out_fence_fd,
-                              void* out_meta, size_t meta_size_bytes) {
-  if (!read_queue || !read_buffer || !out_fence_fd)
-    return -EINVAL;
-
-  if (meta_size_bytes != 0 && !out_meta)
-    return -EINVAL;
-
-  return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
-                             meta_size_bytes);
-}
-
-int dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue* read_queue, int timeout,
-                                    DvrReadBuffer** out_read_buffer,
-                                    DvrNativeBufferMetadata* out_meta,
-                                    int* out_fence_fd) {
-  if (!read_queue || !out_read_buffer || !out_meta || !out_fence_fd)
-    return -EINVAL;
-
-  return read_queue->AcquireBuffer(timeout, out_read_buffer, out_meta,
-                                   out_fence_fd);
-}
-
-int dvrReadBufferQueueReleaseBuffer(DvrReadBufferQueue* read_queue,
-                                    DvrReadBuffer* read_buffer,
-                                    const DvrNativeBufferMetadata* meta,
-                                    int release_fence_fd) {
-  if (!read_queue || !read_buffer || !read_buffer->read_buffer || !meta)
-    return -EINVAL;
-
-  return read_queue->ReleaseBuffer(read_buffer, meta, release_fence_fd);
-}
-
-int dvrReadBufferQueueSetBufferAvailableCallback(
-    DvrReadBufferQueue* read_queue,
-    DvrReadBufferQueueBufferAvailableCallback callback, void* context) {
-  if (!read_queue)
-    return -EINVAL;
-
-  read_queue->SetBufferAvailableCallback(callback, context);
-  return 0;
-}
-
-int dvrReadBufferQueueSetBufferRemovedCallback(
-    DvrReadBufferQueue* read_queue,
-    DvrReadBufferQueueBufferRemovedCallback callback, void* context) {
-  if (!read_queue)
-    return -EINVAL;
-
-  read_queue->SetBufferRemovedCallback(callback, context);
-  return 0;
-}
-
-int dvrReadBufferQueueHandleEvents(DvrReadBufferQueue* read_queue) {
-  if (!read_queue)
-    return -EINVAL;
-
-  return read_queue->HandleEvents();
-}
-
-}  // extern "C"
diff --git a/libs/vr/libdvr/dvr_buffer_queue_internal.h b/libs/vr/libdvr/dvr_buffer_queue_internal.h
deleted file mode 100644
index e53a686..0000000
--- a/libs/vr/libdvr/dvr_buffer_queue_internal.h
+++ /dev/null
@@ -1,95 +0,0 @@
-#ifndef ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
-#define ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
-
-#include <gui/Surface.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <sys/cdefs.h>
-
-#include <array>
-#include <memory>
-
-#include "dvr_internal.h"
-
-struct ANativeWindow;
-
-typedef struct DvrNativeBufferMetadata DvrNativeBufferMetadata;
-typedef struct DvrReadBuffer DvrReadBuffer;
-typedef struct DvrReadBufferQueue DvrReadBufferQueue;
-typedef struct DvrWriteBuffer DvrWriteBuffer;
-typedef void (*DvrReadBufferQueueBufferAvailableCallback)(void* context);
-typedef void (*DvrReadBufferQueueBufferRemovedCallback)(DvrReadBuffer* buffer,
-                                                        void* context);
-
-struct DvrWriteBufferQueue {
-  using BufferHubQueue = android::dvr::BufferHubQueue;
-  using ProducerQueue = android::dvr::ProducerQueue;
-
-  // Create a concrete object for DvrWriteBufferQueue.
-  //
-  // @param producer_queue The BufferHub's ProducerQueue that is used to back
-  //     this DvrWriteBufferQueue, must not be NULL.
-  explicit DvrWriteBufferQueue(
-      const std::shared_ptr<ProducerQueue>& producer_queue);
-
-  int id() const { return producer_queue_->id(); }
-  uint32_t width() const { return width_; };
-  uint32_t height() const { return height_; };
-  uint32_t format() const { return format_; };
-  size_t capacity() const { return producer_queue_->capacity(); }
-  const std::shared_ptr<ProducerQueue>& producer_queue() const {
-    return producer_queue_;
-  }
-
-  int GetNativeWindow(ANativeWindow** out_window);
-  int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
-  int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd);
-  int GainBuffer(int timeout, DvrWriteBuffer** out_write_buffer,
-                 DvrNativeBufferMetadata* out_meta, int* out_fence_fd);
-  int PostBuffer(DvrWriteBuffer* write_buffer,
-                 const DvrNativeBufferMetadata* meta, int ready_fence_fd);
-  int ResizeBuffer(uint32_t width, uint32_t height);
-
- private:
-  std::shared_ptr<ProducerQueue> producer_queue_;
-  std::array<std::unique_ptr<DvrWriteBuffer>, BufferHubQueue::kMaxQueueCapacity>
-      write_buffers_;
-
-  int64_t next_post_index_ = 0;
-  uint32_t width_;
-  uint32_t height_;
-  uint32_t format_;
-
-  android::sp<android::Surface> native_window_;
-};
-
-struct DvrReadBufferQueue {
-  using BufferHubQueue = android::dvr::BufferHubQueue;
-  using ConsumerQueue = android::dvr::ConsumerQueue;
-
-  explicit DvrReadBufferQueue(
-      const std::shared_ptr<ConsumerQueue>& consumer_queue);
-
-  int id() const { return consumer_queue_->id(); }
-  int event_fd() const { return consumer_queue_->queue_fd(); }
-  size_t capacity() const { return consumer_queue_->capacity(); }
-
-  int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
-  int Dequeue(int timeout, DvrReadBuffer* read_buffer, int* out_fence_fd,
-              void* out_meta, size_t user_metadata_size);
-  int AcquireBuffer(int timeout, DvrReadBuffer** out_read_buffer,
-                    DvrNativeBufferMetadata* out_meta, int* out_fence_fd);
-  int ReleaseBuffer(DvrReadBuffer* read_buffer,
-                    const DvrNativeBufferMetadata* meta, int release_fence_fd);
-  void SetBufferAvailableCallback(
-      DvrReadBufferQueueBufferAvailableCallback callback, void* context);
-  void SetBufferRemovedCallback(
-      DvrReadBufferQueueBufferRemovedCallback callback, void* context);
-  int HandleEvents();
-
- private:
-  std::shared_ptr<ConsumerQueue> consumer_queue_;
-  std::array<std::unique_ptr<DvrReadBuffer>, BufferHubQueue::kMaxQueueCapacity>
-      read_buffers_;
-};
-
-#endif  // ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_configuration_data.cpp b/libs/vr/libdvr/dvr_configuration_data.cpp
deleted file mode 100644
index df0d54e..0000000
--- a/libs/vr/libdvr/dvr_configuration_data.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "include/dvr/dvr_configuration_data.h"
-
-#include <private/dvr/display_client.h>
-
-using android::dvr::display::ConfigFileType;
-using android::dvr::display::DisplayClient;
-
-extern "C" {
-
-int dvrConfigurationDataGet(int config_type, uint8_t** data,
-                            size_t* data_size) {
-  if (!data || !data_size) {
-    return -EINVAL;
-  }
-
-  auto client = DisplayClient::Create();
-  if (!client) {
-    ALOGE("dvrGetGlobalBuffer: Failed to create display client!");
-    return -ECOMM;
-  }
-
-  ConfigFileType config_file_type = static_cast<ConfigFileType>(config_type);
-  auto config_data_status =
-      client->GetConfigurationData(config_file_type);
-
-  if (!config_data_status) {
-    return -config_data_status.error();
-  }
-
-  *data_size = config_data_status.get().size();
-  *data = new uint8_t[*data_size];
-  std::copy_n(config_data_status.get().begin(), *data_size, *data);
-  return 0;
-}
-
-void dvrConfigurationDataDestroy(uint8_t* data) {
-  delete[] data;
-}
-
-}  // extern "C"
diff --git a/libs/vr/libdvr/dvr_display_manager.cpp b/libs/vr/libdvr/dvr_display_manager.cpp
deleted file mode 100644
index 7f631e3..0000000
--- a/libs/vr/libdvr/dvr_display_manager.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-#include "include/dvr/dvr_display_manager.h"
-
-#include <dvr/dvr_buffer.h>
-#include <pdx/rpc/variant.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/consumer_buffer.h>
-#include <private/dvr/display_client.h>
-#include <private/dvr/display_manager_client.h>
-
-#include "dvr_internal.h"
-#include "dvr_buffer_queue_internal.h"
-
-using android::dvr::ConsumerBuffer;
-using android::dvr::display::DisplayManagerClient;
-using android::dvr::display::SurfaceAttribute;
-using android::dvr::display::SurfaceAttributes;
-using android::dvr::display::SurfaceState;
-using android::pdx::rpc::EmptyVariant;
-
-namespace {
-
-// Extracts type and value from the attribute Variant and writes them into the
-// respective fields of DvrSurfaceAttribute.
-struct AttributeVisitor {
-  DvrSurfaceAttribute* attribute;
-
-  void operator()(int32_t value) {
-    attribute->value.int32_value = value;
-    attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
-  }
-  void operator()(int64_t value) {
-    attribute->value.int64_value = value;
-    attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT64;
-  }
-  void operator()(bool value) {
-    attribute->value.bool_value = value;
-    attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL;
-  }
-  void operator()(float value) {
-    attribute->value.float_value = value;
-    attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT;
-  }
-  void operator()(const std::array<float, 2>& value) {
-    std::copy(value.cbegin(), value.cend(), attribute->value.float2_value);
-    attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2;
-  }
-  void operator()(const std::array<float, 3>& value) {
-    std::copy(value.cbegin(), value.cend(), attribute->value.float3_value);
-    attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3;
-  }
-  void operator()(const std::array<float, 4>& value) {
-    std::copy(value.cbegin(), value.cend(), attribute->value.float4_value);
-    attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4;
-  }
-  void operator()(const std::array<float, 8>& value) {
-    std::copy(value.cbegin(), value.cend(), attribute->value.float8_value);
-    attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8;
-  }
-  void operator()(const std::array<float, 16>& value) {
-    std::copy(value.cbegin(), value.cend(), attribute->value.float16_value);
-    attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16;
-  }
-  void operator()(EmptyVariant) {
-    attribute->value.type = DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
-  }
-};
-
-size_t ConvertSurfaceAttributes(const SurfaceAttributes& surface_attributes,
-                                DvrSurfaceAttribute* attributes,
-                                size_t max_count) {
-  size_t count = 0;
-  for (const auto& attribute : surface_attributes) {
-    if (count >= max_count)
-      break;
-
-    // Copy the key and extract the Variant value using a visitor.
-    attributes[count].key = attribute.first;
-    attribute.second.Visit(AttributeVisitor{&attributes[count]});
-    count++;
-  }
-
-  return count;
-}
-
-}  // anonymous namespace
-
-extern "C" {
-
-struct DvrDisplayManager {
-  std::unique_ptr<DisplayManagerClient> client;
-};
-
-struct DvrSurfaceState {
-  std::vector<SurfaceState> state;
-};
-
-int dvrDisplayManagerCreate(DvrDisplayManager** client_out) {
-  if (!client_out)
-    return -EINVAL;
-
-  auto client = DisplayManagerClient::Create();
-  if (!client) {
-    ALOGE("dvrDisplayManagerCreate: Failed to create display manager client!");
-    return -EIO;
-  }
-
-  *client_out = new DvrDisplayManager{std::move(client)};
-  return 0;
-}
-
-void dvrDisplayManagerDestroy(DvrDisplayManager* client) { delete client; }
-
-int dvrDisplayManagerGetEventFd(DvrDisplayManager* client) {
-  if (!client)
-    return -EINVAL;
-
-  return client->client->event_fd();
-}
-
-int dvrDisplayManagerTranslateEpollEventMask(DvrDisplayManager* client,
-                                             int in_events, int* out_events) {
-  if (!client || !out_events)
-    return -EINVAL;
-
-  auto status = client->client->GetEventMask(in_events);
-  if (!status)
-    return -status.error();
-
-  *out_events = status.get();
-  return 0;
-}
-
-int dvrDisplayManagerGetSurfaceState(DvrDisplayManager* client,
-                                     DvrSurfaceState* state) {
-  if (!client || !state)
-    return -EINVAL;
-
-  auto status = client->client->GetSurfaceState();
-  if (!status)
-    return -status.error();
-
-  state->state = status.take();
-  return 0;
-}
-
-int dvrDisplayManagerGetReadBufferQueue(DvrDisplayManager* client,
-                                        int surface_id, int queue_id,
-                                        DvrReadBufferQueue** queue_out) {
-  if (!client || !queue_out)
-    return -EINVAL;
-
-  auto status = client->client->GetSurfaceQueue(surface_id, queue_id);
-  if (!status) {
-    ALOGE("dvrDisplayManagerGetReadBufferQueue: Failed to get queue: %s",
-          status.GetErrorMessage().c_str());
-    return -status.error();
-  }
-
-  *queue_out = new DvrReadBufferQueue(status.take());
-  return 0;
-}
-
-int dvrSurfaceStateCreate(DvrSurfaceState** surface_state_out) {
-  if (!surface_state_out)
-    return -EINVAL;
-
-  *surface_state_out = new DvrSurfaceState{};
-  return 0;
-}
-
-void dvrSurfaceStateDestroy(DvrSurfaceState* surface_state) {
-  delete surface_state;
-}
-
-int dvrSurfaceStateGetSurfaceCount(DvrSurfaceState* surface_state,
-                                   size_t* count_out) {
-  if (!surface_state)
-    return -EINVAL;
-
-  *count_out = surface_state->state.size();
-  return 0;
-}
-
-int dvrSurfaceStateGetUpdateFlags(DvrSurfaceState* surface_state,
-                                  size_t surface_index,
-                                  DvrSurfaceUpdateFlags* flags_out) {
-  if (!surface_state || surface_index >= surface_state->state.size())
-    return -EINVAL;
-
-  *flags_out = surface_state->state[surface_index].update_flags;
-  return 0;
-}
-
-int dvrSurfaceStateGetSurfaceId(DvrSurfaceState* surface_state,
-                                size_t surface_index, int* surface_id_out) {
-  if (!surface_state || surface_index >= surface_state->state.size())
-    return -EINVAL;
-
-  *surface_id_out = surface_state->state[surface_index].surface_id;
-  return 0;
-}
-
-int dvrSurfaceStateGetProcessId(DvrSurfaceState* surface_state,
-                                size_t surface_index, int* process_id_out) {
-  if (!surface_state || surface_index >= surface_state->state.size())
-    return -EINVAL;
-
-  *process_id_out = surface_state->state[surface_index].process_id;
-  return 0;
-}
-
-int dvrSurfaceStateGetQueueCount(DvrSurfaceState* surface_state,
-                                 size_t surface_index, size_t* count_out) {
-  if (!surface_state || surface_index >= surface_state->state.size())
-    return -EINVAL;
-
-  *count_out = surface_state->state[surface_index].queue_ids.size();
-  return 0;
-}
-
-ssize_t dvrSurfaceStateGetQueueIds(DvrSurfaceState* surface_state,
-                                   size_t surface_index, int* queue_ids,
-                                   size_t max_count) {
-  if (!surface_state || surface_index >= surface_state->state.size())
-    return -EINVAL;
-
-  size_t i;
-  const auto& state = surface_state->state[surface_index];
-  for (i = 0; i < std::min(max_count, state.queue_ids.size()); i++) {
-    queue_ids[i] = state.queue_ids[i];
-  }
-
-  return i;
-}
-
-int dvrSurfaceStateGetZOrder(DvrSurfaceState* surface_state,
-                             size_t surface_index, int* z_order_out) {
-  if (!surface_state || surface_index >= surface_state->state.size() ||
-      !z_order_out) {
-    return -EINVAL;
-  }
-
-  *z_order_out = surface_state->state[surface_index].GetZOrder();
-  return 0;
-}
-
-int dvrSurfaceStateGetVisible(DvrSurfaceState* surface_state,
-                              size_t surface_index, bool* visible_out) {
-  if (!surface_state || surface_index >= surface_state->state.size() ||
-      !visible_out) {
-    return -EINVAL;
-  }
-
-  *visible_out = surface_state->state[surface_index].GetVisible();
-  return 0;
-}
-
-int dvrSurfaceStateGetAttributeCount(DvrSurfaceState* surface_state,
-                                     size_t surface_index, size_t* count_out) {
-  if (!surface_state || surface_index >= surface_state->state.size() ||
-      !count_out) {
-    return -EINVAL;
-  }
-
-  *count_out = surface_state->state[surface_index].surface_attributes.size();
-  return 0;
-}
-
-ssize_t dvrSurfaceStateGetAttributes(DvrSurfaceState* surface_state,
-                                     size_t surface_index,
-                                     DvrSurfaceAttribute* attributes,
-                                     size_t max_count) {
-  if (!surface_state || surface_index >= surface_state->state.size() ||
-      !attributes) {
-    return -EINVAL;
-  }
-
-  return ConvertSurfaceAttributes(
-      surface_state->state[surface_index].surface_attributes, attributes,
-      max_count);
-}
-
-}  // extern "C"
diff --git a/libs/vr/libdvr/dvr_hardware_composer_client.cpp b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
deleted file mode 100644
index 4e87cf6..0000000
--- a/libs/vr/libdvr/dvr_hardware_composer_client.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
-#include "include/dvr/dvr_hardware_composer_client.h"
-
-#include <android/dvr/IVrComposer.h>
-#include <android/dvr/BnVrComposerCallback.h>
-#include <android/hardware_buffer.h>
-#include <binder/IServiceManager.h>
-#include <private/android/AHardwareBufferHelpers.h>
-
-#include <functional>
-#include <memory>
-#include <mutex>
-
-struct DvrHwcFrame {
-  android::dvr::ComposerView::Frame frame;
-};
-
-namespace {
-
-class HwcCallback : public android::dvr::BnVrComposerCallback {
- public:
-  using CallbackFunction = std::function<int(DvrHwcFrame*)>;
-
-  explicit HwcCallback(const CallbackFunction& callback);
-  ~HwcCallback() override;
-
-  // Reset the callback. This needs to be done early to avoid use after free
-  // accesses from binder thread callbacks.
-  void Shutdown();
-
-  std::unique_ptr<DvrHwcFrame> DequeueFrame();
-
- private:
-  // android::dvr::BnVrComposerCallback:
-  android::binder::Status onNewFrame(
-      const android::dvr::ParcelableComposerFrame& frame,
-      android::dvr::ParcelableUniqueFd* fence) override;
-
-  // Protects the |callback_| from uses from multiple threads. During shutdown
-  // there may be in-flight frame update events. In those cases the callback
-  // access needs to be protected otherwise binder threads may access an invalid
-  // callback.
-  std::mutex mutex_;
-  CallbackFunction callback_;
-
-  HwcCallback(const HwcCallback&) = delete;
-  void operator=(const HwcCallback&) = delete;
-};
-
-HwcCallback::HwcCallback(const CallbackFunction& callback)
-    : callback_(callback) {}
-
-HwcCallback::~HwcCallback() {}
-
-void HwcCallback::Shutdown() {
-  std::lock_guard<std::mutex> guard(mutex_);
-  callback_ = nullptr;
-}
-
-android::binder::Status HwcCallback::onNewFrame(
-    const android::dvr::ParcelableComposerFrame& frame,
-    android::dvr::ParcelableUniqueFd* fence) {
-  std::lock_guard<std::mutex> guard(mutex_);
-
-  if (!callback_) {
-    fence->set_fence(android::base::unique_fd());
-    return android::binder::Status::ok();
-  }
-
-  std::unique_ptr<DvrHwcFrame> dvr_frame(new DvrHwcFrame());
-  dvr_frame->frame = frame.frame();
-
-  fence->set_fence(android::base::unique_fd(callback_(dvr_frame.release())));
-  return android::binder::Status::ok();
-}
-
-}  // namespace
-
-struct DvrHwcClient {
-  android::sp<android::dvr::IVrComposer> composer;
-  android::sp<HwcCallback> callback;
-};
-
-DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback, void* data) {
-  std::unique_ptr<DvrHwcClient> client(new DvrHwcClient());
-
-  android::sp<android::IServiceManager> sm(android::defaultServiceManager());
-  client->composer = android::interface_cast<android::dvr::IVrComposer>(
-      sm->getService(android::dvr::IVrComposer::SERVICE_NAME()));
-  if (!client->composer.get())
-    return nullptr;
-
-  client->callback = new HwcCallback(std::bind(callback, data,
-                                               std::placeholders::_1));
-  android::binder::Status status = client->composer->registerObserver(
-      client->callback);
-  if (!status.isOk())
-    return nullptr;
-
-  return client.release();
-}
-
-void dvrHwcClientDestroy(DvrHwcClient* client) {
-  client->composer->clearObserver();
-
-  // NOTE: Deleting DvrHwcClient* isn't enough since DvrHwcClient::callback is a
-  // shared pointer that could be referenced from a binder thread. But the
-  // client callback isn't valid past this calls so that needs to be reset.
-  client->callback->Shutdown();
-
-  delete client;
-}
-
-void dvrHwcFrameDestroy(DvrHwcFrame* frame) {
-  delete frame;
-}
-
-DvrHwcDisplay dvrHwcFrameGetDisplayId(DvrHwcFrame* frame) {
-  return frame->frame.display_id;
-}
-
-int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame) {
-  return frame->frame.display_width;
-}
-
-int32_t dvrHwcFrameGetDisplayHeight(DvrHwcFrame* frame) {
-  return frame->frame.display_height;
-}
-
-bool dvrHwcFrameGetDisplayRemoved(DvrHwcFrame* frame) {
-  return frame->frame.removed;
-}
-
-size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame) {
-  return frame->frame.layers.size();
-}
-
-uint32_t dvrHwcFrameGetActiveConfig(DvrHwcFrame* frame) {
-  return static_cast<uint32_t>(frame->frame.active_config);
-}
-
-uint32_t dvrHwcFrameGetColorMode(DvrHwcFrame* frame) {
-  return static_cast<uint32_t>(frame->frame.color_mode);
-}
-
-void dvrHwcFrameGetColorTransform(DvrHwcFrame* frame, float* out_matrix,
-                                  int32_t* out_hint) {
-  *out_hint = frame->frame.color_transform_hint;
-  memcpy(out_matrix, frame->frame.color_transform,
-         sizeof(frame->frame.color_transform));
-}
-
-uint32_t dvrHwcFrameGetPowerMode(DvrHwcFrame* frame) {
-  return static_cast<uint32_t>(frame->frame.power_mode);
-}
-
-uint32_t dvrHwcFrameGetVsyncEnabled(DvrHwcFrame* frame) {
-  return static_cast<uint32_t>(frame->frame.vsync_enabled);
-}
-
-DvrHwcLayer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index) {
-  return frame->frame.layers[layer_index].id;
-}
-
-AHardwareBuffer* dvrHwcFrameGetLayerBuffer(DvrHwcFrame* frame,
-                                           size_t layer_index) {
-  AHardwareBuffer* buffer = android::AHardwareBuffer_from_GraphicBuffer(
-      frame->frame.layers[layer_index].buffer.get());
-  AHardwareBuffer_acquire(buffer);
-  return buffer;
-}
-
-int dvrHwcFrameGetLayerFence(DvrHwcFrame* frame, size_t layer_index) {
-  return frame->frame.layers[layer_index].fence->dup();
-}
-
-DvrHwcRecti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame,
-                                            size_t layer_index) {
-  return DvrHwcRecti{
-    frame->frame.layers[layer_index].display_frame.left,
-    frame->frame.layers[layer_index].display_frame.top,
-    frame->frame.layers[layer_index].display_frame.right,
-    frame->frame.layers[layer_index].display_frame.bottom,
-  };
-}
-
-DvrHwcRectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index) {
-  return DvrHwcRectf{
-    frame->frame.layers[layer_index].crop.left,
-    frame->frame.layers[layer_index].crop.top,
-    frame->frame.layers[layer_index].crop.right,
-    frame->frame.layers[layer_index].crop.bottom,
-  };
-}
-
-DvrHwcBlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame,
-                                             size_t layer_index) {
-  return static_cast<DvrHwcBlendMode>(
-      frame->frame.layers[layer_index].blend_mode);
-}
-
-float dvrHwcFrameGetLayerAlpha(DvrHwcFrame* frame, size_t layer_index) {
-  return frame->frame.layers[layer_index].alpha;
-}
-
-uint32_t dvrHwcFrameGetLayerType(DvrHwcFrame* frame, size_t layer_index) {
-  return frame->frame.layers[layer_index].type;
-}
-
-uint32_t dvrHwcFrameGetLayerApplicationId(DvrHwcFrame* frame,
-                                          size_t layer_index) {
-  return frame->frame.layers[layer_index].app_id;
-}
-
-uint32_t dvrHwcFrameGetLayerZOrder(DvrHwcFrame* frame, size_t layer_index) {
-  return frame->frame.layers[layer_index].z_order;
-}
-
-void dvrHwcFrameGetLayerCursor(DvrHwcFrame* frame, size_t layer_index,
-                               int32_t* out_x, int32_t* out_y) {
-  *out_x = frame->frame.layers[layer_index].cursor_x;
-  *out_y = frame->frame.layers[layer_index].cursor_y;
-}
-
-uint32_t dvrHwcFrameGetLayerTransform(DvrHwcFrame* frame, size_t layer_index) {
-  return frame->frame.layers[layer_index].transform;
-}
-
-uint32_t dvrHwcFrameGetLayerDataspace(DvrHwcFrame* frame, size_t layer_index) {
-  return frame->frame.layers[layer_index].dataspace;
-}
-
-uint32_t dvrHwcFrameGetLayerColor(DvrHwcFrame* frame, size_t layer_index) {
-  const auto& color = frame->frame.layers[layer_index].color;
-  return color.r | (static_cast<uint32_t>(color.g) << 8) |
-         (static_cast<uint32_t>(color.b) << 16) |
-         (static_cast<uint32_t>(color.a) << 24);
-}
-
-uint32_t dvrHwcFrameGetLayerNumVisibleRegions(DvrHwcFrame* frame,
-                                              size_t layer_index) {
-  return frame->frame.layers[layer_index].visible_regions.size();
-}
-
-DvrHwcRecti dvrHwcFrameGetLayerVisibleRegion(DvrHwcFrame* frame,
-                                             size_t layer_index, size_t index) {
-  return DvrHwcRecti{
-      frame->frame.layers[layer_index].visible_regions[index].left,
-      frame->frame.layers[layer_index].visible_regions[index].top,
-      frame->frame.layers[layer_index].visible_regions[index].right,
-      frame->frame.layers[layer_index].visible_regions[index].bottom,
-  };
-}
-
-uint32_t dvrHwcFrameGetLayerNumDamagedRegions(DvrHwcFrame* frame,
-                                              size_t layer_index) {
-  return frame->frame.layers[layer_index].damaged_regions.size();
-}
-
-DvrHwcRecti dvrHwcFrameGetLayerDamagedRegion(DvrHwcFrame* frame,
-                                             size_t layer_index, size_t index) {
-  return DvrHwcRecti{
-      frame->frame.layers[layer_index].damaged_regions[index].left,
-      frame->frame.layers[layer_index].damaged_regions[index].top,
-      frame->frame.layers[layer_index].damaged_regions[index].right,
-      frame->frame.layers[layer_index].damaged_regions[index].bottom,
-  };
-}
diff --git a/libs/vr/libdvr/dvr_internal.h b/libs/vr/libdvr/dvr_internal.h
deleted file mode 100644
index f845cd8..0000000
--- a/libs/vr/libdvr/dvr_internal.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef ANDROID_DVR_INTERNAL_H_
-#define ANDROID_DVR_INTERNAL_H_
-
-#include <sys/cdefs.h>
-
-#include <memory>
-
-extern "C" {
-
-typedef struct DvrBuffer DvrBuffer;
-typedef struct DvrReadBuffer DvrReadBuffer;
-typedef struct DvrWriteBuffer DvrWriteBuffer;
-
-}  // extern "C"
-
-namespace android {
-namespace dvr {
-
-class IonBuffer;
-
-DvrBuffer* CreateDvrBufferFromIonBuffer(
-    const std::shared_ptr<IonBuffer>& ion_buffer);
-
-}  // namespace dvr
-}  // namespace android
-
-extern "C" {
-
-struct DvrWriteBuffer {
-  // The slot nubmer of the buffer, a valid slot number must be in the range of
-  // [0, android::BufferQueueDefs::NUM_BUFFER_SLOTS). This is only valid for
-  // DvrWriteBuffer acquired from a DvrWriteBufferQueue.
-  int32_t slot = -1;
-
-  std::shared_ptr<android::dvr::ProducerBuffer> write_buffer;
-};
-
-struct DvrReadBuffer {
-  // The slot nubmer of the buffer, a valid slot number must be in the range of
-  // [0, android::BufferQueueDefs::NUM_BUFFER_SLOTS). This is only valid for
-  // DvrReadBuffer acquired from a DvrReadBufferQueue.
-  int32_t slot = -1;
-
-  std::shared_ptr<android::dvr::ConsumerBuffer> read_buffer;
-};
-
-struct DvrBuffer {
-  std::shared_ptr<android::dvr::IonBuffer> buffer;
-};
-
-}  // extern "C"
-
-#endif  // ANDROID_DVR_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_performance.cpp b/libs/vr/libdvr/dvr_performance.cpp
deleted file mode 100644
index 599101f..0000000
--- a/libs/vr/libdvr/dvr_performance.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "include/dvr/dvr_performance.h"
-
-#include <private/dvr/performance_client.h>
-
-using android::dvr::PerformanceClient;
-
-extern "C" {
-
-int dvrPerformanceSetSchedulerPolicy(pid_t task_id,
-                                     const char* scheduler_policy) {
-  int error;
-  if (auto client = PerformanceClient::Create(&error))
-    return client->SetSchedulerPolicy(task_id, scheduler_policy);
-  else
-    return error;
-}
-
-}  // extern "C"
diff --git a/libs/vr/libdvr/dvr_pose.cpp b/libs/vr/libdvr/dvr_pose.cpp
deleted file mode 100644
index c379ef5..0000000
--- a/libs/vr/libdvr/dvr_pose.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "include/dvr/dvr_pose.h"
-
-#include <memory>
-
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/pose_client_internal.h>
-
-#include "dvr_buffer_queue_internal.h"
-
-using android::dvr::ConsumerQueue;
-
-int dvrPoseClientGetDataReader(DvrPoseClient* client, uint64_t data_type,
-                               DvrReadBufferQueue** queue_out) {
-  if (!client || !queue_out)
-    return -EINVAL;
-
-  ConsumerQueue* consumer_queue;
-  int status = android::dvr::dvrPoseClientGetDataReaderHandle(client,
-                                                              data_type,
-                                                              &consumer_queue);
-  if (status != 0) {
-    ALOGE("dvrPoseClientGetDataReader: Failed to get queue: %d", status);
-    return status;
-  }
-
-  std::shared_ptr<ConsumerQueue> consumer_queue_ptr{consumer_queue};
-  *queue_out = new DvrReadBufferQueue(consumer_queue_ptr);
-  return 0;
-}
diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp
deleted file mode 100644
index 0c7ec01..0000000
--- a/libs/vr/libdvr/dvr_surface.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-#include "include/dvr/dvr_surface.h"
-
-#include <inttypes.h>
-
-#include <pdx/rpc/variant.h>
-#include <private/android/AHardwareBufferHelpers.h>
-#include <private/dvr/display_client.h>
-
-#include "dvr_buffer_queue_internal.h"
-#include "dvr_internal.h"
-
-using android::AHardwareBuffer_convertToGrallocUsageBits;
-using android::dvr::display::DisplayClient;
-using android::dvr::display::Surface;
-using android::dvr::display::SurfaceAttributes;
-using android::dvr::display::SurfaceAttributeValue;
-using android::pdx::rpc::EmptyVariant;
-
-namespace {
-
-// Sets the Variant |destination| to the target std::array type and copies the C
-// array into it. Unsupported std::array configurations will fail to compile.
-template <typename T, std::size_t N>
-void ArrayCopy(SurfaceAttributeValue* destination, const T (&source)[N]) {
-  using ArrayType = std::array<T, N>;
-  *destination = ArrayType{};
-  std::copy(std::begin(source), std::end(source),
-            std::get<ArrayType>(*destination).begin());
-}
-
-bool ConvertSurfaceAttributes(const DvrSurfaceAttribute* attributes,
-                              size_t attribute_count,
-                              SurfaceAttributes* surface_attributes,
-                              size_t* error_index) {
-  for (size_t i = 0; i < attribute_count; i++) {
-    SurfaceAttributeValue value;
-    switch (attributes[i].value.type) {
-      case DVR_SURFACE_ATTRIBUTE_TYPE_INT32:
-        value = attributes[i].value.int32_value;
-        break;
-      case DVR_SURFACE_ATTRIBUTE_TYPE_INT64:
-        value = attributes[i].value.int64_value;
-        break;
-      case DVR_SURFACE_ATTRIBUTE_TYPE_BOOL:
-        // bool_value is defined in an extern "C" block, which makes it look
-        // like an int to C++. Use a cast to assign the correct type to the
-        // Variant type SurfaceAttributeValue.
-        value = static_cast<bool>(attributes[i].value.bool_value);
-        break;
-      case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT:
-        value = attributes[i].value.float_value;
-        break;
-      case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2:
-        ArrayCopy(&value, attributes[i].value.float2_value);
-        break;
-      case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3:
-        ArrayCopy(&value, attributes[i].value.float3_value);
-        break;
-      case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4:
-        ArrayCopy(&value, attributes[i].value.float4_value);
-        break;
-      case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8:
-        ArrayCopy(&value, attributes[i].value.float8_value);
-        break;
-      case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16:
-        ArrayCopy(&value, attributes[i].value.float16_value);
-        break;
-      case DVR_SURFACE_ATTRIBUTE_TYPE_NONE:
-        value = EmptyVariant{};
-        break;
-      default:
-        *error_index = i;
-        return false;
-    }
-
-    surface_attributes->emplace(attributes[i].key, value);
-  }
-
-  return true;
-}
-
-}  // anonymous namespace
-
-extern "C" {
-
-struct DvrSurface {
-  std::unique_ptr<Surface> surface;
-};
-
-int dvrSurfaceCreate(const DvrSurfaceAttribute* attributes,
-                     size_t attribute_count, DvrSurface** out_surface) {
-  if (out_surface == nullptr) {
-    ALOGE("dvrSurfaceCreate: Invalid inputs: out_surface=%p.", out_surface);
-    return -EINVAL;
-  }
-
-  size_t error_index;
-  SurfaceAttributes surface_attributes;
-  if (!ConvertSurfaceAttributes(attributes, attribute_count,
-                                &surface_attributes, &error_index)) {
-    ALOGE("dvrSurfaceCreate: Invalid surface attribute type: %" PRIu64,
-          attributes[error_index].value.type);
-    return -EINVAL;
-  }
-
-  auto status = Surface::CreateSurface(surface_attributes);
-  if (!status) {
-    ALOGE("dvrSurfaceCreate:: Failed to create display surface: %s",
-          status.GetErrorMessage().c_str());
-    return -status.error();
-  }
-
-  *out_surface = new DvrSurface{status.take()};
-  return 0;
-}
-
-void dvrSurfaceDestroy(DvrSurface* surface) { delete surface; }
-
-int dvrSurfaceGetId(DvrSurface* surface) {
-  return surface->surface->surface_id();
-}
-
-int dvrSurfaceSetAttributes(DvrSurface* surface,
-                            const DvrSurfaceAttribute* attributes,
-                            size_t attribute_count) {
-  if (surface == nullptr || attributes == nullptr) {
-    ALOGE(
-        "dvrSurfaceSetAttributes: Invalid inputs: surface=%p attributes=%p "
-        "attribute_count=%zu",
-        surface, attributes, attribute_count);
-    return -EINVAL;
-  }
-
-  size_t error_index;
-  SurfaceAttributes surface_attributes;
-  if (!ConvertSurfaceAttributes(attributes, attribute_count,
-                                &surface_attributes, &error_index)) {
-    ALOGE("dvrSurfaceSetAttributes: Invalid surface attribute type: %" PRIu64,
-          attributes[error_index].value.type);
-    return -EINVAL;
-  }
-
-  auto status = surface->surface->SetAttributes(surface_attributes);
-  if (!status) {
-    ALOGE("dvrSurfaceSetAttributes: Failed to set attributes: %s",
-          status.GetErrorMessage().c_str());
-    return -status.error();
-  }
-
-  return 0;
-}
-
-int dvrSurfaceCreateWriteBufferQueue(DvrSurface* surface, uint32_t width,
-                                     uint32_t height, uint32_t format,
-                                     uint32_t layer_count, uint64_t usage,
-                                     size_t capacity, size_t metadata_size,
-                                     DvrWriteBufferQueue** out_writer) {
-  if (surface == nullptr || out_writer == nullptr) {
-    ALOGE(
-        "dvrSurfaceCreateWriteBufferQueue: Invalid inputs: surface=%p, "
-        "out_writer=%p.",
-        surface, out_writer);
-    return -EINVAL;
-  }
-
-  auto status = surface->surface->CreateQueue(
-      width, height, layer_count, format, usage, capacity, metadata_size);
-  if (!status) {
-    ALOGE("dvrSurfaceCreateWriteBufferQueue: Failed to create queue: %s",
-          status.GetErrorMessage().c_str());
-    return -status.error();
-  }
-
-  *out_writer = new DvrWriteBufferQueue(status.take());
-  return 0;
-}
-
-int dvrSetupGlobalBuffer(DvrGlobalBufferKey key, size_t size, uint64_t usage,
-                         DvrBuffer** buffer_out) {
-  if (!buffer_out)
-    return -EINVAL;
-
-  int error;
-  auto client = DisplayClient::Create(&error);
-  if (!client) {
-    ALOGE("dvrSetupGlobalBuffer: Failed to create display client: %s",
-          strerror(-error));
-    return error;
-  }
-
-  uint64_t gralloc_usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
-
-  auto buffer_status = client->SetupGlobalBuffer(key, size, gralloc_usage);
-  if (!buffer_status) {
-    ALOGE("dvrSetupGlobalBuffer: Failed to setup global buffer: %s",
-          buffer_status.GetErrorMessage().c_str());
-    return -buffer_status.error();
-  }
-
-  *buffer_out = CreateDvrBufferFromIonBuffer(buffer_status.take());
-  return 0;
-}
-
-int dvrDeleteGlobalBuffer(DvrGlobalBufferKey key) {
-  int error;
-  auto client = DisplayClient::Create(&error);
-  if (!client) {
-    ALOGE("dvrDeleteGlobalBuffer: Failed to create display client: %s",
-          strerror(-error));
-    return error;
-  }
-
-  auto buffer_status = client->DeleteGlobalBuffer(key);
-  if (!buffer_status) {
-    ALOGE("dvrDeleteGlobalBuffer: Failed to delete named buffer: %s",
-          buffer_status.GetErrorMessage().c_str());
-    return -buffer_status.error();
-  }
-
-  return 0;
-}
-
-int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer) {
-  if (!out_buffer)
-    return -EINVAL;
-
-  int error;
-  auto client = DisplayClient::Create(&error);
-  if (!client) {
-    ALOGE("dvrGetGlobalBuffer: Failed to create display client: %s",
-          strerror(-error));
-    return error;
-  }
-
-  auto status = client->GetGlobalBuffer(key);
-  if (!status) {
-    return -status.error();
-  }
-  *out_buffer = CreateDvrBufferFromIonBuffer(status.take());
-  return 0;
-}
-
-int dvrGetNativeDisplayMetrics(size_t sizeof_metrics,
-                               DvrNativeDisplayMetrics* metrics) {
-  ALOGE_IF(sizeof_metrics != sizeof(DvrNativeDisplayMetrics),
-           "dvrGetNativeDisplayMetrics: metrics struct mismatch, your dvr api "
-           "header is out of date.");
-
-  auto client = DisplayClient::Create();
-  if (!client) {
-    ALOGE("dvrGetNativeDisplayMetrics: Failed to create display client!");
-    return -ECOMM;
-  }
-
-  if (metrics == nullptr) {
-    ALOGE("dvrGetNativeDisplayMetrics: output metrics buffer must be non-null");
-    return -EINVAL;
-  }
-
-  auto status = client->GetDisplayMetrics();
-
-  if (!status) {
-    return -status.error();
-  }
-
-  if (sizeof_metrics >= 20) {
-    metrics->display_width = status.get().display_width;
-    metrics->display_height = status.get().display_height;
-    metrics->display_x_dpi = status.get().display_x_dpi;
-    metrics->display_y_dpi = status.get().display_y_dpi;
-    metrics->vsync_period_ns = status.get().vsync_period_ns;
-  }
-
-  return 0;
-}
-
-}  // extern "C"
diff --git a/libs/vr/libdvr/dvr_tracking.cpp b/libs/vr/libdvr/dvr_tracking.cpp
deleted file mode 100644
index 73addc9..0000000
--- a/libs/vr/libdvr/dvr_tracking.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#include "include/dvr/dvr_tracking.h"
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#if !DVR_TRACKING_IMPLEMENTED
-
-extern "C" {
-
-// This file provides the stub implementation of dvrTrackingXXX APIs. On
-// platforms that implement these APIs, set -DDVR_TRACKING_IMPLEMENTED=1 in the
-// build file.
-int dvrTrackingCameraCreate(DvrTrackingCamera**) {
-  ALOGE("dvrTrackingCameraCreate is not implemented.");
-  return -ENOSYS;
-}
-
-void dvrTrackingCameraDestroy(DvrTrackingCamera*) {
-  ALOGE("dvrTrackingCameraDestroy is not implemented.");
-}
-
-int dvrTrackingCameraStart(DvrTrackingCamera*, DvrWriteBufferQueue*) {
-  ALOGE("dvrTrackingCameraCreate is not implemented.");
-  return -ENOSYS;
-}
-
-int dvrTrackingCameraStop(DvrTrackingCamera*) {
-  ALOGE("dvrTrackingCameraCreate is not implemented.");
-  return -ENOSYS;
-}
-
-int dvrTrackingFeatureExtractorCreate(DvrTrackingFeatureExtractor**) {
-  ALOGE("dvrTrackingFeatureExtractorCreate is not implemented.");
-  return -ENOSYS;
-}
-
-void dvrTrackingFeatureExtractorDestroy(DvrTrackingFeatureExtractor*) {
-  ALOGE("dvrTrackingFeatureExtractorDestroy is not implemented.");
-}
-
-int dvrTrackingFeatureExtractorStart(DvrTrackingFeatureExtractor*,
-                                     DvrTrackingFeatureCallback, void*) {
-  ALOGE("dvrTrackingFeatureExtractorCreate is not implemented.");
-  return -ENOSYS;
-}
-
-int dvrTrackingFeatureExtractorStop(DvrTrackingFeatureExtractor*) {
-  ALOGE("dvrTrackingFeatureExtractorCreate is not implemented.");
-  return -ENOSYS;
-}
-
-int dvrTrackingFeatureExtractorProcessBuffer(DvrTrackingFeatureExtractor*,
-                                             DvrReadBuffer*,
-                                             const DvrTrackingBufferMetadata*,
-                                             bool*) {
-  ALOGE("dvrTrackingFeatureExtractorProcessBuffer is not implemented.");
-  return -ENOSYS;
-}
-
-int dvrTrackingSensorsCreate(DvrTrackingSensors**, const char*) {
-  ALOGE("dvrTrackingSensorsCreate is not implemented.");
-  return -ENOSYS;
-}
-
-void dvrTrackingSensorsDestroy(DvrTrackingSensors*) {
-  ALOGE("dvrTrackingSensorsDestroy is not implemented.");
-}
-
-int dvrTrackingSensorsStart(DvrTrackingSensors*, DvrTrackingSensorEventCallback,
-                            void*) {
-  ALOGE("dvrTrackingStart is not implemented.");
-  return -ENOSYS;
-}
-
-int dvrTrackingSensorsStop(DvrTrackingSensors*) {
-  ALOGE("dvrTrackingStop is not implemented.");
-  return -ENOSYS;
-}
-
-}  // extern "C"
-
-#endif  // DVR_TRACKING_IMPLEMENTED
diff --git a/libs/vr/libdvr/exported_apis.lds b/libs/vr/libdvr/exported_apis.lds
deleted file mode 100644
index 5ecb498..0000000
--- a/libs/vr/libdvr/exported_apis.lds
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  global:
-    # Whitelist the function to load the dvr api.
-    dvrGetApi;
-
-  local:
-    # Hide everything else.
-    *;
-};
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
deleted file mode 100644
index fe7feb8..0000000
--- a/libs/vr/libdvr/tests/Android.bp
+++ /dev/null
@@ -1,113 +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.
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_native_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_native_license"],
-}
-
-cc_test {
-    srcs: [
-        "dvr_display_manager-test.cpp",
-        "dvr_named_buffer-test.cpp",
-        "dvr_tracking-test.cpp",
-    ],
-
-    header_libs: ["libdvr_headers"],
-    static_libs: [
-        "libdvr_static.google",
-        "libchrome",
-        "libdvrcommon",
-        "libdisplay",
-        "libbroadcastring",
-    ],
-    shared_libs: [
-        "libbase",
-        "libbinder",
-        "libbufferhubqueue",
-        "libcutils",
-        "libgui",
-        "liblog",
-        "libhardware",
-        "libui",
-        "libutils",
-        "libnativewindow",
-        "libpdx_default_transport",
-    ],
-    cflags: [
-        "-DDVR_TRACKING_IMPLEMENTED=0",
-        "-DLOG_TAG=\"dvr_api-test\"",
-        "-DTRACE=0",
-        "-Wno-missing-field-initializers",
-        "-O0",
-        "-g",
-    ],
-    name: "dvr_api-test",
-}
-
-cc_test {
-    name: "dvr_buffer_queue-test",
-
-    // Includes the dvr_api.h header. Tests should only include "dvr_api.h",
-    // and shall only get access to |dvrGetApi|, as other symbols are hidden
-    // from the library.
-    include_dirs: ["frameworks/native/libs/vr/libdvr/include"],
-
-    srcs: ["dvr_buffer_queue-test.cpp"],
-
-    shared_libs: [
-        "libandroid",
-        "liblog",
-    ],
-
-    cflags: [
-        "-DTRACE=0",
-        "-O2",
-        "-g",
-    ],
-
-    // DTS Should only link to NDK libraries.
-    sdk_version: "26",
-    stl: "c++_static",
-}
-
-cc_test {
-    name: "dvr_display-test",
-
-    include_dirs: [
-        "frameworks/native/libs/vr/libdvr/include",
-        "frameworks/native/libs/nativewindow/include",
-    ],
-
-    srcs: ["dvr_display-test.cpp"],
-
-    shared_libs: [
-        "libandroid",
-        "liblog",
-    ],
-
-    cflags: [
-        "-DTRACE=0",
-        "-O2",
-        "-g",
-    ],
-
-    // DTS Should only link to NDK libraries.
-    sdk_version: "26",
-    stl: "c++_static",
-}
diff --git a/libs/vr/libdvr/tests/dvr_api_test.h b/libs/vr/libdvr/tests/dvr_api_test.h
deleted file mode 100644
index 5d2ec28..0000000
--- a/libs/vr/libdvr/tests/dvr_api_test.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#include <dlfcn.h>
-#include <dvr/dvr_api.h>
-
-#include <gtest/gtest.h>
-
-/** DvrTestBase loads the libdvr.so at runtime and get the Dvr API version 1. */
-class DvrApiTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    int flags = RTLD_NOW | RTLD_LOCAL;
-
-    // Here we need to ensure that libdvr is loaded with RTLD_NODELETE flag set
-    // (so that calls to `dlclose` don't actually unload the library). This is a
-    // workaround for an Android NDK bug. See more detail:
-    // https://github.com/android-ndk/ndk/issues/360
-    flags |= RTLD_NODELETE;
-    platform_handle_ = dlopen("libdvr.google.so", flags);
-    ASSERT_NE(nullptr, platform_handle_) << "Dvr shared library missing.";
-
-    auto dvr_get_api = reinterpret_cast<decltype(&dvrGetApi)>(
-        dlsym(platform_handle_, "dvrGetApi"));
-    ASSERT_NE(nullptr, dvr_get_api) << "Platform library missing dvrGetApi.";
-
-    ASSERT_EQ(dvr_get_api(&api_, sizeof(api_), /*version=*/1), 0)
-        << "Unable to find compatible Dvr API.";
-  }
-
-  void TearDown() override {
-    if (platform_handle_ != nullptr) {
-      dlclose(platform_handle_);
-    }
-  }
-
-  void* platform_handle_ = nullptr;
-  DvrApi_v1 api_;
-};
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
deleted file mode 100644
index df06097..0000000
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ /dev/null
@@ -1,579 +0,0 @@
-#include <android/log.h>
-#include <android/native_window.h>
-#include <dvr/dvr_api.h>
-#include <dvr/dvr_buffer_queue.h>
-
-#include <gtest/gtest.h>
-
-#include <array>
-#include <unordered_map>
-
-#include "dvr_api_test.h"
-
-#define LOG_TAG "dvr_buffer_queue-test"
-
-#ifndef ALOGD
-#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
-#endif
-
-#ifndef ALOGD_IF
-#define ALOGD_IF(cond, ...) \
-  ((__predict_false(cond)) ? ((void)ALOGD(__VA_ARGS__)) : (void)0)
-#endif
-
-namespace {
-
-static constexpr uint32_t kBufferWidth = 100;
-static constexpr uint32_t kBufferHeight = 1;
-static constexpr uint32_t kLayerCount = 1;
-static constexpr uint32_t kBufferFormat = AHARDWAREBUFFER_FORMAT_BLOB;
-static constexpr uint64_t kBufferUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
-static constexpr size_t kQueueCapacity = 3;
-
-class DvrBufferQueueTest : public DvrApiTest {
- public:
-  static void BufferAvailableCallback(void* context) {
-    DvrBufferQueueTest* thiz = static_cast<DvrBufferQueueTest*>(context);
-    thiz->HandleBufferAvailable();
-  }
-
-  static void BufferRemovedCallback(DvrReadBuffer* buffer, void* context) {
-    DvrBufferQueueTest* thiz = static_cast<DvrBufferQueueTest*>(context);
-    thiz->HandleBufferRemoved(buffer);
-  }
-
- protected:
-  void TearDown() override {
-    if (write_queue_ != nullptr) {
-      api_.WriteBufferQueueDestroy(write_queue_);
-      write_queue_ = nullptr;
-    }
-    DvrApiTest::TearDown();
-  }
-
-  void HandleBufferAvailable() {
-    buffer_available_count_ += 1;
-    ALOGD_IF(TRACE, "Buffer avaiable, count=%d", buffer_available_count_);
-  }
-
-  void HandleBufferRemoved(DvrReadBuffer* buffer) {
-    buffer_removed_count_ += 1;
-    ALOGD_IF(TRACE, "Buffer removed, buffer=%p, count=%d", buffer,
-             buffer_removed_count_);
-  }
-
-  DvrWriteBufferQueue* write_queue_ = nullptr;
-  int buffer_available_count_{0};
-  int buffer_removed_count_{0};
-};
-
-TEST_F(DvrBufferQueueTest, WriteQueueCreateDestroy) {
-  int ret = api_.WriteBufferQueueCreate(
-      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
-      /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
-  ASSERT_EQ(0, ret);
-
-  api_.WriteBufferQueueDestroy(write_queue_);
-  write_queue_ = nullptr;
-}
-
-TEST_F(DvrBufferQueueTest, WriteQueueGetCapacity) {
-  int ret = api_.WriteBufferQueueCreate(
-      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
-      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
-  ASSERT_EQ(0, ret);
-
-  size_t capacity = api_.WriteBufferQueueGetCapacity(write_queue_);
-
-  ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity);
-  ASSERT_EQ(kQueueCapacity, capacity);
-}
-
-TEST_F(DvrBufferQueueTest, CreateReadQueueFromWriteQueue) {
-  int ret = api_.WriteBufferQueueCreate(
-      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
-      /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
-  ASSERT_EQ(0, ret);
-
-  DvrReadBufferQueue* read_queue = nullptr;
-  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
-
-  ASSERT_EQ(0, ret);
-  ASSERT_NE(nullptr, read_queue);
-
-  api_.ReadBufferQueueDestroy(read_queue);
-}
-
-TEST_F(DvrBufferQueueTest, CreateReadQueueFromReadQueue) {
-  int ret = api_.WriteBufferQueueCreate(
-      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
-      /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
-  ASSERT_EQ(0, ret);
-
-  DvrReadBufferQueue* read_queue1 = nullptr;
-  DvrReadBufferQueue* read_queue2 = nullptr;
-  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
-
-  ASSERT_EQ(0, ret);
-  ASSERT_NE(nullptr, read_queue1);
-
-  ret = api_.ReadBufferQueueCreateReadQueue(read_queue1, &read_queue2);
-  ASSERT_EQ(0, ret);
-  ASSERT_NE(nullptr, read_queue2);
-  ASSERT_NE(read_queue1, read_queue2);
-
-  api_.ReadBufferQueueDestroy(read_queue1);
-  api_.ReadBufferQueueDestroy(read_queue2);
-}
-
-TEST_F(DvrBufferQueueTest, GainBuffer) {
-  int ret = api_.WriteBufferQueueCreate(
-      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
-      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
-  ASSERT_EQ(ret, 0);
-
-  DvrWriteBuffer* wb = nullptr;
-  EXPECT_FALSE(api_.WriteBufferIsValid(wb));
-
-  DvrNativeBufferMetadata meta;
-  int fence_fd = -1;
-  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta,
-                                        &fence_fd);
-  ASSERT_EQ(ret, 0);
-  EXPECT_EQ(fence_fd, -1);
-  EXPECT_NE(wb, nullptr);
-  EXPECT_TRUE(api_.WriteBufferIsValid(wb));
-}
-
-TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) {
-  int ret = api_.WriteBufferQueueCreate(
-      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
-      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
-  ASSERT_EQ(ret, 0);
-
-  DvrReadBufferQueue* read_queue = nullptr;
-  DvrReadBuffer* rb = nullptr;
-  DvrWriteBuffer* wb = nullptr;
-  DvrNativeBufferMetadata meta1;
-  DvrNativeBufferMetadata meta2;
-  int fence_fd = -1;
-
-  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
-
-  ASSERT_EQ(ret, 0);
-  ASSERT_NE(read_queue, nullptr);
-
-  api_.ReadBufferQueueSetBufferAvailableCallback(
-      read_queue, &BufferAvailableCallback, this);
-
-  // Gain buffer for writing.
-  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb,
-                                        &meta1, &fence_fd);
-  ASSERT_EQ(ret, 0);
-  ASSERT_NE(wb, nullptr);
-  ASSERT_TRUE(api_.WriteBufferIsValid(wb));
-  ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d",
-           wb, fence_fd);
-  close(fence_fd);
-
-  // Post buffer to the read_queue.
-  meta1.timestamp = 42;
-  ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
-  ASSERT_EQ(ret, 0);
-  ASSERT_FALSE(api_.WriteBufferIsValid(wb));
-  wb = nullptr;
-
-  // Acquire buffer for reading.
-  ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb,
-                                          &meta2, &fence_fd);
-  ASSERT_EQ(ret, 0);
-  ASSERT_NE(rb, nullptr);
-
-  // Dequeue is successfully, BufferAvailableCallback should be fired once.
-  ASSERT_EQ(buffer_available_count_, 1);
-  ASSERT_TRUE(api_.ReadBufferIsValid(rb));
-
-  // Metadata should be passed along from producer to consumer properly.
-  ASSERT_EQ(meta1.timestamp, meta2.timestamp);
-
-  ALOGD_IF(TRACE,
-           "TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb,
-           fence_fd);
-  close(fence_fd);
-
-  // Release buffer to the write_queue.
-  ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
-                                          /*release_fence_fd=*/-1);
-  ASSERT_EQ(ret, 0);
-  ASSERT_FALSE(api_.ReadBufferIsValid(rb));
-  rb = nullptr;
-
-  // TODO(b/34387835) Currently buffer allocation has to happen after all queues
-  // are initialized.
-  size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue);
-
-  ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, capacity=%zu", capacity);
-  ASSERT_EQ(kQueueCapacity, capacity);
-
-  api_.ReadBufferQueueDestroy(read_queue);
-}
-
-TEST_F(DvrBufferQueueTest, GetANativeWindow) {
-  int ret = api_.WriteBufferQueueCreate(
-      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
-      /*capacity=*/0, /*user_metadata_size=*/0, &write_queue_);
-  ASSERT_EQ(0, ret);
-  ASSERT_NE(nullptr, write_queue_);
-
-  ANativeWindow* window = nullptr;
-  ret = api_.WriteBufferQueueGetANativeWindow(write_queue_, &window);
-  ASSERT_EQ(0, ret);
-  ASSERT_NE(nullptr, window);
-
-  uint32_t width = ANativeWindow_getWidth(window);
-  uint32_t height = ANativeWindow_getHeight(window);
-  uint32_t format = ANativeWindow_getFormat(window);
-  ASSERT_EQ(kBufferWidth, width);
-  ASSERT_EQ(kBufferHeight, height);
-  ASSERT_EQ(kBufferFormat, format);
-}
-
-// Create buffer queue of three buffers and dequeue three buffers out of it.
-// Before each dequeue operation, we resize the buffer queue and expect the
-// queue always return buffer with desired dimension.
-TEST_F(DvrBufferQueueTest, ResizeBuffer) {
-  int ret = api_.WriteBufferQueueCreate(
-      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
-      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
-  ASSERT_EQ(0, ret);
-
-  int fence_fd = -1;
-
-  DvrNativeBufferMetadata meta;
-  DvrReadBufferQueue* read_queue = nullptr;
-  DvrWriteBuffer* wb1 = nullptr;
-  DvrWriteBuffer* wb2 = nullptr;
-  DvrWriteBuffer* wb3 = nullptr;
-  AHardwareBuffer* ahb1 = nullptr;
-  AHardwareBuffer* ahb2 = nullptr;
-  AHardwareBuffer* ahb3 = nullptr;
-  AHardwareBuffer_Desc buffer_desc;
-
-  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
-
-  ASSERT_EQ(0, ret);
-  ASSERT_NE(nullptr, read_queue);
-
-  api_.ReadBufferQueueSetBufferRemovedCallback(read_queue,
-                                               &BufferRemovedCallback, this);
-
-  // Handle all pending events on the read queue.
-  ret = api_.ReadBufferQueueHandleEvents(read_queue);
-  ASSERT_EQ(0, ret);
-
-  size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue);
-  ALOGD_IF(TRACE, "TestResizeBuffer, capacity=%zu", capacity);
-  ASSERT_EQ(kQueueCapacity, capacity);
-
-  // Resize before dequeuing.
-  constexpr uint32_t w1 = 10;
-  ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight);
-  ASSERT_EQ(0, ret);
-
-  // Gain first buffer for writing. All buffers will be resized.
-  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1,
-                                        &meta, &fence_fd);
-  ASSERT_EQ(0, ret);
-  ASSERT_TRUE(api_.WriteBufferIsValid(wb1));
-  ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1);
-  close(fence_fd);
-
-  // Check the buffer dimension.
-  ret = api_.WriteBufferGetAHardwareBuffer(wb1, &ahb1);
-  ASSERT_EQ(0, ret);
-  AHardwareBuffer_describe(ahb1, &buffer_desc);
-  ASSERT_EQ(w1, buffer_desc.width);
-  ASSERT_EQ(kBufferHeight, buffer_desc.height);
-  AHardwareBuffer_release(ahb1);
-
-  // For the first resize, all buffers are reallocated.
-  int expected_buffer_removed_count = kQueueCapacity;
-  ret = api_.ReadBufferQueueHandleEvents(read_queue);
-  ASSERT_EQ(0, ret);
-  ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
-
-  // Resize the queue. We are testing with blob format, keep height to be 1.
-  constexpr uint32_t w2 = 20;
-  ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight);
-  ASSERT_EQ(0, ret);
-
-  // The next buffer we dequeued should have new width.
-  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2,
-                                        &meta, &fence_fd);
-  ASSERT_EQ(0, ret);
-  ASSERT_TRUE(api_.WriteBufferIsValid(wb2));
-  ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2,
-           fence_fd);
-  close(fence_fd);
-
-  // Check the buffer dimension, should be new width
-  ret = api_.WriteBufferGetAHardwareBuffer(wb2, &ahb2);
-  ASSERT_EQ(0, ret);
-  AHardwareBuffer_describe(ahb2, &buffer_desc);
-  ASSERT_EQ(w2, buffer_desc.width);
-  AHardwareBuffer_release(ahb2);
-
-  // For the second resize, all but one buffers are reallocated.
-  expected_buffer_removed_count += (kQueueCapacity - 1);
-  ret = api_.ReadBufferQueueHandleEvents(read_queue);
-  ASSERT_EQ(0, ret);
-  ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
-
-  // Resize the queue for the third time.
-  constexpr uint32_t w3 = 30;
-  ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight);
-  ASSERT_EQ(0, ret);
-
-  // The next buffer we dequeued should have new width.
-  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3,
-                                        &meta, &fence_fd);
-  ASSERT_EQ(0, ret);
-  ASSERT_TRUE(api_.WriteBufferIsValid(wb3));
-  ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3,
-           fence_fd);
-  close(fence_fd);
-
-  // Check the buffer dimension, should be new width
-  ret = api_.WriteBufferGetAHardwareBuffer(wb3, &ahb3);
-  ASSERT_EQ(0, ret);
-  AHardwareBuffer_describe(ahb3, &buffer_desc);
-  ASSERT_EQ(w3, buffer_desc.width);
-  AHardwareBuffer_release(ahb3);
-
-  // For the third resize, all but two buffers are reallocated.
-  expected_buffer_removed_count += (kQueueCapacity - 2);
-  ret = api_.ReadBufferQueueHandleEvents(read_queue);
-  ASSERT_EQ(0, ret);
-  ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
-
-  api_.ReadBufferQueueDestroy(read_queue);
-}
-
-TEST_F(DvrBufferQueueTest, ReadQueueEventFd) {
-  int ret = api_.WriteBufferQueueCreate(
-      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
-      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
-  ASSERT_EQ(0, ret);
-
-  DvrReadBufferQueue* read_queue = nullptr;
-  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
-
-  ASSERT_EQ(0, ret);
-  ASSERT_NE(nullptr, read_queue);
-
-  int event_fd = api_.ReadBufferQueueGetEventFd(read_queue);
-  ASSERT_GT(event_fd, 0);
-}
-
-// Verifies a Dvr{Read,Write}BufferQueue contains the same set of
-// Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id,
-// the corresponding AHardwareBuffer handle stays the same.
-TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) {
-  int ret = api_.WriteBufferQueueCreate(
-      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
-      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
-  ASSERT_EQ(0, ret);
-
-  int fence_fd = -1;
-  DvrReadBufferQueue* read_queue = nullptr;
-  EXPECT_EQ(0, api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
-
-  // Read buffers.
-  std::array<DvrReadBuffer*, kQueueCapacity> rbs;
-  // Write buffers.
-  std::array<DvrWriteBuffer*, kQueueCapacity> wbs;
-  // Buffer metadata.
-  std::array<DvrNativeBufferMetadata, kQueueCapacity> metas;
-  // Hardware buffers for Read buffers.
-  std::unordered_map<int, AHardwareBuffer*> rhbs;
-  // Hardware buffers for Write buffers.
-  std::unordered_map<int, AHardwareBuffer*> whbs;
-
-  constexpr int kNumTests = 100;
-
-  // This test runs the following operations many many times. Thus we prefer to
-  // use ASSERT_XXX rather than EXPECT_XXX to avoid spamming the output.
-  std::function<void(size_t i)> Gain = [&](size_t i) {
-    int ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10,
-                                              &wbs[i], &metas[i], &fence_fd);
-    ASSERT_EQ(ret, 0);
-    ASSERT_LT(fence_fd, 0);  // expect invalid fence.
-    ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i]));
-    int buffer_id = api_.WriteBufferGetId(wbs[i]);
-    ASSERT_GT(buffer_id, 0);
-
-    AHardwareBuffer* hb = nullptr;
-    ASSERT_EQ(0, api_.WriteBufferGetAHardwareBuffer(wbs[i], &hb));
-
-    auto whb_it = whbs.find(buffer_id);
-    if (whb_it == whbs.end()) {
-      // If this is a new buffer id, check that total number of unique
-      // hardware buffers won't exceed queue capacity.
-      ASSERT_LT(whbs.size(), kQueueCapacity);
-      whbs.emplace(buffer_id, hb);
-    } else {
-      // If this is a buffer id we have seen before, check that the
-      // buffer_id maps to the same AHardwareBuffer handle.
-      ASSERT_EQ(hb, whb_it->second);
-    }
-  };
-
-  std::function<void(size_t i)> Post = [&](size_t i) {
-    ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i]));
-
-    metas[i].timestamp++;
-    int ret = api_.WriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i],
-                                              /*fence=*/-1);
-    ASSERT_EQ(ret, 0);
-  };
-
-  std::function<void(size_t i)> Acquire = [&](size_t i) {
-    int ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10,
-                                                &rbs[i], &metas[i], &fence_fd);
-    ASSERT_EQ(ret, 0);
-    ASSERT_LT(fence_fd, 0);  // expect invalid fence.
-    ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i]));
-
-    int buffer_id = api_.ReadBufferGetId(rbs[i]);
-    ASSERT_GT(buffer_id, 0);
-
-    AHardwareBuffer* hb = nullptr;
-    ASSERT_EQ(0, api_.ReadBufferGetAHardwareBuffer(rbs[i], &hb));
-
-    auto rhb_it = rhbs.find(buffer_id);
-    if (rhb_it == rhbs.end()) {
-      // If this is a new buffer id, check that total number of unique hardware
-      // buffers won't exceed queue capacity.
-      ASSERT_LT(rhbs.size(), kQueueCapacity);
-      rhbs.emplace(buffer_id, hb);
-    } else {
-      // If this is a buffer id we have seen before, check that the buffer_id
-      // maps to the same AHardwareBuffer handle.
-      ASSERT_EQ(hb, rhb_it->second);
-    }
-  };
-
-  std::function<void(size_t i)> Release = [&](size_t i) {
-    ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i]));
-
-    int ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i],
-                                                /*release_fence_fd=*/-1);
-    ASSERT_EQ(ret, 0);
-  };
-
-  // Scenario one:
-  for (int i = 0; i < kNumTests; i++) {
-    // Gain all write buffers.
-    for (size_t i = 0; i < kQueueCapacity; i++) {
-      ASSERT_NO_FATAL_FAILURE(Gain(i));
-    }
-    // Post all write buffers.
-    for (size_t i = 0; i < kQueueCapacity; i++) {
-      ASSERT_NO_FATAL_FAILURE(Post(i));
-    }
-    // Acquire all read buffers.
-    for (size_t i = 0; i < kQueueCapacity; i++) {
-      ASSERT_NO_FATAL_FAILURE(Acquire(i));
-    }
-    // Release all read buffers.
-    for (size_t i = 0; i < kQueueCapacity; i++) {
-      ASSERT_NO_FATAL_FAILURE(Release(i));
-    }
-  }
-
-  // Scenario two:
-  for (int i = 0; i < kNumTests; i++) {
-    // Gain and post all write buffers.
-    for (size_t i = 0; i < kQueueCapacity; i++) {
-      ASSERT_NO_FATAL_FAILURE(Gain(i));
-      ASSERT_NO_FATAL_FAILURE(Post(i));
-    }
-    // Acquire and release all read buffers.
-    for (size_t i = 0; i < kQueueCapacity; i++) {
-      ASSERT_NO_FATAL_FAILURE(Acquire(i));
-      ASSERT_NO_FATAL_FAILURE(Release(i));
-    }
-  }
-
-  // Scenario three:
-  for (int i = 0; i < kNumTests; i++) {
-    // Gain all write buffers then post them in reversed order.
-    for (size_t i = 0; i < kQueueCapacity; i++) {
-      ASSERT_NO_FATAL_FAILURE(Gain(i));
-    }
-    for (size_t i = 0; i < kQueueCapacity; i++) {
-      ASSERT_NO_FATAL_FAILURE(Post(kQueueCapacity - 1 - i));
-    }
-
-    // Acquire all write buffers then release them in reversed order.
-    for (size_t i = 0; i < kQueueCapacity; i++) {
-      ASSERT_NO_FATAL_FAILURE(Acquire(i));
-    }
-    for (size_t i = 0; i < kQueueCapacity; i++) {
-      ASSERT_NO_FATAL_FAILURE(Release(kQueueCapacity - 1 - i));
-    }
-  }
-}
-
-TEST_F(DvrBufferQueueTest, ConsumerReleaseAfterProducerDestroy) {
-  int ret = api_.WriteBufferQueueCreate(
-      kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
-      kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
-  ASSERT_EQ(ret, 0);
-
-  DvrReadBufferQueue* read_queue = nullptr;
-  DvrReadBuffer* rb = nullptr;
-  DvrWriteBuffer* wb = nullptr;
-  DvrNativeBufferMetadata meta1;
-  DvrNativeBufferMetadata meta2;
-  int fence_fd = -1;
-
-  ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
-  ASSERT_EQ(ret, 0);
-
-  api_.ReadBufferQueueSetBufferAvailableCallback(
-      read_queue, &BufferAvailableCallback, this);
-
-  // Gain buffer for writing.
-  ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb,
-                                        &meta1, &fence_fd);
-  ASSERT_EQ(ret, 0);
-  close(fence_fd);
-
-  // Post buffer to the read_queue.
-  ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
-  ASSERT_EQ(ret, 0);
-  wb = nullptr;
-
-  // Acquire buffer for reading.
-  ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb,
-                                          &meta2, &fence_fd);
-  ASSERT_EQ(ret, 0);
-  close(fence_fd);
-
-  // Destroy the write buffer queue and make sure the reader queue is picking
-  // these events up.
-  api_.WriteBufferQueueDestroy(write_queue_);
-  ret = api_.ReadBufferQueueHandleEvents(read_queue);
-  ASSERT_EQ(0, ret);
-
-  // Release buffer to the write_queue.
-  ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
-                                          /*release_fence_fd=*/-1);
-  ASSERT_EQ(ret, 0);
-  rb = nullptr;
-
-  api_.ReadBufferQueueDestroy(read_queue);
-}
-
-}  // namespace
diff --git a/libs/vr/libdvr/tests/dvr_display-test.cpp b/libs/vr/libdvr/tests/dvr_display-test.cpp
deleted file mode 100644
index c72f940..0000000
--- a/libs/vr/libdvr/tests/dvr_display-test.cpp
+++ /dev/null
@@ -1,351 +0,0 @@
-#include <android/hardware_buffer.h>
-#include <android/log.h>
-#include <dvr/dvr_api.h>
-#include <dvr/dvr_display_types.h>
-#include <dvr/dvr_surface.h>
-
-#include <gtest/gtest.h>
-
-#include "dvr_api_test.h"
-
-#define LOG_TAG "dvr_display-test"
-
-#ifndef ALOGD
-#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
-#endif
-
-class DvrDisplayTest : public DvrApiTest {
- protected:
-  void SetUp() override {
-    DvrApiTest::SetUp();
-    int ret = api_.GetNativeDisplayMetrics(sizeof(display_metrics_),
-                                           &display_metrics_);
-    ASSERT_EQ(ret, 0) << "Failed to get display metrics.";
-    ALOGD(
-        "display_width: %d, display_height: %d, display_x_dpi: %d, "
-        "display_y_dpi: %d, vsync_period_ns: %d.",
-        display_metrics_.display_width, display_metrics_.display_height,
-        display_metrics_.display_x_dpi, display_metrics_.display_y_dpi,
-        display_metrics_.vsync_period_ns);
-  }
-
-  void TearDown() override {
-    if (write_queue_ != nullptr) {
-      api_.WriteBufferQueueDestroy(write_queue_);
-      write_queue_ = nullptr;
-    }
-    if (direct_surface_ != nullptr) {
-      api_.SurfaceDestroy(direct_surface_);
-      direct_surface_ = nullptr;
-    }
-    DvrApiTest::TearDown();
-  }
-
-  /* Convert a write buffer to an android hardware buffer and fill in
-   * color_textures evenly to the buffer.
-   * AssertionError if the width of the buffer is not equal to the input width,
-   * AssertionError if the height of the buffer is not equal to the input
-   * height.
-   */
-  void FillWriteBuffer(DvrWriteBuffer* write_buffer,
-                       const std::vector<uint32_t>& color_textures,
-                       uint32_t width, uint32_t height);
-
-  // Write buffer queue properties.
-  static constexpr uint64_t kUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
-                                     AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
-                                     AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
-  uint32_t kFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
-  static constexpr size_t kMetadataSize = 0;
-  static constexpr int kTimeoutMs = 1000;  // Time for getting buffer.
-  uint32_t kLayerCount = 1;
-  DvrWriteBufferQueue* write_queue_ = nullptr;
-  DvrSurface* direct_surface_ = nullptr;
-
-  // Device display properties.
-  DvrNativeDisplayMetrics display_metrics_;
-};
-
-TEST_F(DvrDisplayTest, DisplayWithOneBuffer) {
-  // Create a direct surface.
-  std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
-      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
-       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
-       .value.bool_value = true},
-      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
-       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
-       .value.int32_value = 10},
-      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
-       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
-       .value.bool_value = true},
-  };
-  int ret =
-      api_.SurfaceCreate(direct_surface_attributes.data(),
-                         direct_surface_attributes.size(), &direct_surface_);
-  ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
-
-  // Create a buffer queue with the direct surface.
-  constexpr size_t kCapacity = 1;
-  uint32_t width = display_metrics_.display_width;
-  uint32_t height = display_metrics_.display_height;
-  ret = api_.SurfaceCreateWriteBufferQueue(
-      direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
-      kMetadataSize, &write_queue_);
-  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
-  ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
-
-  // Get buffer from WriteBufferQueue.
-  DvrWriteBuffer* write_buffer = nullptr;
-  DvrNativeBufferMetadata out_meta;
-  int out_fence_fd = -1;
-  ret = api_.WriteBufferQueueGainBuffer(write_queue_, kTimeoutMs, &write_buffer,
-                                        &out_meta, &out_fence_fd);
-  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
-  ASSERT_NE(nullptr, write_buffer) << "Gained buffer should not be null.";
-
-  // Color the write buffer.
-  FillWriteBuffer(write_buffer,
-                  {0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
-                  width, height);
-
-  // Post buffer.
-  int ready_fence_fd = -1;
-  ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
-                                        ready_fence_fd);
-  EXPECT_EQ(0, ret) << "Failed to post the buffer.";
-
-  sleep(5);  // For visual check on the device under test.
-  // Should observe three primary colors on the screen center.
-}
-
-TEST_F(DvrDisplayTest, DisplayWithDoubleBuffering) {
-  // Create a direct surface.
-  std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
-      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
-       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
-       .value.bool_value = true},
-      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
-       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
-       .value.int32_value = 10},
-      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
-       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
-       .value.bool_value = true},
-  };
-  int ret =
-      api_.SurfaceCreate(direct_surface_attributes.data(),
-                         direct_surface_attributes.size(), &direct_surface_);
-  ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
-
-  // Create a buffer queue with the direct surface.
-  constexpr size_t kCapacity = 2;
-  uint32_t width = display_metrics_.display_width;
-  uint32_t height = display_metrics_.display_height;
-  ret = api_.SurfaceCreateWriteBufferQueue(
-      direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
-      kMetadataSize, &write_queue_);
-  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
-  ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
-
-  int num_display_cycles_in_5s = 5 / (display_metrics_.vsync_period_ns / 1e9);
-  ALOGD("The number of display cycles: %d", num_display_cycles_in_5s);
-  int bufferhub_id_prev_write_buffer = -1;
-  for (int i = 0; i < num_display_cycles_in_5s; ++i) {
-    // Get a buffer from the WriteBufferQueue.
-    DvrWriteBuffer* write_buffer = nullptr;
-    DvrNativeBufferMetadata out_meta;
-    int out_fence_fd = -1;
-    ret = api_.WriteBufferQueueGainBuffer(
-        write_queue_, kTimeoutMs, &write_buffer, &out_meta, &out_fence_fd);
-    EXPECT_EQ(0, ret) << "Failed to get the a write buffer.";
-    ASSERT_NE(nullptr, write_buffer) << "The gained buffer should not be null.";
-
-    int bufferhub_id = api_.WriteBufferGetId(write_buffer);
-    ALOGD("Display cycle: %d, bufferhub id of the write buffer: %d", i,
-          bufferhub_id);
-    EXPECT_NE(bufferhub_id_prev_write_buffer, bufferhub_id)
-        << "Double buffering should be using the two buffers in turns, not "
-           "reusing the same write buffer.";
-    bufferhub_id_prev_write_buffer = bufferhub_id;
-
-    // Color the write buffer.
-    if (i % 2) {
-      FillWriteBuffer(write_buffer, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
-                      height);
-    } else {
-      FillWriteBuffer(write_buffer, {0xff00ff00, 0xff0000ff, 0xffff0000}, width,
-                      height);
-    }
-
-    // Post the write buffer.
-    int ready_fence_fd = -1;
-    ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
-                                          ready_fence_fd);
-    EXPECT_EQ(0, ret) << "Failed to post the buffer.";
-  }
-  // Should observe blinking screen in secondary colors
-  // although it is actually displaying primary colors.
-}
-
-TEST_F(DvrDisplayTest, DisplayWithTwoHardwareLayers) {
-  // Create the direct_surface_0 of z order 10 and direct_surface_1 of z
-  // order 11.
-  DvrSurface* direct_surface_0 = nullptr;
-  std::vector<DvrSurfaceAttribute> direct_surface_0_attributes = {
-      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
-       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
-       .value.bool_value = true},
-      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
-       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
-       .value.int32_value = 10},
-      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
-       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
-       .value.bool_value = true},
-  };
-  int ret =
-      api_.SurfaceCreate(direct_surface_0_attributes.data(),
-                         direct_surface_0_attributes.size(), &direct_surface_0);
-  EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
-
-  DvrSurface* direct_surface_1 = nullptr;
-  std::vector<DvrSurfaceAttribute> direct_surface_1_attributes = {
-      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
-       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
-       .value.bool_value = true},
-      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
-       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
-       .value.int32_value = 11},
-      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
-       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
-       .value.bool_value = true},
-  };
-  ret =
-      api_.SurfaceCreate(direct_surface_1_attributes.data(),
-                         direct_surface_1_attributes.size(), &direct_surface_1);
-  EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
-
-  // Create a buffer queue for each of the direct surfaces.
-  constexpr size_t kCapacity = 1;
-  uint32_t width = display_metrics_.display_width;
-  uint32_t height = display_metrics_.display_height;
-
-  DvrWriteBufferQueue* write_queue_0 = nullptr;
-  ret = api_.SurfaceCreateWriteBufferQueue(
-      direct_surface_0, width, height, kFormat, kLayerCount, kUsage, kCapacity,
-      kMetadataSize, &write_queue_0);
-  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
-  EXPECT_NE(nullptr, write_queue_0) << "Write buffer queue should not be null.";
-
-  DvrWriteBufferQueue* write_queue_1 = nullptr;
-  ret = api_.SurfaceCreateWriteBufferQueue(
-      direct_surface_1, width, height, kFormat, kLayerCount, kUsage, kCapacity,
-      kMetadataSize, &write_queue_1);
-  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
-  EXPECT_NE(nullptr, write_queue_1) << "Write buffer queue should not be null.";
-
-  // Get a buffer from each of the write buffer queues.
-  DvrWriteBuffer* write_buffer_0 = nullptr;
-  DvrNativeBufferMetadata out_meta_0;
-  int out_fence_fd = -1;
-  ret = api_.WriteBufferQueueGainBuffer(
-      write_queue_0, kTimeoutMs, &write_buffer_0, &out_meta_0, &out_fence_fd);
-  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
-  EXPECT_NE(nullptr, write_buffer_0) << "Gained buffer should not be null.";
-
-  DvrWriteBuffer* write_buffer_1 = nullptr;
-  DvrNativeBufferMetadata out_meta_1;
-  out_fence_fd = -1;
-  ret = api_.WriteBufferQueueGainBuffer(
-      write_queue_1, kTimeoutMs, &write_buffer_1, &out_meta_1, &out_fence_fd);
-  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
-  EXPECT_NE(nullptr, write_buffer_1) << "Gained buffer should not be null.";
-
-  // Color the write buffers.
-  FillWriteBuffer(write_buffer_0, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
-                  height);
-  FillWriteBuffer(write_buffer_1, {0x7f00ff00, 0x7f0000ff, 0x7fff0000}, width,
-                  height);
-
-  // Post buffers.
-  int ready_fence_fd = -1;
-  ret = api_.WriteBufferQueuePostBuffer(write_queue_0, write_buffer_0,
-                                        &out_meta_0, ready_fence_fd);
-  EXPECT_EQ(0, ret) << "Failed to post the buffer.";
-
-  ready_fence_fd = -1;
-  ret = api_.WriteBufferQueuePostBuffer(write_queue_1, write_buffer_1,
-                                        &out_meta_1, ready_fence_fd);
-  EXPECT_EQ(0, ret) << "Failed to post the buffer.";
-
-  sleep(5);  // For visual check on the device under test.
-  // Should observe three secondary colors.
-
-  // Test finished. Clean up buffers and surfaces.
-  if (write_queue_0 != nullptr) {
-    api_.WriteBufferQueueDestroy(write_queue_0);
-    write_queue_0 = nullptr;
-  }
-  if (write_queue_1 != nullptr) {
-    api_.WriteBufferQueueDestroy(write_queue_1);
-    write_queue_1 = nullptr;
-  }
-  if (direct_surface_0 != nullptr) {
-    api_.SurfaceDestroy(direct_surface_0);
-  }
-  if (direct_surface_1 != nullptr) {
-    api_.SurfaceDestroy(direct_surface_1);
-  }
-}
-
-void DvrDisplayTest::FillWriteBuffer(
-    DvrWriteBuffer* write_buffer, const std::vector<uint32_t>& color_textures,
-    uint32_t width, uint32_t height) {
-  uint32_t num_colors = color_textures.size();
-  // Convert the first write buffer to an android hardware buffer.
-  AHardwareBuffer* ah_buffer = nullptr;
-  int ret = api_.WriteBufferGetAHardwareBuffer(write_buffer, &ah_buffer);
-  ASSERT_EQ(0, ret) << "Failed to get a hardware buffer from the write buffer.";
-  ASSERT_NE(nullptr, ah_buffer) << "AHardware buffer should not be null.";
-  AHardwareBuffer_Desc ah_buffer_describe;
-  AHardwareBuffer_describe(ah_buffer, &ah_buffer_describe);
-  ASSERT_EQ(ah_buffer_describe.format, kFormat)
-      << "The format of the android hardware buffer is wrong.";
-  ASSERT_EQ(ah_buffer_describe.layers, kLayerCount)
-      << "The obtained android hardware buffer should have 2 layers.";
-  ASSERT_EQ(ah_buffer_describe.width, width)
-      << "The obtained android hardware buffer width is wrong.";
-  ASSERT_EQ(ah_buffer_describe.height, height)
-      << "The obtained android hardware buffer height is wrong.";
-  // Change the content of the android hardware buffer.
-  void* buffer_data = nullptr;
-  int32_t fence = -1;
-  ret = AHardwareBuffer_lock(ah_buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
-                             fence, nullptr, &buffer_data);
-  ASSERT_EQ(0, ret) << "Failed to lock the hardware buffer.";
-  ASSERT_NE(nullptr, buffer_data) << "Buffer data should not be null.";
-
-  uint32_t num_pixels = width * height / num_colors;
-  for (uint32_t color_index = 0; color_index < num_colors - 1; ++color_index) {
-    uint32_t color_texture = color_textures[color_index];
-    for (uint32_t i = 0; i < num_pixels; ++i) {
-      memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
-                                     (i + num_pixels * color_index) *
-                                         sizeof(color_texture)),
-             &color_texture, sizeof(color_texture));
-    }
-  }
-  uint32_t color_texture = color_textures[num_colors - 1];
-  uint32_t num_colored_pixels = num_pixels * (num_colors - 1);
-  num_pixels = width * height - num_colored_pixels;
-  for (uint32_t i = 0; i < num_pixels; ++i) {
-    memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
-                                   (i + num_colored_pixels) *
-                                       sizeof(color_texture)),
-           &color_texture, sizeof(color_texture));
-  }
-  fence = -1;
-  ret = AHardwareBuffer_unlock(ah_buffer, &fence);
-  EXPECT_EQ(0, ret) << "Failed to unlock the hardware buffer.";
-
-  // Release the android hardware buffer.
-  AHardwareBuffer_release(ah_buffer);
-}
diff --git a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
deleted file mode 100644
index 07e2121..0000000
--- a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
+++ /dev/null
@@ -1,891 +0,0 @@
-#include <android-base/properties.h>
-#include <base/logging.h>
-#include <cutils/properties.h>
-#include <gtest/gtest.h>
-#include <log/log.h>
-#include <poll.h>
-
-#include <android/hardware_buffer.h>
-
-#include <algorithm>
-#include <array>
-#include <set>
-#include <thread>
-#include <vector>
-
-#include <dvr/dvr_configuration_data.h>
-#include <dvr/dvr_deleter.h>
-#include <dvr/dvr_display_manager.h>
-#include <dvr/dvr_surface.h>
-
-#include <pdx/status.h>
-
-using android::pdx::ErrorStatus;
-using android::pdx::Status;
-
-namespace android {
-namespace dvr {
-
-namespace {
-
-using ::testing::Test;
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, nullptr_t) {
-  DvrSurfaceAttribute attribute;
-  attribute.key = key;
-  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
-  return attribute;
-}
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int32_t value) {
-  DvrSurfaceAttribute attribute;
-  attribute.key = key;
-  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
-  attribute.value.int32_value = value;
-  return attribute;
-}
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int64_t value) {
-  DvrSurfaceAttribute attribute;
-  attribute.key = key;
-  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT64;
-  attribute.value.int64_value = value;
-  return attribute;
-}
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, bool value) {
-  DvrSurfaceAttribute attribute;
-  attribute.key = key;
-  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL;
-  attribute.value.bool_value = value;
-  return attribute;
-}
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, float value) {
-  DvrSurfaceAttribute attribute;
-  attribute.key = key;
-  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT;
-  attribute.value.float_value = value;
-  return attribute;
-}
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
-                                  const std::array<float, 2>& value) {
-  DvrSurfaceAttribute attribute;
-  attribute.key = key;
-  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2;
-  std::copy(value.begin(), value.end(), attribute.value.float2_value);
-  return attribute;
-}
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
-                                  const std::array<float, 3>& value) {
-  DvrSurfaceAttribute attribute;
-  attribute.key = key;
-  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3;
-  std::copy(value.begin(), value.end(), attribute.value.float3_value);
-  return attribute;
-}
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
-                                  const std::array<float, 4>& value) {
-  DvrSurfaceAttribute attribute;
-  attribute.key = key;
-  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4;
-  std::copy(value.begin(), value.end(), attribute.value.float4_value);
-  return attribute;
-}
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
-                                  const std::array<float, 8>& value) {
-  DvrSurfaceAttribute attribute;
-  attribute.key = key;
-  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8;
-  std::copy(value.begin(), value.end(), attribute.value.float8_value);
-  return attribute;
-}
-
-DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
-                                  const std::array<float, 16>& value) {
-  DvrSurfaceAttribute attribute;
-  attribute.key = key;
-  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16;
-  std::copy(value.begin(), value.end(), attribute.value.float16_value);
-  return attribute;
-}
-
-Status<UniqueDvrSurface> CreateApplicationSurface(bool visible = false,
-                                                  int32_t z_order = 0) {
-  DvrSurface* surface = nullptr;
-  DvrSurfaceAttribute attributes[] = {
-      MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, z_order),
-      MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, visible)};
-
-  const int ret = dvrSurfaceCreate(
-      attributes, std::extent<decltype(attributes)>::value, &surface);
-  if (ret < 0)
-    return ErrorStatus(-ret);
-  else
-    return {UniqueDvrSurface(surface)};
-}
-
-Status<UniqueDvrWriteBufferQueue> CreateSurfaceQueue(
-    const UniqueDvrSurface& surface, uint32_t width, uint32_t height,
-    uint32_t format, uint32_t layer_count, uint64_t usage, size_t capacity,
-    size_t metadata_size) {
-  DvrWriteBufferQueue* queue;
-  const int ret = dvrSurfaceCreateWriteBufferQueue(
-      surface.get(), width, height, format, layer_count, usage, capacity,
-      metadata_size, &queue);
-  if (ret < 0)
-    return ErrorStatus(-ret);
-  else
-    return {UniqueDvrWriteBufferQueue(queue)};
-}
-
-Status<std::vector<uint8_t>> GetConfigData(int config_type) {
-  uint8_t* data = nullptr;
-  size_t data_size = 0;
-  int error = dvrConfigurationDataGet(config_type, &data, &data_size);
-  if (error < 0) {
-    return ErrorStatus(-error);
-  }
-
-  if (!data || data_size == 0) {
-    return ErrorStatus(EINVAL);
-  }
-  std::vector<uint8_t> data_result(data, data + data_size);
-  dvrConfigurationDataDestroy(data);
-  std::string s(data, data + data_size);
-  return {std::move(data_result)};
-}
-
-class TestDisplayManager {
- public:
-  TestDisplayManager(UniqueDvrDisplayManager display_manager,
-                     UniqueDvrSurfaceState surface_state)
-      : display_manager_(std::move(display_manager)),
-        surface_state_(std::move(surface_state)) {
-    const int fd = dvrDisplayManagerGetEventFd(display_manager_.get());
-    LOG_IF(INFO, fd < 0) << "Failed to get event fd: " << strerror(-fd);
-    display_manager_event_fd_ = fd;
-  }
-
-  Status<UniqueDvrReadBufferQueue> GetReadBufferQueue(int surface_id,
-                                                      int queue_id) {
-    DvrReadBufferQueue* queue;
-    const int ret = dvrDisplayManagerGetReadBufferQueue(
-        display_manager_.get(), surface_id, queue_id, &queue);
-    if (ret < 0)
-      return ErrorStatus(-ret);
-    else
-      return {UniqueDvrReadBufferQueue(queue)};
-  }
-
-  Status<void> UpdateSurfaceState() {
-    const int ret = dvrDisplayManagerGetSurfaceState(display_manager_.get(),
-                                                     surface_state_.get());
-    if (ret < 0)
-      return ErrorStatus(-ret);
-    else
-      return {};
-  }
-
-  enum : int { kTimeoutMs = 10000 };  // 10s
-
-  Status<void> WaitForUpdate(int timeout_ms = kTimeoutMs) {
-    if (display_manager_event_fd_ < 0)
-      return ErrorStatus(-display_manager_event_fd_);
-
-    pollfd pfd = {display_manager_event_fd_, POLLIN, 0};
-    const int count = poll(&pfd, 1, timeout_ms);
-    if (count < 0)
-      return ErrorStatus(errno);
-    else if (count == 0)
-      return ErrorStatus(ETIMEDOUT);
-
-    int events;
-    const int ret = dvrDisplayManagerTranslateEpollEventMask(
-        display_manager_.get(), pfd.revents, &events);
-    if (ret < 0)
-      return ErrorStatus(-ret);
-    else if (events & POLLIN)
-      return UpdateSurfaceState();
-    else
-      return ErrorStatus(EPROTO);
-  }
-
-  Status<size_t> GetSurfaceCount() {
-    size_t count = 0;
-    const int ret =
-        dvrSurfaceStateGetSurfaceCount(surface_state_.get(), &count);
-    if (ret < 0)
-      return ErrorStatus(-ret);
-    else
-      return {count};
-  }
-
-  Status<DvrSurfaceUpdateFlags> GetUpdateFlags(size_t surface_index) {
-    DvrSurfaceUpdateFlags update_flags;
-    const int ret = dvrSurfaceStateGetUpdateFlags(surface_state_.get(),
-                                                  surface_index, &update_flags);
-    if (ret < 0)
-      return ErrorStatus(-ret);
-    else
-      return {update_flags};
-  }
-
-  Status<int> GetSurfaceId(size_t surface_index) {
-    int surface_id;
-    const int ret = dvrSurfaceStateGetSurfaceId(surface_state_.get(),
-                                                surface_index, &surface_id);
-    if (ret < 0)
-      return ErrorStatus(-ret);
-    else
-      return {surface_id};
-  }
-
-  Status<int> GetProcessId(size_t surface_index) {
-    int process_id;
-    const int ret = dvrSurfaceStateGetProcessId(surface_state_.get(),
-                                                surface_index, &process_id);
-    if (ret < 0)
-      return ErrorStatus(-ret);
-    else
-      return {process_id};
-  }
-
-  Status<std::vector<DvrSurfaceAttribute>> GetAttributes(size_t surface_index) {
-    std::vector<DvrSurfaceAttribute> attributes;
-    size_t count = 0;
-    const int ret = dvrSurfaceStateGetAttributeCount(surface_state_.get(),
-                                                     surface_index, &count);
-    if (ret < 0)
-      return ErrorStatus(-ret);
-
-    attributes.resize(count);
-    const ssize_t return_count = dvrSurfaceStateGetAttributes(
-        surface_state_.get(), surface_index, attributes.data(), count);
-    if (return_count < 0)
-      return ErrorStatus(-return_count);
-
-    attributes.resize(return_count);
-    return {std::move(attributes)};
-  }
-
-  Status<std::vector<int>> GetQueueIds(size_t surface_index) {
-    std::vector<int> queue_ids;
-    size_t count = 0;
-    const int ret = dvrSurfaceStateGetQueueCount(surface_state_.get(),
-                                                 surface_index, &count);
-    if (ret < 0)
-      return ErrorStatus(-ret);
-
-    if (count > 0) {
-      queue_ids.resize(count);
-      const ssize_t return_count = dvrSurfaceStateGetQueueIds(
-          surface_state_.get(), surface_index, queue_ids.data(), count);
-      if (return_count < 0)
-        return ErrorStatus(-return_count);
-
-      queue_ids.resize(return_count);
-    }
-
-    return {std::move(queue_ids)};
-  }
-
- private:
-  UniqueDvrDisplayManager display_manager_;
-  UniqueDvrSurfaceState surface_state_;
-
-  // Owned by object in display_manager_, do not explicitly close.
-  int display_manager_event_fd_;
-
-  TestDisplayManager(const TestDisplayManager&) = delete;
-  void operator=(const TestDisplayManager&) = delete;
-};
-
-class DvrDisplayManagerTest : public Test {
- protected:
-  void SetUp() override {
-    int ret;
-    DvrDisplayManager* display_manager;
-    DvrSurfaceState* surface_state;
-
-    ret = dvrDisplayManagerCreate(&display_manager);
-    ASSERT_EQ(0, ret) << "Failed to create display manager client";
-    ASSERT_NE(nullptr, display_manager);
-
-    ret = dvrSurfaceStateCreate(&surface_state);
-    ASSERT_EQ(0, ret) << "Failed to create surface state object";
-    ASSERT_NE(nullptr, surface_state);
-
-    manager_.reset(
-        new TestDisplayManager(UniqueDvrDisplayManager(display_manager),
-                               UniqueDvrSurfaceState(surface_state)));
-  }
-  void TearDown() override {}
-
-  std::unique_ptr<TestDisplayManager> manager_;
-};
-
-// TODO(eieio): Consider moving these somewhere more central because they are
-// broadly useful.
-
-template <typename T>
-testing::AssertionResult StatusOk(const char* status_expression,
-                                  const Status<T>& status) {
-  if (!status.ok()) {
-    return testing::AssertionFailure()
-           << "(" << status_expression
-           << ") expected to indicate success but actually contains error ("
-           << status.error() << ")";
-  } else {
-    return testing::AssertionSuccess();
-  }
-}
-
-template <typename T>
-testing::AssertionResult StatusError(const char* status_expression,
-                                     const Status<T>& status) {
-  if (status.ok()) {
-    return testing::AssertionFailure()
-           << "(" << status_expression
-           << ") expected to indicate error but instead indicates success.";
-  } else {
-    return testing::AssertionSuccess();
-  }
-}
-
-template <typename T>
-testing::AssertionResult StatusHasError(const char* status_expression,
-                                        const char* /*error_code_expression*/,
-                                        const Status<T>& status,
-                                        int error_code) {
-  if (status.ok()) {
-    return StatusError(status_expression, status);
-  } else if (status.error() != error_code) {
-    return testing::AssertionFailure()
-           << "(" << status_expression << ") expected to indicate error ("
-           << error_code << ") but actually indicates error (" << status.error()
-           << ")";
-  } else {
-    return testing::AssertionSuccess();
-  }
-}
-
-template <typename T, typename U>
-testing::AssertionResult StatusHasValue(const char* status_expression,
-                                        const char* /*value_expression*/,
-                                        const Status<T>& status,
-                                        const U& value) {
-  if (!status.ok()) {
-    return StatusOk(status_expression, status);
-  } else if (status.get() != value) {
-    return testing::AssertionFailure()
-           << "(" << status_expression << ") expected to contain value ("
-           << testing::PrintToString(value) << ") but actually contains value ("
-           << testing::PrintToString(status.get()) << ")";
-  } else {
-    return testing::AssertionSuccess();
-  }
-}
-
-template <typename T, typename Op>
-testing::AssertionResult StatusPred(const char* status_expression,
-                                    const char* pred_expression,
-                                    const Status<T>& status, Op pred) {
-  if (!status.ok()) {
-    return StatusOk(status_expression, status);
-  } else if (!pred(status.get())) {
-    return testing::AssertionFailure()
-           << status_expression << " value ("
-           << testing::PrintToString(status.get())
-           << ") failed to pass predicate " << pred_expression;
-  } else {
-    return testing::AssertionSuccess();
-  }
-}
-
-#define ASSERT_STATUS_OK(status) ASSERT_PRED_FORMAT1(StatusOk, status)
-#define ASSERT_STATUS_ERROR(status) ASSERT_PRED_FORMAT1(StatusError, status)
-
-#define ASSERT_STATUS_ERROR_VALUE(value, status) \
-  ASSERT_PRED_FORMAT2(StatusHasError, status, value)
-
-#define ASSERT_STATUS_EQ(value, status) \
-  ASSERT_PRED_FORMAT2(StatusHasValue, status, value)
-
-#define EXPECT_STATUS_OK(status) EXPECT_PRED_FORMAT1(StatusOk, status)
-#define EXPECT_STATUS_ERROR(status) EXPECT_PRED_FORMAT1(StatusError, status)
-
-#define EXPECT_STATUS_ERROR_VALUE(value, status) \
-  EXPECT_PRED_FORMAT2(StatusHasError, status, value)
-
-#define EXPECT_STATUS_EQ(value, status) \
-  EXPECT_PRED_FORMAT2(StatusHasValue, status, value)
-
-#define EXPECT_STATUS_PRED(pred, status) \
-  EXPECT_PRED_FORMAT2(StatusPred, status, pred)
-
-#if 0
-// Verify utility predicate/macro functionality. This section is commented out
-// because it is designed to fail in some cases to validate the helpers.
-TEST_F(Test, ExpectVoid) {
-  Status<void> status_error{ErrorStatus{EINVAL}};
-  Status<void> status_ok{};
-
-  EXPECT_STATUS_ERROR(status_error);
-  EXPECT_STATUS_ERROR(status_ok);
-  EXPECT_STATUS_OK(status_error);
-  EXPECT_STATUS_OK(status_ok);
-
-  EXPECT_STATUS_ERROR_VALUE(EINVAL, status_error);
-  EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_error);
-  EXPECT_STATUS_ERROR_VALUE(EINVAL, status_ok);
-  EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_ok);
-}
-
-TEST_F(Test, ExpectInt) {
-  Status<int> status_error{ErrorStatus{EINVAL}};
-  Status<int> status_ok{10};
-
-  EXPECT_STATUS_ERROR(status_error);
-  EXPECT_STATUS_ERROR(status_ok);
-  EXPECT_STATUS_OK(status_error);
-  EXPECT_STATUS_OK(status_ok);
-
-  EXPECT_STATUS_ERROR_VALUE(EINVAL, status_error);
-  EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_error);
-  EXPECT_STATUS_ERROR_VALUE(EINVAL, status_ok);
-  EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_ok);
-
-  EXPECT_STATUS_EQ(10, status_error);
-  EXPECT_STATUS_EQ(20, status_error);
-  EXPECT_STATUS_EQ(10, status_ok);
-  EXPECT_STATUS_EQ(20, status_ok);
-
-  auto pred1 = [](const auto& value) { return value < 15; };
-  auto pred2 = [](const auto& value) { return value > 5; };
-  auto pred3 = [](const auto& value) { return value > 15; };
-  auto pred4 = [](const auto& value) { return value < 5; };
-
-  EXPECT_STATUS_PRED(pred1, status_error);
-  EXPECT_STATUS_PRED(pred2, status_error);
-  EXPECT_STATUS_PRED(pred3, status_error);
-  EXPECT_STATUS_PRED(pred4, status_error);
-  EXPECT_STATUS_PRED(pred1, status_ok);
-  EXPECT_STATUS_PRED(pred2, status_ok);
-  EXPECT_STATUS_PRED(pred3, status_ok);
-  EXPECT_STATUS_PRED(pred4, status_ok);
-}
-#endif
-
-TEST_F(DvrDisplayManagerTest, SurfaceCreateEvent) {
-  // Get surface state and verify there are no surfaces.
-  ASSERT_STATUS_OK(manager_->UpdateSurfaceState());
-  ASSERT_STATUS_EQ(0u, manager_->GetSurfaceCount());
-
-  // Get flags for invalid surface index.
-  EXPECT_STATUS_ERROR_VALUE(EINVAL, manager_->GetUpdateFlags(0));
-
-  // Create an application surface.
-  auto surface_status = CreateApplicationSurface();
-  ASSERT_STATUS_OK(surface_status);
-  UniqueDvrSurface surface = surface_status.take();
-  ASSERT_NE(nullptr, surface.get());
-
-  const int surface_id = dvrSurfaceGetId(surface.get());
-  ASSERT_GE(surface_id, 0);
-
-  // Now there should be one new surface.
-  ASSERT_STATUS_OK(manager_->WaitForUpdate());
-  EXPECT_STATUS_EQ(1u, manager_->GetSurfaceCount());
-
-  // Verify the new surface flag is set.
-  auto check_flags = [](const auto& value) {
-    return value & DVR_SURFACE_UPDATE_FLAGS_NEW_SURFACE;
-  };
-  EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
-
-  // Verify the surface id matches.
-  EXPECT_STATUS_EQ(surface_id, manager_->GetSurfaceId(0));
-
-  // Verify the owning process of the surface.
-  EXPECT_STATUS_EQ(getpid(), manager_->GetProcessId(0));
-
-  surface.reset();
-
-  ASSERT_STATUS_OK(manager_->WaitForUpdate());
-  EXPECT_STATUS_EQ(0u, manager_->GetSurfaceCount());
-}
-
-TEST_F(DvrDisplayManagerTest, SurfaceAttributeEvent) {
-  // Get surface state and verify there are no surfaces.
-  ASSERT_STATUS_OK(manager_->UpdateSurfaceState());
-  ASSERT_STATUS_EQ(0u, manager_->GetSurfaceCount());
-
-  // Get attributes for an invalid surface index.
-  EXPECT_STATUS_ERROR_VALUE(EINVAL, manager_->GetAttributes(0));
-
-  const bool kInitialVisibility = true;
-  const int32_t kInitialZOrder = 10;
-  auto surface_status =
-      CreateApplicationSurface(kInitialVisibility, kInitialZOrder);
-  ASSERT_STATUS_OK(surface_status);
-  auto surface = surface_status.take();
-  ASSERT_NE(nullptr, surface.get());
-
-  ASSERT_STATUS_OK(manager_->WaitForUpdate());
-  ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
-
-  // Check the initial attribute values.
-  auto attribute_status = manager_->GetAttributes(0);
-  ASSERT_STATUS_OK(attribute_status);
-  auto attributes = attribute_status.take();
-  EXPECT_GE(attributes.size(), 2u);
-
-  std::set<int32_t> actual_keys;
-  std::set<int32_t> expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
-                                     DVR_SURFACE_ATTRIBUTE_VISIBLE};
-
-  // Collect all the keys in attributes that match the expected keys.
-  auto compare_keys = [](const auto& attributes, const auto& expected_keys) {
-    std::set<int32_t> keys;
-    for (const auto& attribute : attributes) {
-      if (expected_keys.find(attribute.key) != expected_keys.end())
-        keys.emplace(attribute.key);
-    }
-    return keys;
-  };
-
-  // If the sets match then attributes contained at least the expected keys,
-  // even if other keys were also present.
-  actual_keys = compare_keys(attributes, expected_keys);
-  EXPECT_EQ(expected_keys, actual_keys);
-
-  std::vector<DvrSurfaceAttribute> attributes_to_set = {
-      MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, 0)};
-
-  // Test invalid args.
-  EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(nullptr, attributes_to_set.data(),
-                                             attributes_to_set.size()));
-  EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(surface.get(), nullptr,
-                                             attributes_to_set.size()));
-
-  // Test attribute change events.
-  ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
-                                       attributes_to_set.size()));
-  ASSERT_STATUS_OK(manager_->WaitForUpdate());
-
-  // Verify the attributes changed flag is set.
-  auto check_flags = [](const auto& value) {
-    return value & DVR_SURFACE_UPDATE_FLAGS_ATTRIBUTES_CHANGED;
-  };
-  EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
-
-  attribute_status = manager_->GetAttributes(0);
-  ASSERT_STATUS_OK(attribute_status);
-  attributes = attribute_status.take();
-  EXPECT_GE(attributes.size(), 2u);
-
-  expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
-                   DVR_SURFACE_ATTRIBUTE_VISIBLE};
-
-  actual_keys.clear();
-  actual_keys = compare_keys(attributes, expected_keys);
-  EXPECT_EQ(expected_keys, actual_keys);
-
-  // Test setting and then deleting an attribute.
-  const DvrSurfaceAttributeKey kUserKey = 1;
-  attributes_to_set = {MakeAttribute(kUserKey, 1024)};
-
-  ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
-                                       attributes_to_set.size()));
-  ASSERT_STATUS_OK(manager_->WaitForUpdate());
-  EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
-
-  attribute_status = manager_->GetAttributes(0);
-  ASSERT_STATUS_OK(attribute_status);
-  attributes = attribute_status.take();
-  EXPECT_GE(attributes.size(), 2u);
-
-  expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE,
-                   kUserKey};
-
-  actual_keys.clear();
-  actual_keys = compare_keys(attributes, expected_keys);
-  EXPECT_EQ(expected_keys, actual_keys);
-
-  // Delete the attribute.
-  attributes_to_set = {MakeAttribute(kUserKey, nullptr)};
-
-  ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
-                                       attributes_to_set.size()));
-  ASSERT_STATUS_OK(manager_->WaitForUpdate());
-  EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
-
-  attribute_status = manager_->GetAttributes(0);
-  ASSERT_STATUS_OK(attribute_status);
-  attributes = attribute_status.take();
-  EXPECT_GE(attributes.size(), 2u);
-
-  expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE,
-                   kUserKey};
-
-  actual_keys.clear();
-  actual_keys = compare_keys(attributes, expected_keys);
-  EXPECT_NE(expected_keys, actual_keys);
-
-  // Test deleting a reserved attribute.
-  attributes_to_set = {MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, nullptr)};
-
-  EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
-                                       attributes_to_set.size()));
-
-  // Failed attribute operations should not trigger update events.
-  const int kTimeoutMs = 100;  // 0.1s
-  EXPECT_STATUS_ERROR_VALUE(ETIMEDOUT, manager_->WaitForUpdate(kTimeoutMs));
-
-  attribute_status = manager_->GetAttributes(0);
-  ASSERT_STATUS_OK(attribute_status);
-  attributes = attribute_status.take();
-  EXPECT_GE(attributes.size(), 2u);
-
-  expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
-                   DVR_SURFACE_ATTRIBUTE_VISIBLE};
-
-  actual_keys.clear();
-  actual_keys = compare_keys(attributes, expected_keys);
-  EXPECT_EQ(expected_keys, actual_keys);
-}
-
-TEST_F(DvrDisplayManagerTest, SurfaceAttributeTypes) {
-  // Create an application surface.
-  auto surface_status = CreateApplicationSurface();
-  ASSERT_STATUS_OK(surface_status);
-  UniqueDvrSurface surface = surface_status.take();
-  ASSERT_NE(nullptr, surface.get());
-
-  enum : std::int32_t {
-    kInt32Key = 1,
-    kInt64Key,
-    kBoolKey,
-    kFloatKey,
-    kFloat2Key,
-    kFloat3Key,
-    kFloat4Key,
-    kFloat8Key,
-    kFloat16Key,
-  };
-
-  const std::vector<DvrSurfaceAttribute> attributes_to_set = {
-      MakeAttribute(kInt32Key, int32_t{0}),
-      MakeAttribute(kInt64Key, int64_t{0}),
-      MakeAttribute(kBoolKey, false),
-      MakeAttribute(kFloatKey, 0.0f),
-      MakeAttribute(kFloat2Key, std::array<float, 2>{{1.0f, 2.0f}}),
-      MakeAttribute(kFloat3Key, std::array<float, 3>{{3.0f, 4.0f, 5.0f}}),
-      MakeAttribute(kFloat4Key, std::array<float, 4>{{6.0f, 7.0f, 8.0f, 9.0f}}),
-      MakeAttribute(kFloat8Key,
-                    std::array<float, 8>{{10.0f, 11.0f, 12.0f, 13.0f, 14.0f,
-                                          15.0f, 16.0f, 17.0f}}),
-      MakeAttribute(kFloat16Key, std::array<float, 16>{
-                                     {18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f,
-                                      24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f,
-                                      30.0f, 31.0f, 32.0f, 33.0f}})};
-
-  EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
-                                       attributes_to_set.size()));
-
-  ASSERT_STATUS_OK(manager_->WaitForUpdate());
-  auto attribute_status = manager_->GetAttributes(0);
-  ASSERT_STATUS_OK(attribute_status);
-  auto attributes = attribute_status.take();
-  EXPECT_GE(attributes.size(), attributes_to_set.size());
-
-  auto HasAttribute = [](const auto& attributes,
-                         DvrSurfaceAttributeKey key) -> bool {
-    for (const auto& attribute : attributes) {
-      if (attribute.key == key)
-        return true;
-    }
-    return false;
-  };
-  auto AttributeType =
-      [](const auto& attributes,
-         DvrSurfaceAttributeKey key) -> DvrSurfaceAttributeType {
-    for (const auto& attribute : attributes) {
-      if (attribute.key == key)
-        return attribute.value.type;
-    }
-    return DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
-  };
-
-  ASSERT_TRUE(HasAttribute(attributes, kInt32Key));
-  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
-            AttributeType(attributes, kInt32Key));
-
-  ASSERT_TRUE(HasAttribute(attributes, kInt64Key));
-  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT64,
-            AttributeType(attributes, kInt64Key));
-
-  ASSERT_TRUE(HasAttribute(attributes, kBoolKey));
-  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
-            AttributeType(attributes, kBoolKey));
-
-  ASSERT_TRUE(HasAttribute(attributes, kFloatKey));
-  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT,
-            AttributeType(attributes, kFloatKey));
-
-  ASSERT_TRUE(HasAttribute(attributes, kFloat2Key));
-  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2,
-            AttributeType(attributes, kFloat2Key));
-
-  ASSERT_TRUE(HasAttribute(attributes, kFloat3Key));
-  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3,
-            AttributeType(attributes, kFloat3Key));
-
-  ASSERT_TRUE(HasAttribute(attributes, kFloat4Key));
-  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4,
-            AttributeType(attributes, kFloat4Key));
-
-  ASSERT_TRUE(HasAttribute(attributes, kFloat8Key));
-  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8,
-            AttributeType(attributes, kFloat8Key));
-
-  ASSERT_TRUE(HasAttribute(attributes, kFloat16Key));
-  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16,
-            AttributeType(attributes, kFloat16Key));
-}
-
-TEST_F(DvrDisplayManagerTest, SurfaceQueueEvent) {
-  // Create an application surface.
-  auto surface_status = CreateApplicationSurface();
-  ASSERT_STATUS_OK(surface_status);
-  UniqueDvrSurface surface = surface_status.take();
-  ASSERT_NE(nullptr, surface.get());
-
-  const int surface_id = dvrSurfaceGetId(surface.get());
-  ASSERT_GE(surface_id, 0);
-  // Get surface state and verify there is one surface.
-  ASSERT_STATUS_OK(manager_->WaitForUpdate());
-  ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
-
-  // Verify there are no queues for the surface recorded in the state
-  // snapshot.
-  EXPECT_STATUS_EQ(std::vector<int>{}, manager_->GetQueueIds(0));
-
-  // Create a new queue in the surface.
-  auto write_queue_status = CreateSurfaceQueue(
-      surface, 320, 240, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 1,
-      AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1, 0);
-  ASSERT_STATUS_OK(write_queue_status);
-  UniqueDvrWriteBufferQueue write_queue = write_queue_status.take();
-  ASSERT_NE(nullptr, write_queue.get());
-
-  const int queue_id = dvrWriteBufferQueueGetId(write_queue.get());
-  ASSERT_GE(queue_id, 0);
-
-  // Update surface state.
-  ASSERT_STATUS_OK(manager_->WaitForUpdate());
-  ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
-
-  // Verify the buffers changed flag is set.
-  auto check_flags = [](const auto& value) {
-    return value & DVR_SURFACE_UPDATE_FLAGS_BUFFERS_CHANGED;
-  };
-  EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
-
-  auto queue_ids_status = manager_->GetQueueIds(0);
-  ASSERT_STATUS_OK(queue_ids_status);
-
-  auto queue_ids = queue_ids_status.take();
-  ASSERT_EQ(1u, queue_ids.size());
-  EXPECT_EQ(queue_id, queue_ids[0]);
-
-  auto read_queue_status = manager_->GetReadBufferQueue(surface_id, queue_id);
-  ASSERT_STATUS_OK(read_queue_status);
-  UniqueDvrReadBufferQueue read_queue = read_queue_status.take();
-  ASSERT_NE(nullptr, read_queue.get());
-  EXPECT_EQ(queue_id, dvrReadBufferQueueGetId(read_queue.get()));
-
-  write_queue.reset();
-
-  // Verify that destroying the queue generates a surface update event.
-  ASSERT_STATUS_OK(manager_->WaitForUpdate());
-  ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
-
-  // Verify that the buffers changed flag is set.
-  EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
-
-  // Verify that the queue ids reflect the change.
-  queue_ids_status = manager_->GetQueueIds(0);
-  ASSERT_STATUS_OK(queue_ids_status);
-
-  queue_ids = queue_ids_status.take();
-  ASSERT_EQ(0u, queue_ids.size());
-}
-
-TEST_F(DvrDisplayManagerTest, MultiLayerBufferQueue) {
-  // Create an application surface.
-  auto surface_status = CreateApplicationSurface();
-  ASSERT_STATUS_OK(surface_status);
-  UniqueDvrSurface surface = surface_status.take();
-  ASSERT_NE(nullptr, surface.get());
-
-  // Get surface state and verify there is one surface.
-  ASSERT_STATUS_OK(manager_->WaitForUpdate());
-  ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
-
-  // Create a new queue in the surface.
-  const uint32_t kLayerCount = 3;
-  auto write_queue_status = CreateSurfaceQueue(
-      surface, 320, 240, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, kLayerCount,
-      AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1, 0);
-  ASSERT_STATUS_OK(write_queue_status);
-  UniqueDvrWriteBufferQueue write_queue = write_queue_status.take();
-  ASSERT_NE(nullptr, write_queue.get());
-
-  DvrWriteBuffer* buffer = nullptr;
-  DvrNativeBufferMetadata metadata;
-  int fence_fd = -1;
-  int error = dvrWriteBufferQueueGainBuffer(write_queue.get(), /*timeout=*/1000,
-                                            &buffer, &metadata, &fence_fd);
-  ASSERT_EQ(0, error);
-
-  AHardwareBuffer* hardware_buffer = nullptr;
-  error = dvrWriteBufferGetAHardwareBuffer(buffer, &hardware_buffer);
-  ASSERT_EQ(0, error);
-
-  AHardwareBuffer_Desc desc = {};
-  AHardwareBuffer_describe(hardware_buffer, &desc);
-  ASSERT_EQ(kLayerCount, desc.layers);
-
-  AHardwareBuffer_release(hardware_buffer);
-  dvrWriteBufferDestroy(buffer);
-}
-
-TEST_F(Test, ConfigurationData) {
-  // TODO(hendrikw): Move this test and GetConfigData helper function out of the
-  // display manager tests.
-  auto data1 = GetConfigData(-1);
-  ASSERT_STATUS_ERROR(data1);
-
-  const char kDvrLensMetricsProperty[] = "ro.dvr.lens_metrics";
-
-  // This should be run on devices with and without built in metrics.
-  bool has_metric = !base::GetProperty(kDvrLensMetricsProperty, "").empty();
-  auto data2 = GetConfigData(DVR_CONFIGURATION_DATA_LENS_METRICS);
-  if (has_metric) {
-    ASSERT_STATUS_OK(data2);
-    ASSERT_NE(0u, data2.get().size());
-  } else {
-    ASSERT_STATUS_ERROR(data2);
-  }
-}
-
-}  // namespace
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
deleted file mode 100644
index 5c837e7..0000000
--- a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
+++ /dev/null
@@ -1,284 +0,0 @@
-#include <android/hardware_buffer.h>
-#include <dvr/dvr_buffer.h>
-#include <dvr/dvr_config.h>
-#include <dvr/dvr_shared_buffers.h>
-#include <dvr/dvr_surface.h>
-#include <system/graphics.h>
-
-#include <gtest/gtest.h>
-
-namespace android {
-namespace dvr {
-
-namespace {
-
-TEST(DvrGlobalBufferTest, TestGlobalBuffersSameName) {
-  const DvrGlobalBufferKey buffer_key = 101;
-  DvrBuffer* buffer1 = nullptr;
-  int ret1 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer1);
-  ASSERT_EQ(0, ret1);
-  ASSERT_NE(nullptr, buffer1);
-
-  DvrBuffer* buffer2 = nullptr;
-  int ret2 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer2);
-  ASSERT_EQ(0, ret2);
-  ASSERT_NE(nullptr, buffer2);
-
-  AHardwareBuffer* hardware_buffer1 = nullptr;
-  int e1 = dvrBufferGetAHardwareBuffer(buffer1, &hardware_buffer1);
-  ASSERT_EQ(0, e1);
-  ASSERT_NE(nullptr, hardware_buffer1);
-
-  AHardwareBuffer* hardware_buffer2 = nullptr;
-  int e2 = dvrBufferGetAHardwareBuffer(buffer2, &hardware_buffer2);
-  ASSERT_EQ(0, e2);
-  ASSERT_NE(nullptr, hardware_buffer2);
-
-  AHardwareBuffer_Desc desc1 = {};
-  AHardwareBuffer_describe(hardware_buffer1, &desc1);
-  AHardwareBuffer_Desc desc2 = {};
-  AHardwareBuffer_describe(hardware_buffer2, &desc2);
-  ASSERT_EQ(desc1.width, 10u);
-  ASSERT_EQ(desc1.height, 1u);
-  ASSERT_EQ(desc1.layers, 1u);
-  ASSERT_EQ(desc1.format, HAL_PIXEL_FORMAT_BLOB);
-  ASSERT_EQ(desc1.usage, 0u);
-  ASSERT_EQ(desc2.width, 10u);
-  ASSERT_EQ(desc2.height, 1u);
-  ASSERT_EQ(desc2.layers, 1u);
-  ASSERT_EQ(desc2.format, HAL_PIXEL_FORMAT_BLOB);
-  ASSERT_EQ(desc2.usage, 0u);
-
-  dvrBufferDestroy(buffer1);
-  dvrBufferDestroy(buffer2);
-
-  DvrBuffer* buffer3 = nullptr;
-  int e3 = dvrGetGlobalBuffer(buffer_key, &buffer3);
-  ASSERT_NE(nullptr, buffer3);
-  ASSERT_EQ(0, e3);
-
-  AHardwareBuffer* hardware_buffer3 = nullptr;
-  int e4 = dvrBufferGetAHardwareBuffer(buffer3, &hardware_buffer3);
-  ASSERT_EQ(0, e4);
-  ASSERT_NE(nullptr, hardware_buffer3);
-
-  AHardwareBuffer_Desc desc3 = {};
-  AHardwareBuffer_describe(hardware_buffer3, &desc3);
-  ASSERT_EQ(desc3.width, 10u);
-  ASSERT_EQ(desc3.height, 1u);
-  ASSERT_EQ(desc3.layers, 1u);
-  ASSERT_EQ(desc3.format, HAL_PIXEL_FORMAT_BLOB);
-  ASSERT_EQ(desc3.usage, 0u);
-
-  dvrBufferDestroy(buffer3);
-
-  AHardwareBuffer_release(hardware_buffer1);
-  AHardwareBuffer_release(hardware_buffer2);
-  AHardwareBuffer_release(hardware_buffer3);
-}
-
-TEST(DvrGlobalBufferTest, TestMultipleGlobalBuffers) {
-  const DvrGlobalBufferKey buffer_key1 = 102;
-  const DvrGlobalBufferKey buffer_key2 = 103;
-  DvrBuffer* setup_buffer1 = nullptr;
-  int ret1 = dvrSetupGlobalBuffer(buffer_key1, 10, 0, &setup_buffer1);
-  ASSERT_EQ(0, ret1);
-  ASSERT_NE(nullptr, setup_buffer1);
-  dvrBufferDestroy(setup_buffer1);
-
-  DvrBuffer* setup_buffer2 = nullptr;
-  int ret2 = dvrSetupGlobalBuffer(buffer_key2, 10, 0, &setup_buffer2);
-  ASSERT_EQ(0, ret2);
-  ASSERT_NE(nullptr, setup_buffer2);
-  dvrBufferDestroy(setup_buffer2);
-
-  DvrBuffer* buffer1 = nullptr;
-  int e1 = dvrGetGlobalBuffer(buffer_key1, &buffer1);
-  ASSERT_NE(nullptr, buffer1);
-  ASSERT_EQ(0, e1);
-  dvrBufferDestroy(buffer1);
-
-  DvrBuffer* buffer2 = nullptr;
-  int e2 = dvrGetGlobalBuffer(buffer_key2, &buffer2);
-  ASSERT_NE(nullptr, buffer2);
-  ASSERT_EQ(0, e2);
-  dvrBufferDestroy(buffer2);
-}
-
-TEST(DvrGlobalBufferTest, TestGlobalBufferUsage) {
-  const DvrGlobalBufferKey buffer_key = 100;
-
-  // Set usage to AHARDWAREBUFFER_USAGE_VIDEO_ENCODE. We use this because
-  // internally AHARDWAREBUFFER_USAGE_VIDEO_ENCODE is converted to
-  // GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER, and these two values are different.
-  // If all is good, when we get the AHardwareBuffer, it should be converted
-  // back to AHARDWAREBUFFER_USAGE_VIDEO_ENCODE.
-  const uint64_t usage = AHARDWAREBUFFER_USAGE_VIDEO_ENCODE;
-
-  DvrBuffer* setup_buffer = nullptr;
-  int e1 = dvrSetupGlobalBuffer(buffer_key, 10, usage, &setup_buffer);
-  ASSERT_NE(nullptr, setup_buffer);
-  ASSERT_EQ(0, e1);
-
-  AHardwareBuffer* hardware_buffer = nullptr;
-  int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer);
-  ASSERT_EQ(0, e2);
-  ASSERT_NE(nullptr, hardware_buffer);
-
-  AHardwareBuffer_Desc desc = {};
-  AHardwareBuffer_describe(hardware_buffer, &desc);
-  ASSERT_EQ(usage, desc.usage);
-
-  dvrBufferDestroy(setup_buffer);
-  AHardwareBuffer_release(hardware_buffer);
-}
-
-TEST(DvrGlobalBufferTest, TestGlobalBufferCarriesData) {
-  const DvrGlobalBufferKey buffer_name = 110;
-
-  uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
-                   AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
-  constexpr size_t size = 1024 * sizeof(uint64_t);
-  constexpr uint64_t value = 0x123456787654321;
-
-  {
-    // Allocate some data and set it to something.
-    DvrBuffer* setup_buffer = nullptr;
-    int e1 = dvrSetupGlobalBuffer(buffer_name, size, usage, &setup_buffer);
-    ASSERT_NE(nullptr, setup_buffer);
-    ASSERT_EQ(0, e1);
-
-    AHardwareBuffer* hardware_buffer = nullptr;
-    int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer);
-    ASSERT_EQ(0, e2);
-    ASSERT_NE(nullptr, hardware_buffer);
-
-    void* buffer;
-    int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer);
-    ASSERT_EQ(0, e3);
-    ASSERT_NE(nullptr, buffer);
-    // Verify that the buffer pointer is at least 16 byte aligned.
-    ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
-
-    uint64_t* data = static_cast<uint64_t*>(buffer);
-    constexpr size_t num_values = size / sizeof(uint64_t);
-    for (size_t i = 0; i < num_values; ++i) {
-      data[i] = value;
-    }
-
-    int32_t fence = -1;
-    int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
-    ASSERT_EQ(0, e4);
-
-    dvrBufferDestroy(setup_buffer);
-    AHardwareBuffer_release(hardware_buffer);
-  }
-
-  {
-    // Get the buffer and check that all the data is still present.
-    DvrBuffer* setup_buffer = nullptr;
-    int e1 = dvrGetGlobalBuffer(buffer_name, &setup_buffer);
-    ASSERT_NE(nullptr, setup_buffer);
-    ASSERT_EQ(0, e1);
-
-    AHardwareBuffer* hardware_buffer = nullptr;
-    int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer);
-    ASSERT_EQ(0, e2);
-    ASSERT_NE(nullptr, hardware_buffer);
-
-    void* buffer;
-    int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer);
-    ASSERT_EQ(0, e3);
-    ASSERT_NE(nullptr, buffer);
-    // Verify that the buffer pointer is at least 16 byte aligned.
-    ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
-
-    uint64_t* data = static_cast<uint64_t*>(buffer);
-    constexpr size_t num_values = size / sizeof(uint64_t);
-    bool is_equal = true;
-    for (size_t i = 0; i < num_values; ++i) {
-      is_equal &= (data[i] == value);
-    }
-    ASSERT_TRUE(is_equal);
-
-    int32_t fence = -1;
-    int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
-    ASSERT_EQ(0, e4);
-
-    dvrBufferDestroy(setup_buffer);
-    AHardwareBuffer_release(hardware_buffer);
-  }
-}
-
-TEST(DvrGlobalBufferTest, TestGlobalBufferZeroed) {
-  const DvrGlobalBufferKey buffer_name = 120;
-
-  // Allocate 1MB and check that it is all zeros.
-  uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
-                   AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
-  constexpr size_t size = 1024 * 1024;
-  DvrBuffer* setup_buffer = nullptr;
-  int e1 = dvrSetupGlobalBuffer(buffer_name, size, usage, &setup_buffer);
-  ASSERT_NE(nullptr, setup_buffer);
-  ASSERT_EQ(0, e1);
-
-  AHardwareBuffer* hardware_buffer = nullptr;
-  int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer);
-  ASSERT_EQ(0, e2);
-  ASSERT_NE(nullptr, hardware_buffer);
-
-  void* buffer;
-  int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer);
-  ASSERT_EQ(0, e3);
-  ASSERT_NE(nullptr, buffer);
-  // Verify that the buffer pointer is at least 16 byte aligned.
-  ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
-
-  uint64_t* data = static_cast<uint64_t*>(buffer);
-  constexpr size_t num_values = size / sizeof(uint64_t);
-  uint64_t zero = 0;
-  for (size_t i = 0; i < num_values; ++i) {
-    zero |= data[i];
-  }
-  ASSERT_EQ(0U, zero);
-
-  int32_t fence = -1;
-  int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
-  ASSERT_EQ(0, e4);
-
-  dvrBufferDestroy(setup_buffer);
-  AHardwareBuffer_release(hardware_buffer);
-}
-
-TEST(DvrGlobalBufferTest, TestVrflingerConfigBuffer) {
-  const DvrGlobalBufferKey buffer_name =
-      DvrGlobalBuffers::kVrFlingerConfigBufferKey;
-
-  // First delete any existing buffer so we can test the failure case.
-  dvrDeleteGlobalBuffer(buffer_name);
-
-  const uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
-                         AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY;
-
-  size_t correct_size = DvrConfigRing::MemorySize();
-  size_t wrong_size = DvrConfigRing::MemorySize(0);
-
-  // Setup an invalid config buffer (too small) and assert that it fails.
-  DvrBuffer* setup_buffer = nullptr;
-  int e1 = dvrSetupGlobalBuffer(buffer_name, wrong_size, usage, &setup_buffer);
-  ASSERT_EQ(nullptr, setup_buffer);
-  ASSERT_GT(0, e1);
-
-  // Setup a correct config buffer.
-  int e2 =
-      dvrSetupGlobalBuffer(buffer_name, correct_size, usage, &setup_buffer);
-  ASSERT_NE(nullptr, setup_buffer);
-  ASSERT_EQ(0, e2);
-
-  dvrBufferDestroy(setup_buffer);
-}
-
-}  // namespace
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libdvr/tests/dvr_tracking-test.cpp b/libs/vr/libdvr/tests/dvr_tracking-test.cpp
deleted file mode 100644
index 3b6d6e1..0000000
--- a/libs/vr/libdvr/tests/dvr_tracking-test.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-#include <android/log.h>
-#include <gtest/gtest.h>
-
-#include "dvr_api_test.h"
-
-namespace {
-
-class DvrTrackingTest : public DvrApiTest {};
-
-#if DVR_TRACKING_IMPLEMENTED
-
-TEST_F(DvrTrackingTest, Implemented) {
-  ASSERT_TRUE(api_.TrackingCameraCreate != nullptr);
-  ASSERT_TRUE(api_.TrackingCameraStart != nullptr);
-  ASSERT_TRUE(api_.TrackingCameraStop != nullptr);
-
-  ASSERT_TRUE(api_.TrackingFeatureExtractorCreate != nullptr);
-  ASSERT_TRUE(api_.TrackingFeatureExtractorDestroy != nullptr);
-  ASSERT_TRUE(api_.TrackingFeatureExtractorStart != nullptr);
-  ASSERT_TRUE(api_.TrackingFeatureExtractorStop != nullptr);
-  ASSERT_TRUE(api_.TrackingFeatureExtractorProcessBuffer != nullptr);
-}
-
-TEST_F(DvrTrackingTest, CameraCreateFailsForInvalidInput) {
-  int ret;
-  ret = api_.TrackingCameraCreate(nullptr);
-  EXPECT_EQ(ret, -EINVAL);
-
-  DvrTrackingCamera* camera = reinterpret_cast<DvrTrackingCamera*>(42);
-  ret = api_.TrackingCameraCreate(&camera);
-  EXPECT_EQ(ret, -EINVAL);
-}
-
-TEST_F(DvrTrackingTest, CameraCreateDestroy) {
-  DvrTrackingCamera* camera = nullptr;
-  int ret = api_.TrackingCameraCreate(&camera);
-
-  EXPECT_EQ(ret, 0);
-  ASSERT_TRUE(camera != nullptr);
-
-  api_.TrackingCameraDestroy(camera);
-}
-
-TEST_F(DvrTrackingTest, FeatureExtractorCreateFailsForInvalidInput) {
-  int ret;
-  ret = api_.TrackingFeatureExtractorCreate(nullptr);
-  EXPECT_EQ(ret, -EINVAL);
-
-  DvrTrackingFeatureExtractor* camera =
-      reinterpret_cast<DvrTrackingFeatureExtractor*>(42);
-  ret = api_.TrackingFeatureExtractorCreate(&camera);
-  EXPECT_EQ(ret, -EINVAL);
-}
-
-TEST_F(DvrTrackingTest, FeatureExtractorCreateDestroy) {
-  DvrTrackingFeatureExtractor* camera = nullptr;
-  int ret = api_.TrackingFeatureExtractorCreate(&camera);
-
-  EXPECT_EQ(ret, 0);
-  ASSERT_TRUE(camera != nullptr);
-
-  api_.TrackingFeatureExtractorDestroy(camera);
-}
-
-#else  // !DVR_TRACKING_IMPLEMENTED
-
-TEST_F(DvrTrackingTest, NotImplemented) {
-  ASSERT_TRUE(api_.TrackingCameraCreate != nullptr);
-  ASSERT_TRUE(api_.TrackingCameraDestroy != nullptr);
-  ASSERT_TRUE(api_.TrackingCameraStart != nullptr);
-  ASSERT_TRUE(api_.TrackingCameraStop != nullptr);
-
-  EXPECT_EQ(api_.TrackingCameraCreate(nullptr), -ENOSYS);
-  EXPECT_EQ(api_.TrackingCameraStart(nullptr, nullptr), -ENOSYS);
-  EXPECT_EQ(api_.TrackingCameraStop(nullptr), -ENOSYS);
-
-  ASSERT_TRUE(api_.TrackingFeatureExtractorCreate != nullptr);
-  ASSERT_TRUE(api_.TrackingFeatureExtractorDestroy != nullptr);
-  ASSERT_TRUE(api_.TrackingFeatureExtractorStart != nullptr);
-  ASSERT_TRUE(api_.TrackingFeatureExtractorStop != nullptr);
-  ASSERT_TRUE(api_.TrackingFeatureExtractorProcessBuffer != nullptr);
-
-  EXPECT_EQ(api_.TrackingFeatureExtractorCreate(nullptr), -ENOSYS);
-  EXPECT_EQ(api_.TrackingFeatureExtractorStart(nullptr, nullptr, nullptr),
-            -ENOSYS);
-  EXPECT_EQ(api_.TrackingFeatureExtractorStop(nullptr), -ENOSYS);
-  EXPECT_EQ(api_.TrackingFeatureExtractorProcessBuffer(nullptr, nullptr,
-                                                       nullptr, nullptr),
-            -ENOSYS);
-
-  ASSERT_TRUE(api_.TrackingSensorsCreate != nullptr);
-  ASSERT_TRUE(api_.TrackingSensorsDestroy != nullptr);
-  ASSERT_TRUE(api_.TrackingSensorsStart != nullptr);
-  ASSERT_TRUE(api_.TrackingSensorsStop != nullptr);
-
-  EXPECT_EQ(api_.TrackingSensorsCreate(nullptr, nullptr), -ENOSYS);
-  EXPECT_EQ(api_.TrackingSensorsStart(nullptr, nullptr, nullptr), -ENOSYS);
-  EXPECT_EQ(api_.TrackingSensorsStop(nullptr), -ENOSYS);
-}
-
-#endif  // DVR_TRACKING_IMPLEMENTED
-
-}  // namespace
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
deleted file mode 100644
index 40a5099..0000000
--- a/libs/vr/libvrsensor/Android.bp
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_native_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_native_license"],
-}
-
-sourceFiles = [
-    "pose_client.cpp",
-    "latency_model.cpp",
-]
-
-includeFiles = [
-    "include",
-]
-
-staticLibraries = [
-    "libdisplay",
-    "libdvrcommon",
-    "libbroadcastring",
-]
-
-sharedLibraries = [
-    "libbase",
-    "libbinder",
-    "libbufferhubqueue",
-    "libcutils",
-    "libhardware",
-    "liblog",
-    "libutils",
-    "libui",
-    "libpdx_default_transport",
-]
-
-cc_library {
-    srcs: sourceFiles,
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-macro-redefined",
-    ],
-    export_include_dirs: includeFiles,
-    static_libs: staticLibraries,
-    shared_libs: sharedLibraries,
-    header_libs: ["libdvr_headers"],
-    name: "libvrsensor",
-}
diff --git a/libs/vr/libvrsensor/include/CPPLINT.cfg b/libs/vr/libvrsensor/include/CPPLINT.cfg
deleted file mode 100644
index 2f8a3c0..0000000
--- a/libs/vr/libvrsensor/include/CPPLINT.cfg
+++ /dev/null
@@ -1 +0,0 @@
-filter=-build/header_guard
diff --git a/libs/vr/libvrsensor/include/dvr/pose_client.h b/libs/vr/libvrsensor/include/dvr/pose_client.h
deleted file mode 100644
index b663a67..0000000
--- a/libs/vr/libvrsensor/include/dvr/pose_client.h
+++ /dev/null
@@ -1,176 +0,0 @@
-#ifndef ANDROID_DVR_POSE_CLIENT_H_
-#define ANDROID_DVR_POSE_CLIENT_H_
-
-#ifdef __ARM_NEON
-#include <arm_neon.h>
-#else
-#ifndef __FLOAT32X4T_86
-#define __FLOAT32X4T_86
-typedef float float32x4_t __attribute__ ((__vector_size__ (16)));
-typedef struct float32x4x4_t { float32x4_t val[4]; } float32x4x4_t;
-#endif
-#endif
-
-#include <stdbool.h>
-#include <stdint.h>
-
-#include <dvr/dvr_pose.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct DvrPoseClient DvrPoseClient;
-
-// Returned by the async pose ring buffer access API.
-typedef struct DvrPoseRingBufferInfo {
-  // Read-only pointer to the pose ring buffer. The current pose is in this
-  // buffer at element buffer[current_frame & (buffer_size - 1)]. The next
-  // frame's forecasted pose is at element
-  // ((current_frame + 1) & (buffer_size - 1)). And so on. The poses are
-  // predicted for when 50% of the corresponding frame's pixel data is visible
-  // to the user.
-  // The last value returned by dvrPresent is the count for the next frame,
-  // which is the earliest that the application could display something if they
-  // were to render promptly. (TODO(jbates) move this comment to dvrPresent).
-  volatile const DvrPoseAsync* buffer;
-  // Minimum number of accurate forecasted poses including the current frame's
-  // pose. This is the number of poses that are udpated by the pose service.
-  // If the application reads past this count, they will get a stale prediction
-  // from a previous frame. Guaranteed to be at least 2.
-  uint32_t min_future_count;
-  // Number of elements in buffer. At least 8 and greater than min_future_count.
-  // Guaranteed to be a power of two. The total size of the buffer in bytes is:
-  //   total_count * sizeof(DvrPoseAsync)
-  uint32_t total_count;
-} DvrPoseRingBufferInfo;
-
-typedef enum DvrPoseMode {
-  DVR_POSE_MODE_6DOF = 0,
-  DVR_POSE_MODE_3DOF,
-  DVR_POSE_MODE_MOCK_FROZEN,
-  DVR_POSE_MODE_MOCK_HEAD_TURN_SLOW,
-  DVR_POSE_MODE_MOCK_HEAD_TURN_FAST,
-  DVR_POSE_MODE_MOCK_ROTATE_SLOW,
-  DVR_POSE_MODE_MOCK_ROTATE_MEDIUM,
-  DVR_POSE_MODE_MOCK_ROTATE_FAST,
-  DVR_POSE_MODE_MOCK_CIRCLE_STRAFE,
-  DVR_POSE_MODE_FLOAT,
-  DVR_POSE_MODE_MOCK_MOTION_SICKNESS,
-
-  // Always last.
-  DVR_POSE_MODE_COUNT,
-} DvrPoseMode;
-
-typedef enum DvrControllerId {
-  DVR_CONTROLLER_0 = 0,
-  DVR_CONTROLLER_1 = 1,
-} DvrControllerId;
-
-// Creates a new pose client.
-//
-// @return Pointer to the created pose client, nullptr on failure.
-DvrPoseClient* dvrPoseClientCreate();
-
-// Destroys a pose client.
-//
-// @param client Pointer to the pose client to be destroyed.
-void dvrPoseClientDestroy(DvrPoseClient* client);
-
-// Gets the pose for the given vsync count.
-//
-// @param client Pointer to the pose client.
-// @param vsync_count Vsync that this pose should be forward-predicted to.
-//     Typically this is the count returned by dvrGetNextVsyncCount.
-// @param out_pose Struct to store pose state.
-// @return Zero on success, negative error code on failure.
-int dvrPoseClientGet(DvrPoseClient* client, uint32_t vsync_count,
-                     DvrPoseAsync* out_pose);
-
-// Gets the current vsync count.
-uint32_t dvrPoseClientGetVsyncCount(DvrPoseClient* client);
-
-// Gets the pose for the given controller at the given vsync count.
-//
-// @param client Pointer to the pose client.
-// @param controller_id The controller id.
-// @param vsync_count Vsync that this pose should be forward-predicted to.
-//     Typically this is the count returned by dvrGetNextVsyncCount.
-// @param out_pose Struct to store pose state.
-// @return Zero on success, negative error code on failure.
-int dvrPoseClientGetController(DvrPoseClient* client, int32_t controller_id,
-                               uint32_t vsync_count, DvrPoseAsync* out_pose);
-
-// Enables/disables logging for the controller fusion.
-//
-// @param client Pointer to the pose client.
-// @param enable True starts logging, False stops.
-// @return Zero on success, negative error code on failure.
-int dvrPoseClientLogController(DvrPoseClient* client, bool enable);
-
-// DEPRECATED
-// Polls current pose state.
-//
-// @param client Pointer to the pose client.
-// @param state Struct to store polled state.
-// @return Zero on success, negative error code on failure.
-int dvrPoseClientPoll(DvrPoseClient* client, DvrPose* state);
-
-// Freezes the pose to the provided state.
-//
-// Future poll operations will return this state until a different state is
-// frozen or dvrPoseClientModeSet() is called with a different mode. The timestamp is
-// not frozen.
-//
-// @param client Pointer to the pose client.
-// @param frozen_state State pose to be frozen to.
-// @return Zero on success, negative error code on failure.
-int dvrPoseClientFreeze(DvrPoseClient* client, const DvrPose* frozen_state);
-
-// Sets the pose service mode.
-//
-// @param mode The requested pose mode.
-// @return Zero on success, negative error code on failure.
-int dvrPoseClientModeSet(DvrPoseClient* client, DvrPoseMode mode);
-
-// Gets the pose service mode.
-//
-// @param mode Return value for the current pose mode.
-// @return Zero on success, negative error code on failure.
-int dvrPoseClientModeGet(DvrPoseClient* client, DvrPoseMode* mode);
-
-// Get access to the shared memory pose ring buffer.
-// A future pose at vsync <current> + <offset> is accessed at index:
-//   index = (<current> + <offset>) % out_buffer_size
-// Where <current> was the last value returned by dvrPresent and
-// <offset> is less than or equal to |out_min_future_count|.
-// |out_buffer| will be set to a pointer to the buffer.
-// |out_fd| will be set to the gralloc buffer file descriptor, which is
-//   required for binding this buffer for GPU use.
-// Returns 0 on success.
-int dvrPoseClientGetRingBuffer(DvrPoseClient* client,
-                               DvrPoseRingBufferInfo* out_info);
-
-// Sets enabled state for sensors pose processing.
-//
-// @param enabled Whether sensors are enabled or disabled.
-// @return Zero on success
-int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled);
-
-// Requests a burst of data samples from pose service. The data samples are
-// passed through a shared memory buffer obtained by calling
-// dvrPoseClientGetDataReader().
-//
-// @param DvrPoseDataCaptureRequest Parameters on how to capture data.
-// @return Zero on success.
-int dvrPoseClientDataCapture(DvrPoseClient* client,
-                             const DvrPoseDataCaptureRequest* request);
-
-// Destroys the write buffer queue for the given |data_type|.
-int dvrPoseClientDataReaderDestroy(DvrPoseClient* client, uint64_t data_type);
-
-#ifdef __cplusplus
-}  // extern "C"
-#endif
-
-#endif  // ANDROID_DVR_POSE_CLIENT_H_
diff --git a/libs/vr/libvrsensor/include/private/dvr/latency_model.h b/libs/vr/libvrsensor/include/private/dvr/latency_model.h
deleted file mode 100644
index bf0e687..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/latency_model.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef ANDROID_DVR_LATENCY_MODEL_H_
-#define ANDROID_DVR_LATENCY_MODEL_H_
-
-#include <vector>
-
-namespace android {
-namespace dvr {
-
-// This class models the latency from sensors. It will look at the first
-// window_size measurements and return their average after that.
-class LatencyModel {
- public:
-  explicit LatencyModel(size_t window_size);
-  ~LatencyModel() = default;
-
-  void AddLatency(int64_t latency_ns);
-  int64_t CurrentLatencyEstimate() const { return latency_; }
-
- private:
-  size_t window_size_;
-  int64_t latency_sum_ = 0;
-  size_t num_summed_ = 0;
-  int64_t latency_ = 0;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_LATENCY_MODEL_H_
diff --git a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h b/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
deleted file mode 100644
index 7bf1cd4..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef ANDROID_DVR_POSE_IPC_H_
-#define ANDROID_DVR_POSE_IPC_H_
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define DVR_POSE_SERVICE_BASE "system/vr/pose"
-#define DVR_POSE_SERVICE_CLIENT (DVR_POSE_SERVICE_BASE "/client")
-
-enum {
-  DVR_POSE_FREEZE = 0,
-  DVR_POSE_SET_MODE,
-  DVR_POSE_GET_MODE,
-  DVR_POSE_GET_CONTROLLER_RING_BUFFER,
-  DVR_POSE_LOG_CONTROLLER,
-  DVR_POSE_SENSORS_ENABLE,
-  DVR_POSE_GET_TANGO_READER,
-  DVR_POSE_DATA_CAPTURE,
-  DVR_POSE_TANGO_READER_DESTROY,
-};
-
-#ifdef __cplusplus
-}  // extern "C"
-#endif
-
-#endif  // ANDROID_DVR_POSE_IPC_H_
diff --git a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h b/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
deleted file mode 100644
index 39592bb..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
-#define ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
-
-#include <private/dvr/buffer_hub_queue_client.h>
-
-using android::dvr::ConsumerQueue;
-
-typedef struct DvrPoseClient DvrPoseClient;
-
-namespace android {
-namespace dvr {
-
-int dvrPoseClientGetDataReaderHandle(DvrPoseClient *client, uint64_t data_type,
-                                     ConsumerQueue **queue_out);
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
diff --git a/libs/vr/libvrsensor/latency_model.cpp b/libs/vr/libvrsensor/latency_model.cpp
deleted file mode 100644
index d3a4521..0000000
--- a/libs/vr/libvrsensor/latency_model.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-#include <private/dvr/latency_model.h>
-
-#include <cmath>
-
-namespace android {
-namespace dvr {
-
-LatencyModel::LatencyModel(size_t window_size) : window_size_(window_size) {}
-
-void LatencyModel::AddLatency(int64_t latency_ns) {
-  // Not enough samples yet?
-  if (num_summed_ < window_size_) {
-    // Accumulate.
-    latency_sum_ += latency_ns;
-
-    // Have enough samples for latency estimate?
-    if (++num_summed_ == window_size_) {
-      latency_ = latency_sum_ / window_size_;
-    }
-  }
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp
deleted file mode 100644
index 4ff6a09..0000000
--- a/libs/vr/libvrsensor/pose_client.cpp
+++ /dev/null
@@ -1,368 +0,0 @@
-#define LOG_TAG "PoseClient"
-#include <dvr/dvr_shared_buffers.h>
-#include <dvr/pose_client.h>
-
-#include <stdint.h>
-
-#include <log/log.h>
-#include <pdx/client.h>
-#include <pdx/default_transport/client_channel_factory.h>
-#include <pdx/file_handle.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/consumer_buffer.h>
-#include <private/dvr/display_client.h>
-#include <private/dvr/pose-ipc.h>
-#include <private/dvr/shared_buffer_helpers.h>
-
-using android::dvr::ConsumerQueue;
-using android::pdx::LocalHandle;
-using android::pdx::LocalChannelHandle;
-using android::pdx::Status;
-using android::pdx::Transaction;
-
-namespace android {
-namespace dvr {
-namespace {
-
-typedef CPUMappedBroadcastRing<DvrPoseRing> SensorPoseRing;
-
-constexpr static int32_t MAX_CONTROLLERS = 2;
-}  // namespace
-
-// PoseClient is a remote interface to the pose service in sensord.
-class PoseClient : public pdx::ClientBase<PoseClient> {
- public:
-  ~PoseClient() override {}
-
-  // Casts C handle into an instance of this class.
-  static PoseClient* FromC(DvrPoseClient* client) {
-    return reinterpret_cast<PoseClient*>(client);
-  }
-
-  // Polls the pose service for the current state and stores it in *state.
-  // Returns zero on success, a negative error code otherwise.
-  int Poll(DvrPose* state) {
-    // Allocate the helper class to access the sensor pose buffer.
-    if (sensor_pose_buffer_ == nullptr) {
-      sensor_pose_buffer_ = std::make_unique<SensorPoseRing>(
-          DvrGlobalBuffers::kSensorPoseBuffer, CPUUsageMode::READ_RARELY);
-    }
-
-    if (state) {
-      if (sensor_pose_buffer_->GetNewest(state)) {
-        return 0;
-      } else {
-        return -EAGAIN;
-      }
-    }
-
-    return -EINVAL;
-  }
-
-  int GetPose(uint32_t vsync_count, DvrPoseAsync* out_pose) {
-    const auto vsync_buffer = GetVsyncBuffer();
-    if (vsync_buffer) {
-      *out_pose =
-          vsync_buffer
-              ->vsync_poses[vsync_count & DvrVsyncPoseBuffer::kIndexMask];
-      return 0;
-    } else {
-      return -EAGAIN;
-    }
-  }
-
-  uint32_t GetVsyncCount() {
-    const auto vsync_buffer = GetVsyncBuffer();
-    if (vsync_buffer) {
-      return vsync_buffer->vsync_count;
-    }
-
-    return 0;
-  }
-
-  int GetControllerPose(int32_t controller_id, uint32_t vsync_count,
-                        DvrPoseAsync* out_pose) {
-    if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) {
-      return -EINVAL;
-    }
-    if (!controllers_[controller_id].mapped_pose_buffer) {
-      int ret = GetControllerRingBuffer(controller_id);
-      if (ret < 0)
-        return ret;
-    }
-    *out_pose =
-        controllers_[controller_id]
-            .mapped_pose_buffer[vsync_count & DvrVsyncPoseBuffer::kIndexMask];
-    return 0;
-  }
-
-  int LogController(bool enable) {
-    Transaction trans{*this};
-    Status<int> status = trans.Send<int>(DVR_POSE_LOG_CONTROLLER, &enable,
-                                         sizeof(enable), nullptr, 0);
-    ALOGE_IF(!status, "Pose LogController() failed because: %s",
-             status.GetErrorMessage().c_str());
-    return ReturnStatusOrError(status);
-  }
-
-  // Freezes the pose to the provided state. Future poll operations will return
-  // this state until a different state is frozen or SetMode() is called with a
-  // different mode.
-  // Returns zero on success, a negative error code otherwise.
-  int Freeze(const DvrPose& frozen_state) {
-    Transaction trans{*this};
-    Status<int> status = trans.Send<int>(DVR_POSE_FREEZE, &frozen_state,
-                                         sizeof(frozen_state), nullptr, 0);
-    ALOGE_IF(!status, "Pose Freeze() failed because: %s\n",
-             status.GetErrorMessage().c_str());
-    return ReturnStatusOrError(status);
-  }
-
-  // Sets the data mode for the pose service.
-  int SetMode(DvrPoseMode mode) {
-    Transaction trans{*this};
-    Status<int> status =
-        trans.Send<int>(DVR_POSE_SET_MODE, &mode, sizeof(mode), nullptr, 0);
-    ALOGE_IF(!status, "Pose SetPoseMode() failed because: %s",
-             status.GetErrorMessage().c_str());
-    return ReturnStatusOrError(status);
-  }
-
-  // Gets the data mode for the pose service.
-  int GetMode(DvrPoseMode* out_mode) {
-    int mode;
-    Transaction trans{*this};
-    Status<int> status =
-        trans.Send<int>(DVR_POSE_GET_MODE, nullptr, 0, &mode, sizeof(mode));
-    ALOGE_IF(!status, "Pose GetPoseMode() failed because: %s",
-             status.GetErrorMessage().c_str());
-    if (status)
-      *out_mode = DvrPoseMode(mode);
-    return ReturnStatusOrError(status);
-  }
-
-  int GetTangoReaderHandle(uint64_t data_type, ConsumerQueue** queue_out) {
-    // Get buffer.
-    Transaction trans{*this};
-    Status<LocalChannelHandle> status = trans.Send<LocalChannelHandle>(
-        DVR_POSE_GET_TANGO_READER, &data_type, sizeof(data_type), nullptr, 0);
-
-    if (!status) {
-      ALOGE("PoseClient GetTangoReaderHandle() failed because: %s",
-            status.GetErrorMessage().c_str());
-      *queue_out = nullptr;
-      return -status.error();
-    }
-
-    std::unique_ptr<ConsumerQueue> consumer_queue =
-        ConsumerQueue::Import(status.take());
-    *queue_out = consumer_queue.release();
-    return 0;
-  }
-
-  int DataCapture(const DvrPoseDataCaptureRequest* request) {
-    Transaction trans{*this};
-    Status<int> status = trans.Send<int>(DVR_POSE_DATA_CAPTURE, request,
-                                         sizeof(*request), nullptr, 0);
-    ALOGE_IF(!status, "PoseClient DataCapture() failed because: %s\n",
-             status.GetErrorMessage().c_str());
-    return ReturnStatusOrError(status);
-  }
-
-  int DataReaderDestroy(uint64_t data_type) {
-    Transaction trans{*this};
-    Status<int> status = trans.Send<int>(DVR_POSE_TANGO_READER_DESTROY,
-                                         &data_type, sizeof(data_type), nullptr,
-                                         0);
-    ALOGE_IF(!status, "PoseClient DataReaderDestroy() failed because: %s\n",
-             status.GetErrorMessage().c_str());
-    return ReturnStatusOrError(status);
-  }
-
-  // Enables or disables all pose processing from sensors
-  int EnableSensors(bool enabled) {
-    Transaction trans{*this};
-    Status<int> status = trans.Send<int>(DVR_POSE_SENSORS_ENABLE, &enabled,
-                                         sizeof(enabled), nullptr, 0);
-    ALOGE_IF(!status, "Pose EnableSensors() failed because: %s\n",
-             status.GetErrorMessage().c_str());
-    return ReturnStatusOrError(status);
-  }
-
-  int GetRingBuffer(DvrPoseRingBufferInfo* out_info) {
-    // First time mapping the buffer?
-    const auto vsync_buffer = GetVsyncBuffer();
-    if (vsync_buffer) {
-      if (out_info) {
-        out_info->min_future_count = DvrVsyncPoseBuffer::kMinFutureCount;
-        out_info->total_count = DvrVsyncPoseBuffer::kSize;
-        out_info->buffer = vsync_buffer->vsync_poses;
-      }
-      return -EINVAL;
-    }
-
-    return -EAGAIN;
-  }
-
-  int GetControllerRingBuffer(int32_t controller_id) {
-    if (controller_id < 0 || controller_id >= MAX_CONTROLLERS) {
-      return -EINVAL;
-    }
-    ControllerClientState& client_state = controllers_[controller_id];
-    if (client_state.pose_buffer.get()) {
-      return 0;
-    }
-
-    Transaction trans{*this};
-    Status<LocalChannelHandle> status = trans.Send<LocalChannelHandle>(
-        DVR_POSE_GET_CONTROLLER_RING_BUFFER, &controller_id,
-        sizeof(controller_id), nullptr, 0);
-    if (!status) {
-      return -status.error();
-    }
-
-    auto buffer = ConsumerBuffer::Import(status.take());
-    if (!buffer) {
-      ALOGE("Pose failed to import ring buffer");
-      return -EIO;
-    }
-    constexpr size_t size = DvrVsyncPoseBuffer::kSize * sizeof(DvrPoseAsync);
-    void* addr = nullptr;
-    int ret = buffer->GetBlobReadWritePointer(size, &addr);
-    if (ret < 0 || !addr) {
-      ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, addr);
-      return -EIO;
-    }
-    client_state.pose_buffer.swap(buffer);
-    client_state.mapped_pose_buffer = static_cast<const DvrPoseAsync*>(addr);
-    ALOGI(
-        "Mapped controller %d pose data translation %f,%f,%f quat %f,%f,%f,%f",
-        controller_id, client_state.mapped_pose_buffer[0].position[0],
-        client_state.mapped_pose_buffer[0].position[1],
-        client_state.mapped_pose_buffer[0].position[2],
-        client_state.mapped_pose_buffer[0].orientation[0],
-        client_state.mapped_pose_buffer[0].orientation[1],
-        client_state.mapped_pose_buffer[0].orientation[2],
-        client_state.mapped_pose_buffer[0].orientation[3]);
-    return 0;
-  }
-
- private:
-  friend BASE;
-
-  // Set up a channel to the pose service.
-  PoseClient()
-      : BASE(pdx::default_transport::ClientChannelFactory::Create(
-            DVR_POSE_SERVICE_CLIENT)) {
-    // TODO(eieio): Cache the pose and make timeout 0 so that the API doesn't
-    // block while waiting for the pose service to come back up.
-    EnableAutoReconnect(kInfiniteTimeout);
-  }
-
-  PoseClient(const PoseClient&) = delete;
-  PoseClient& operator=(const PoseClient&) = delete;
-
-  const DvrVsyncPoseBuffer* GetVsyncBuffer() {
-    if (mapped_vsync_pose_buffer_ == nullptr) {
-      if (vsync_pose_buffer_ == nullptr) {
-        // The constructor tries mapping it so we do not need TryMapping after.
-        vsync_pose_buffer_ = std::make_unique<CPUMappedBuffer>(
-            DvrGlobalBuffers::kVsyncPoseBuffer, CPUUsageMode::READ_OFTEN);
-      } else if (vsync_pose_buffer_->IsMapped() == false) {
-        vsync_pose_buffer_->TryMapping();
-      }
-
-      if (vsync_pose_buffer_->IsMapped()) {
-        mapped_vsync_pose_buffer_ =
-            static_cast<DvrVsyncPoseBuffer*>(vsync_pose_buffer_->Address());
-      }
-    }
-
-    return mapped_vsync_pose_buffer_;
-  }
-
-  // The vsync pose buffer if already mapped.
-  std::unique_ptr<CPUMappedBuffer> vsync_pose_buffer_;
-
-  // The direct sensor pose buffer.
-  std::unique_ptr<SensorPoseRing> sensor_pose_buffer_;
-
-  const DvrVsyncPoseBuffer* mapped_vsync_pose_buffer_ = nullptr;
-
-  struct ControllerClientState {
-    std::unique_ptr<ConsumerBuffer> pose_buffer;
-    const DvrPoseAsync* mapped_pose_buffer = nullptr;
-  };
-  ControllerClientState controllers_[MAX_CONTROLLERS];
-};
-
-int dvrPoseClientGetDataReaderHandle(DvrPoseClient* client, uint64_t type,
-                                     ConsumerQueue** queue_out) {
-  return PoseClient::FromC(client)->GetTangoReaderHandle(type, queue_out);
-}
-
-}  // namespace dvr
-}  // namespace android
-
-using android::dvr::PoseClient;
-
-extern "C" {
-
-DvrPoseClient* dvrPoseClientCreate() {
-  auto* client = PoseClient::Create().release();
-  return reinterpret_cast<DvrPoseClient*>(client);
-}
-
-void dvrPoseClientDestroy(DvrPoseClient* client) {
-  delete PoseClient::FromC(client);
-}
-
-int dvrPoseClientGet(DvrPoseClient* client, uint32_t vsync_count,
-                     DvrPoseAsync* out_pose) {
-  return PoseClient::FromC(client)->GetPose(vsync_count, out_pose);
-}
-
-uint32_t dvrPoseClientGetVsyncCount(DvrPoseClient* client) {
-  return PoseClient::FromC(client)->GetVsyncCount();
-}
-
-int dvrPoseClientGetController(DvrPoseClient* client, int32_t controller_id,
-                               uint32_t vsync_count, DvrPoseAsync* out_pose) {
-  return PoseClient::FromC(client)->GetControllerPose(controller_id,
-                                                      vsync_count, out_pose);
-}
-
-int dvrPoseClientLogController(DvrPoseClient* client, bool enable) {
-  return PoseClient::FromC(client)->LogController(enable);
-}
-
-int dvrPoseClientPoll(DvrPoseClient* client, DvrPose* state) {
-  return PoseClient::FromC(client)->Poll(state);
-}
-
-int dvrPoseClientFreeze(DvrPoseClient* client, const DvrPose* frozen_state) {
-  return PoseClient::FromC(client)->Freeze(*frozen_state);
-}
-
-int dvrPoseClientModeSet(DvrPoseClient* client, DvrPoseMode mode) {
-  return PoseClient::FromC(client)->SetMode(mode);
-}
-
-int dvrPoseClientModeGet(DvrPoseClient* client, DvrPoseMode* mode) {
-  return PoseClient::FromC(client)->GetMode(mode);
-}
-
-int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled) {
-  return PoseClient::FromC(client)->EnableSensors(enabled);
-}
-
-int dvrPoseClientDataCapture(DvrPoseClient* client,
-                             const DvrPoseDataCaptureRequest* request) {
-  return PoseClient::FromC(client)->DataCapture(request);
-}
-
-int dvrPoseClientDataReaderDestroy(DvrPoseClient* client, uint64_t data_type) {
-  return PoseClient::FromC(client)->DataReaderDestroy(data_type);
-}
-
-}  // extern "C"
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 76fd7f0..dd14bcf 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -207,7 +207,8 @@
     ATRACE_CALL();
     const nsecs_t openTime = systemTime();
 
-    if (should_unload_system_driver(cnx)) {
+    if (!android::GraphicsEnv::getInstance().angleIsSystemDriver() &&
+        should_unload_system_driver(cnx)) {
         unload_system_driver(cnx);
     }
 
@@ -216,8 +217,13 @@
         return cnx->dso;
     }
 
-    // Firstly, try to load ANGLE driver.
-    driver_t* hnd = attempt_to_load_angle(cnx);
+    // Firstly, try to load ANGLE driver, unless we know that we shouldn't.
+    bool shouldForceLegacyDriver = android::GraphicsEnv::getInstance().shouldForceLegacyDriver();
+    driver_t* hnd = nullptr;
+    if (!shouldForceLegacyDriver) {
+        hnd = attempt_to_load_angle(cnx);
+    }
+
     if (!hnd) {
         // Secondly, try to load from driver apk.
         hnd = attempt_to_load_updated_driver(cnx);
@@ -230,21 +236,29 @@
             LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s",
                              android::GraphicsEnv::getInstance().getDriverPath().c_str());
         }
-        // Finally, try to load system driver, start by searching for the library name appended by
-        // the system properties of the GLES userspace driver in both locations.
-        // i.e.:
-        //      libGLES_${prop}.so, or:
-        //      libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so
-        for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
-            auto prop = base::GetProperty(key, "");
-            if (prop.empty()) {
-                continue;
-            }
-            hnd = attempt_to_load_system_driver(cnx, prop.c_str(), true);
-            if (hnd) {
-                break;
-            } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
-                failToLoadFromDriverSuffixProperty = true;
+        // Finally, try to load system driver.  If ANGLE is the system driver
+        // (i.e. we are forcing the legacy system driver instead of ANGLE), use
+        // the driver suffix that was passed down from above.
+        if (shouldForceLegacyDriver) {
+            std::string suffix = android::GraphicsEnv::getInstance().getLegacySuffix();
+            hnd = attempt_to_load_system_driver(cnx, suffix.c_str(), true);
+        } else {
+            // Start by searching for the library name appended by the system
+            // properties of the GLES userspace driver in both locations.
+            // i.e.:
+            //      libGLES_${prop}.so, or:
+            //      libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so
+            for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
+                auto prop = base::GetProperty(key, "");
+                if (prop.empty()) {
+                    continue;
+                }
+                hnd = attempt_to_load_system_driver(cnx, prop.c_str(), true);
+                if (hnd) {
+                    break;
+                } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
+                    failToLoadFromDriverSuffixProperty = true;
+                }
             }
         }
     }
diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp
index b3d6f74..e0ba946 100644
--- a/opengl/libs/EGL/getProcAddress.cpp
+++ b/opengl/libs/EGL/getProcAddress.cpp
@@ -118,70 +118,27 @@
             : "rax", "cc"                                       \
             );
 
-#elif defined(__mips64)
+#elif defined(__riscv)
+    #define API_ENTRY(_api) __attribute__((noinline)) _api
 
-        #define API_ENTRY(_api) __attribute__((noinline)) _api
-
-        #define CALL_GL_EXTENSION_API(_api, ...)                    \
-            register unsigned int _t0 asm("$12");                   \
-            register unsigned int _fn asm("$25");                   \
-            register unsigned int _tls asm("$3");                   \
-            asm volatile(                                           \
-                ".set  push\n\t"                                    \
-                ".set  noreorder\n\t"                               \
-                "rdhwr %[tls], $29\n\t"                             \
-                "ld    %[t0], %[OPENGL_API](%[tls])\n\t"            \
-                "beqz  %[t0], 1f\n\t"                               \
-                " move %[fn], $ra\n\t"                              \
-                "ld    %[t0], %[API](%[t0])\n\t"                    \
-                "beqz  %[t0], 1f\n\t"                               \
-                " nop\n\t"                                          \
-                "move  %[fn], %[t0]\n\t"                            \
-                "1:\n\t"                                            \
-                "jalr  $0, %[fn]\n\t"                               \
-                " nop\n\t"                                          \
-                ".set  pop\n\t"                                     \
-                : [fn] "=c"(_fn),                                   \
-                  [tls] "=&r"(_tls),                                \
-                  [t0] "=&r"(_t0)                                   \
-                : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4),          \
-                  [API] "I"(__builtin_offsetof(gl_hooks_t,          \
-                                          ext.extensions[_api]))    \
-                :                                                   \
-            );
-
-#elif defined(__mips__)
-
-        #define API_ENTRY(_api) __attribute__((noinline)) _api
-
-        #define CALL_GL_EXTENSION_API(_api, ...)                    \
-            register unsigned int _t0 asm("$8");                    \
-            register unsigned int _fn asm("$25");                    \
-            register unsigned int _tls asm("$3");                   \
-            asm volatile(                                           \
-                ".set  push\n\t"                                    \
-                ".set  noreorder\n\t"                               \
-                ".set  mips32r2\n\t"                                \
-                "rdhwr %[tls], $29\n\t"                             \
-                "lw    %[t0], %[OPENGL_API](%[tls])\n\t"            \
-                "beqz  %[t0], 1f\n\t"                               \
-                " move %[fn], $ra\n\t"                              \
-                "lw    %[t0], %[API](%[t0])\n\t"                    \
-                "beqz  %[t0], 1f\n\t"                               \
-                " nop\n\t"                                          \
-                "move  %[fn], %[t0]\n\t"                            \
-                "1:\n\t"                                            \
-                "jalr  $0, %[fn]\n\t"                               \
-                " nop\n\t"                                          \
-                ".set  pop\n\t"                                     \
-                : [fn] "=c"(_fn),                                   \
-                  [tls] "=&r"(_tls),                                \
-                  [t0] "=&r"(_t0)                                   \
-                : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4),          \
-                  [API] "I"(__builtin_offsetof(gl_hooks_t,          \
-                                          ext.extensions[_api]))    \
-                :                                                   \
-            );
+    #define CALL_GL_EXTENSION_API(_api)                             \
+        asm volatile(                                               \
+            "mv t0, tp\n"                                           \
+            "li t1, %[tls]\n"                                       \
+            "add t0, t0, t1\n"                                      \
+            "ld t0, 0(t0)\n"                                        \
+            "beqz t0, 1f\n"                                         \
+            "li t1, %[api]\n"                                       \
+            "add t0, t0, t1\n"                                      \
+            "ld t0, 0(t0)\n"                                        \
+            "jalr x0, t0\n"                                         \
+            "1: ret\n"                                              \
+            :                                                       \
+            : [tls] "i" (TLS_SLOT_OPENGL_API * sizeof(void*)),      \
+              [api] "i" (__builtin_offsetof(gl_hooks_t,             \
+                                        ext.extensions[_api]))      \
+            : "t0", "t1"                                            \
+        );
 
 #endif
 
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index 65f50f5..5bd5c14 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -191,73 +191,44 @@
             :                              \
         );
 
-#elif defined(__mips64)
+#elif defined(__riscv)
 
     #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
 
-    // t0:  $12
-    // fn:  $25
-    // tls: $3
-    // v0:  $2
-    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                  \
-        asm volatile(                                             \
-            ".set  push\n\t"                                      \
-            ".set  noreorder\n\t"                                 \
-            "rdhwr $3, $29\n\t"                                   \
-            "ld    $12, %[OPENGL_API]($3)\n\t"                    \
-            "beqz  $12, 1f\n\t"                                   \
-            " move $25, $ra\n\t"                                  \
-            "ld    $12, %[API]($12)\n\t"                          \
-            "beqz  $12, 1f\n\t"                                   \
-            " nop\n\t"                                            \
-            "move  $25, $12\n\t"                                  \
-            "1:\n\t"                                              \
-            "jalr  $0, $25\n\t"                                   \
-            " move $2, $0\n\t"                                    \
-            ".set  pop\n\t"                                       \
-            :                                                     \
-            : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
-              [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api))  \
-            : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",     \
-              "$10", "$11", "$12", "$25"                          \
-        );
-
-    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
-    #define CALL_GL_API_INTERNAL_DO_RETURN
-
-#elif defined(__mips__)
-
-    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
-
-    // t0:  $8
-    // fn:  $25
-    // tls: $3
-    // v0:  $2
     #define CALL_GL_API_INTERNAL_CALL(_api, ...)                 \
         asm volatile(                                            \
-            ".set  push\n\t"                                     \
-            ".set  noreorder\n\t"                                \
-            ".set  mips32r2\n\t"                                 \
-            "rdhwr $3, $29\n\t"                                  \
-            "lw    $3, %[OPENGL_API]($3)\n\t"                    \
-            "beqz  $3, 1f\n\t"                                   \
-            " move $25,$ra\n\t"                                  \
-            "lw    $3, %[API]($3)\n\t"                           \
-            "beqz  $3, 1f\n\t"                                   \
-            " nop\n\t"                                           \
-            "move  $25, $3\n\t"                                  \
-            "1:\n\t"                                             \
-            "jalr  $0, $25\n\t"                                  \
-            " move $2, $0\n\t"                                   \
-            ".set  pop\n\t"                                      \
+            "mv t0, tp\n"                                        \
+            "li t1, %[tls]\n"                                    \
+            "add t0, t0, t1\n"                                   \
+            "ld t0, 0(t0)\n"                                     \
+            "beqz t0, 1f\n"                                      \
+            "li t1, %[api]\n"                                    \
+            "add t0, t0, t1\n"                                   \
+            "ld t0, 0(t0)\n"                                     \
+            "jalr x0, t0\n"                                      \
+            "1:\n"                                               \
             :                                                    \
-            : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4),           \
-              [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
-            : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$25"    \
+            : [tls] "i"(TLS_SLOT_OPENGL_API*sizeof(void *)),     \
+              [api] "i"(__builtin_offsetof(gl_hooks_t, gl._api)) \
+            : "t0", "t1", "t2", "a0", "a1", "a2", "a3", "a4",    \
+              "a5", "t6", "t3", "t4", "t5", "t6"                 \
         );
 
-    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
-    #define CALL_GL_API_INTERNAL_DO_RETURN
+    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+        asm volatile(                             \
+            "li a0, 0\n"                          \
+            :                                     \
+            :                                     \
+            : "a0"                                \
+        );
+
+    #define CALL_GL_API_INTERNAL_DO_RETURN \
+        asm volatile(                      \
+            "ret\n"                        \
+            :                              \
+            :                              \
+            :                              \
+        );
 
 #endif
 
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index bacd4b4..64c0f97 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -247,73 +247,44 @@
             :                              \
         );
 
-#elif defined(__mips64)
+#elif defined(__riscv)
 
     #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
 
-    // t0:  $12
-    // fn:  $25
-    // tls: $3
-    // v0:  $2
-    #define CALL_GL_API_INTERNAL_CALL(_api, ...)                  \
-        asm volatile(                                             \
-            ".set  push\n\t"                                      \
-            ".set  noreorder\n\t"                                 \
-            "rdhwr $3, $29\n\t"                                   \
-            "ld    $12, %[OPENGL_API]($3)\n\t"                    \
-            "beqz  $12, 1f\n\t"                                   \
-            " move $25, $ra\n\t"                                  \
-            "ld    $12, %[API]($12)\n\t"                          \
-            "beqz  $12, 1f\n\t"                                   \
-            " nop\n\t"                                            \
-            "move  $25, $12\n\t"                                  \
-            "1:\n\t"                                              \
-            "jalr  $0, $25\n\t"                                   \
-            " move $2, $0\n\t"                                    \
-            ".set  pop\n\t"                                       \
-            :                                                     \
-            : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
-              [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api))  \
-            : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",     \
-              "$10", "$11", "$12", "$25"                          \
-        );
-
-    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
-    #define CALL_GL_API_INTERNAL_DO_RETURN
-
-#elif defined(__mips__)
-
-    #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
-
-    // t0:  $8
-    // fn:  $25
-    // tls: $3
-    // v0:  $2
     #define CALL_GL_API_INTERNAL_CALL(_api, ...)                 \
         asm volatile(                                            \
-            ".set  push\n\t"                                     \
-            ".set  noreorder\n\t"                                \
-            ".set  mips32r2\n\t"                                 \
-            "rdhwr $3, $29\n\t"                                  \
-            "lw    $3, %[OPENGL_API]($3)\n\t"                    \
-            "beqz  $3, 1f\n\t"                                   \
-            " move $25,$ra\n\t"                                  \
-            "lw    $3, %[API]($3)\n\t"                           \
-            "beqz  $3, 1f\n\t"                                   \
-            " nop\n\t"                                           \
-            "move  $25, $3\n\t"                                  \
-            "1:\n\t"                                             \
-            "jalr  $0, $25\n\t"                                  \
-            " move $2, $0\n\t"                                   \
-            ".set  pop\n\t"                                      \
+            "mv t0, tp\n"                                        \
+            "li t1, %[tls]\n"                                    \
+            "add t0, t0, t1\n"                                   \
+            "ld t0, 0(t0)\n"                                     \
+            "beqz t0, 1f\n"                                      \
+            "li t1, %[api]\n"                                    \
+            "add t0, t0, t1\n"                                   \
+            "ld t0, 0(t0)\n"                                     \
+            "jalr x0, t0\n"                                      \
+            "1:\n"                                               \
             :                                                    \
-            : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4),           \
-              [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
-            : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$25"    \
+            : [tls] "i"(TLS_SLOT_OPENGL_API*sizeof(void *)),     \
+              [api] "i"(__builtin_offsetof(gl_hooks_t, gl._api)) \
+            : "t0", "t1", "t2", "a0", "a1", "a2", "a3", "a4",    \
+              "a5", "t6", "t3", "t4", "t5", "t6"                 \
         );
 
-    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
-    #define CALL_GL_API_INTERNAL_DO_RETURN
+    #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+        asm volatile(                             \
+            "li a0, 0\n"                          \
+            :                                     \
+            :                                     \
+            : "a0"                                \
+        );
+
+    #define CALL_GL_API_INTERNAL_DO_RETURN \
+        asm volatile(                      \
+            "ret\n"                        \
+            :                              \
+            :                              \
+            :                              \
+        );
 
 #endif
 
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 2a3924b..dce327e 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -196,9 +196,20 @@
         }
         coords += StringPrintf("{%" PRIu32 ": ", i);
         coords +=
-                StringPrintf("id=%" PRIu32 " x=%.1f y=%.1f, pressure=%.1f", pointerProperties[i].id,
+                StringPrintf("id=%" PRIu32 " x=%.1f y=%.1f pressure=%.1f", pointerProperties[i].id,
                              pointerCoords[i].getX(), pointerCoords[i].getY(),
                              pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
+        const int32_t toolType = pointerProperties[i].toolType;
+        if (toolType != AMOTION_EVENT_TOOL_TYPE_FINGER) {
+            coords += StringPrintf(" toolType=%s", motionToolTypeToString(toolType));
+        }
+        const float major = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR);
+        const float minor = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR);
+        const float orientation = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
+        if (major != 0 || minor != 0) {
+            coords += StringPrintf(" major=%.1f minor=%.1f orientation=%.1f", major, minor,
+                                   orientation);
+        }
         coords += "}";
     }
     return StringPrintf("NotifyMotionArgs(id=%" PRId32 ", eventTime=%" PRId64 ", deviceId=%" PRId32
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index b4b617e..8d5d883 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -15,6 +15,9 @@
       "name": "inputflinger_tests"
     },
     {
+      "name": "libchrome-gestures_test"
+    },
+    {
       "name": "libpalmrejection_test"
     },
     {
diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp
index f57ff33..ec41025 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.cpp
+++ b/services/inputflinger/UnwantedInteractionBlocker.cpp
@@ -29,8 +29,40 @@
 
 using android::base::StringPrintf;
 
+/**
+ * This type is declared here to ensure consistency between the instantiated type (used in the
+ * constructor via std::make_unique) and the cast-to type (used in PalmRejector::dump() with
+ * static_cast). Due to the lack of rtti support, dynamic_cast is not available, so this can't be
+ * checked at runtime to avoid undefined behaviour.
+ */
+using PalmFilterImplementation = ::ui::NeuralStylusPalmDetectionFilter;
+
 namespace android {
 
+/**
+ * Log detailed debug messages about each inbound motion event notification to the blocker.
+ * Enable this via "adb shell setprop log.tag.UnwantedInteractionBlockerInboundMotion DEBUG"
+ * (requires restart)
+ */
+const bool DEBUG_INBOUND_MOTION =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "InboundMotion", ANDROID_LOG_INFO);
+
+/**
+ * Log detailed debug messages about each outbound motion event processed by the blocker.
+ * Enable this via "adb shell setprop log.tag.UnwantedInteractionBlockerOutboundMotion DEBUG"
+ * (requires restart)
+ */
+const bool DEBUG_OUTBOUND_MOTION =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "OutboundMotion", ANDROID_LOG_INFO);
+
+/**
+ * Log the data sent to the model and received back from the model.
+ * Enable this via "adb shell setprop log.tag.UnwantedInteractionBlockerModel DEBUG"
+ * (requires restart)
+ */
+const bool DEBUG_MODEL =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Model", ANDROID_LOG_INFO);
+
 // Category (=namespace) name for the input settings that are applied at boot time
 static const char* INPUT_NATIVE_BOOT = "input_native_boot";
 /**
@@ -45,13 +77,11 @@
 }
 
 static bool isFromTouchscreen(int32_t source) {
-    return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN) &&
-            !isFromSource(source, AINPUT_SOURCE_STYLUS);
+    return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN);
 }
 
 static ::base::TimeTicks toChromeTimestamp(nsecs_t eventTime) {
-    return ::base::TimeTicks::UnixEpoch() +
-            ::base::Milliseconds(static_cast<float>(ns2ms(eventTime)));
+    return ::base::TimeTicks::UnixEpoch() + ::base::TimeDelta::FromNanosecondsD(eventTime);
 }
 
 /**
@@ -61,39 +91,22 @@
 static bool isPalmRejectionEnabled() {
     std::string value = toLower(
             server_configurable_flags::GetServerConfigurableFlag(INPUT_NATIVE_BOOT,
-                                                                 PALM_REJECTION_ENABLED, "false"));
-    if (value == "true" || value == "1") {
+                                                                 PALM_REJECTION_ENABLED, "0"));
+    if (value == "1") {
         return true;
     }
     return false;
 }
 
-static int getLinuxToolType(int32_t toolType) {
-    switch (toolType) {
-        case AMOTION_EVENT_TOOL_TYPE_FINGER:
-            return MT_TOOL_FINGER;
-        case AMOTION_EVENT_TOOL_TYPE_STYLUS:
-            return MT_TOOL_PEN;
-        case AMOTION_EVENT_TOOL_TYPE_PALM:
-            return MT_TOOL_PALM;
+static int getLinuxToolCode(int toolType) {
+    if (toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS) {
+        return BTN_TOOL_PEN;
     }
-    ALOGW("Got tool type %" PRId32 ", converting to MT_TOOL_FINGER", toolType);
-    return MT_TOOL_FINGER;
-}
-
-static std::string dumpDeviceInfo(const AndroidPalmFilterDeviceInfo& info) {
-    std::string out;
-    out += StringPrintf("max_x = %.2f\n", info.max_x);
-    out += StringPrintf("max_y = %.2f\n", info.max_y);
-    out += StringPrintf("x_res = %.2f\n", info.x_res);
-    out += StringPrintf("y_res = %.2f\n", info.y_res);
-    out += StringPrintf("major_radius_res = %.2f\n", info.major_radius_res);
-    out += StringPrintf("minor_radius_res = %.2f\n", info.minor_radius_res);
-    out += StringPrintf("minor_radius_supported = %s\n",
-                        info.minor_radius_supported ? "true" : "false");
-    out += StringPrintf("touch_major_res = %" PRId32 "\n", info.touch_major_res);
-    out += StringPrintf("touch_minor_res = %" PRId32 "\n", info.touch_minor_res);
-    return out;
+    if (toolType == AMOTION_EVENT_TOOL_TYPE_FINGER) {
+        return BTN_TOOL_FINGER;
+    }
+    ALOGW("Got tool type %" PRId32 ", converting to BTN_TOOL_FINGER", toolType);
+    return BTN_TOOL_FINGER;
 }
 
 static int32_t getActionUpForPointerId(const NotifyMotionArgs& args, int32_t pointerId) {
@@ -128,32 +141,6 @@
     return AMOTION_EVENT_ACTION_MOVE;
 }
 
-std::string toString(const ::ui::InProgressTouchEvdev& touch) {
-    return StringPrintf("x=%.1f, y=%.1f, tracking_id=%i, slot=%zu,"
-                        " pressure=%.1f, major=%i, minor=%i, "
-                        "tool_type=%i, altered=%s, was_touching=%s, touching=%s",
-                        touch.x, touch.y, touch.tracking_id, touch.slot, touch.pressure,
-                        touch.major, touch.minor, touch.tool_type, toString(touch.altered),
-                        toString(touch.was_touching), toString(touch.touching));
-}
-
-/**
- * Remove the data for the provided pointers from the args. The pointers are identified by their
- * pointerId, not by the index inside the array.
- * Return the new NotifyMotionArgs struct that has the remaining pointers.
- * The only fields that may be different in the returned args from the provided args are:
- *     - action
- *     - pointerCount
- *     - pointerProperties
- *     - pointerCoords
- * Action might change because it contains a pointer index. If another pointer is removed, the
- * active pointer index would be shifted.
- * Do not call this function for events with POINTER_UP or POINTER_DOWN events when removed pointer
- * id is the acting pointer id.
- *
- * @param args the args from which the pointers should be removed
- * @param pointerIds the pointer ids of the pointers that should be removed
- */
 NotifyMotionArgs removePointerIds(const NotifyMotionArgs& args,
                                   const std::set<int32_t>& pointerIds) {
     const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
@@ -199,6 +186,26 @@
     return newArgs;
 }
 
+/**
+ * Remove stylus pointers from the provided NotifyMotionArgs.
+ *
+ * Return NotifyMotionArgs where the stylus pointers have been removed.
+ * If this results in removal of the active pointer, then return nullopt.
+ */
+static std::optional<NotifyMotionArgs> removeStylusPointerIds(const NotifyMotionArgs& args) {
+    std::set<int32_t> stylusPointerIds;
+    for (uint32_t i = 0; i < args.pointerCount; i++) {
+        if (args.pointerProperties[i].toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS) {
+            stylusPointerIds.insert(args.pointerProperties[i].id);
+        }
+    }
+    NotifyMotionArgs withoutStylusPointers = removePointerIds(args, stylusPointerIds);
+    if (withoutStylusPointers.pointerCount == 0 || withoutStylusPointers.action == ACTION_UNKNOWN) {
+        return std::nullopt;
+    }
+    return withoutStylusPointers;
+}
+
 std::optional<AndroidPalmFilterDeviceInfo> createPalmFilterDeviceInfo(
         const InputDeviceInfo& deviceInfo) {
     if (!isFromTouchscreen(deviceInfo.getSources())) {
@@ -326,6 +333,7 @@
 }
 
 void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) {
+    ALOGD_IF(DEBUG_INBOUND_MOTION, "%s: %s", __func__, args->dump().c_str());
     { // acquire lock
         std::scoped_lock lock(mLock);
         const std::vector<NotifyMotionArgs> processedArgs =
@@ -339,17 +347,22 @@
     mQueuedListener.flush();
 }
 
+void UnwantedInteractionBlocker::enqueueOutboundMotionLocked(const NotifyMotionArgs& args) {
+    ALOGD_IF(DEBUG_OUTBOUND_MOTION, "%s: %s", __func__, args.dump().c_str());
+    mQueuedListener.notifyMotion(&args);
+}
+
 void UnwantedInteractionBlocker::notifyMotionLocked(const NotifyMotionArgs* args) {
     auto it = mPalmRejectors.find(args->deviceId);
     const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args->source);
     if (!sendToPalmRejector) {
-        mQueuedListener.notifyMotion(args);
+        enqueueOutboundMotionLocked(*args);
         return;
     }
 
     std::vector<NotifyMotionArgs> processedArgs = it->second.processMotion(*args);
     for (const NotifyMotionArgs& loopArgs : processedArgs) {
-        mQueuedListener.notifyMotion(&loopArgs);
+        enqueueOutboundMotionLocked(loopArgs);
     }
 }
 
@@ -428,9 +441,10 @@
     dump += "UnwantedInteractionBlocker:\n";
     dump += "  mPreferStylusOverTouchBlocker:\n";
     dump += addLinePrefix(mPreferStylusOverTouchBlocker.dump(), "    ");
-    dump += StringPrintf("  mEnablePalmRejection: %s\n", toString(mEnablePalmRejection));
+    dump += StringPrintf("  mEnablePalmRejection: %s\n",
+                         std::to_string(mEnablePalmRejection).c_str());
     dump += StringPrintf("  isPalmRejectionEnabled (flag value): %s\n",
-                         toString(isPalmRejectionEnabled()));
+                         std::to_string(isPalmRejectionEnabled()).c_str());
     dump += mPalmRejectors.empty() ? "  mPalmRejectors: None\n" : "  mPalmRejectors:\n";
     for (const auto& [deviceId, palmRejector] : mPalmRejectors) {
         dump += StringPrintf("    deviceId = %" PRId32 ":\n", deviceId);
@@ -512,6 +526,15 @@
     return out;
 }
 
+class AndroidPalmRejectionModel : public ::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel {
+public:
+    AndroidPalmRejectionModel()
+          : ::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel(/*default version*/ "",
+                                                                     std::vector<float>()) {
+        config_.resample_period = ::ui::kResamplePeriod;
+    }
+};
+
 PalmRejector::PalmRejector(const AndroidPalmFilterDeviceInfo& info,
                            std::unique_ptr<::ui::PalmDetectionFilter> filter)
       : mSharedPalmState(std::make_unique<::ui::SharedPalmDetectionFilterState>()),
@@ -523,11 +546,9 @@
         return;
     }
     std::unique_ptr<::ui::NeuralStylusPalmDetectionFilterModel> model =
-            std::make_unique<::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel>(
-                    std::vector<float>());
-    mPalmDetectionFilter =
-            std::make_unique<::ui::NeuralStylusPalmDetectionFilter>(mDeviceInfo, std::move(model),
-                                                                    mSharedPalmState.get());
+            std::make_unique<AndroidPalmRejectionModel>();
+    mPalmDetectionFilter = std::make_unique<PalmFilterImplementation>(mDeviceInfo, std::move(model),
+                                                                      mSharedPalmState.get());
 }
 
 std::vector<::ui::InProgressTouchEvdev> getTouches(const NotifyMotionArgs& args,
@@ -541,7 +562,7 @@
         touches.emplace_back(::ui::InProgressTouchEvdev());
         touches.back().major = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR);
         touches.back().minor = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR);
-        touches.back().tool_type = getLinuxToolType(args.pointerProperties[i].toolType);
+        // The field 'tool_type' is not used for palm rejection
 
         // Whether there is new information for the touch.
         touches.back().altered = true;
@@ -588,15 +609,57 @@
 
         // The fields 'radius_x' and 'radius_x' are not used for palm rejection
         touches.back().pressure = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
-        touches.back().tool_code = BTN_TOOL_FINGER;
+        touches.back().tool_code = getLinuxToolCode(args.pointerProperties[i].toolType);
         // The field 'orientation' is not used for palm rejection
         // The fields 'tilt_x' and 'tilt_y' are not used for palm rejection
-        touches.back().reported_tool_type = ::ui::EventPointerType::kTouch;
+        // The field 'reported_tool_type' is not used for palm rejection
         touches.back().stylus_button = false;
     }
     return touches;
 }
 
+std::set<int32_t> PalmRejector::detectPalmPointers(const NotifyMotionArgs& args) {
+    std::bitset<::ui::kNumTouchEvdevSlots> slotsToHold;
+    std::bitset<::ui::kNumTouchEvdevSlots> slotsToSuppress;
+
+    // Store the slot state before we call getTouches and update it. This way, we can find
+    // the slots that have been removed due to the incoming event.
+    SlotState oldSlotState = mSlotState;
+    mSlotState.update(args);
+
+    std::vector<::ui::InProgressTouchEvdev> touches =
+            getTouches(args, mDeviceInfo, oldSlotState, mSlotState);
+    ::base::TimeTicks chromeTimestamp = toChromeTimestamp(args.eventTime);
+
+    if (DEBUG_MODEL) {
+        std::stringstream touchesStream;
+        for (const ::ui::InProgressTouchEvdev& touch : touches) {
+            touchesStream << touch.tracking_id << " : " << touch << "\n";
+        }
+        ALOGD("Filter: touches = %s", touchesStream.str().c_str());
+    }
+
+    mPalmDetectionFilter->Filter(touches, chromeTimestamp, &slotsToHold, &slotsToSuppress);
+
+    ALOGD_IF(DEBUG_MODEL, "Response: slotsToHold = %s, slotsToSuppress = %s",
+             slotsToHold.to_string().c_str(), slotsToSuppress.to_string().c_str());
+
+    // Now that we know which slots should be suppressed, let's convert those to pointer id's.
+    std::set<int32_t> newSuppressedIds;
+    for (size_t i = 0; i < args.pointerCount; i++) {
+        const int32_t pointerId = args.pointerProperties[i].id;
+        std::optional<size_t> slot = oldSlotState.getSlotForPointerId(pointerId);
+        if (!slot) {
+            slot = mSlotState.getSlotForPointerId(pointerId);
+            LOG_ALWAYS_FATAL_IF(!slot, "Could not find slot for pointer id %" PRId32, pointerId);
+        }
+        if (slotsToSuppress.test(*slot)) {
+            newSuppressedIds.insert(pointerId);
+        }
+    }
+    return newSuppressedIds;
+}
+
 std::vector<NotifyMotionArgs> PalmRejector::processMotion(const NotifyMotionArgs& args) {
     if (mPalmDetectionFilter == nullptr) {
         return {args};
@@ -614,32 +677,17 @@
     if (args.action == AMOTION_EVENT_ACTION_DOWN) {
         mSuppressedPointerIds.clear();
     }
-    std::bitset<::ui::kNumTouchEvdevSlots> slotsToHold;
-    std::bitset<::ui::kNumTouchEvdevSlots> slotsToSuppress;
 
-    // Store the slot state before we call getTouches and update it. This way, we can find
-    // the slots that have been removed due to the incoming event.
-    SlotState oldSlotState = mSlotState;
-    mSlotState.update(args);
-    std::vector<::ui::InProgressTouchEvdev> touches =
-            getTouches(args, mDeviceInfo, oldSlotState, mSlotState);
-    ::base::TimeTicks chromeTimestamp = toChromeTimestamp(args.eventTime);
-
-    mPalmDetectionFilter->Filter(touches, chromeTimestamp, &slotsToHold, &slotsToSuppress);
-
-    // Now that we know which slots should be suppressed, let's convert those to pointer id's.
     std::set<int32_t> oldSuppressedIds;
     std::swap(oldSuppressedIds, mSuppressedPointerIds);
-    for (size_t i = 0; i < args.pointerCount; i++) {
-        const int32_t pointerId = args.pointerProperties[i].id;
-        std::optional<size_t> slot = oldSlotState.getSlotForPointerId(pointerId);
-        if (!slot) {
-            slot = mSlotState.getSlotForPointerId(pointerId);
-            LOG_ALWAYS_FATAL_IF(!slot, "Could not find slot for pointer id %" PRId32, pointerId);
-        }
-        if (slotsToSuppress.test(*slot)) {
-            mSuppressedPointerIds.insert(pointerId);
-        }
+
+    std::optional<NotifyMotionArgs> touchOnlyArgs = removeStylusPointerIds(args);
+    if (touchOnlyArgs) {
+        mSuppressedPointerIds = detectPalmPointers(*touchOnlyArgs);
+    } else {
+        // This is a stylus-only event.
+        // We can skip this event and just keep the suppressed pointer ids the same as before.
+        mSuppressedPointerIds = oldSuppressedIds;
     }
 
     std::vector<NotifyMotionArgs> argsWithoutUnwantedPointers =
@@ -648,29 +696,40 @@
         LOG_ALWAYS_FATAL_IF(checkArgs.action == ACTION_UNKNOWN, "%s", checkArgs.dump().c_str());
     }
 
-    if (mSuppressedPointerIds != oldSuppressedIds) {
-        if (argsWithoutUnwantedPointers.size() != 1 ||
-            argsWithoutUnwantedPointers[0].pointerCount != args.pointerCount) {
-            ALOGI("Palm detected, removing pointer ids %s from %s",
-                  dumpSet(mSuppressedPointerIds).c_str(), args.dump().c_str());
-        }
+    // Only log if new pointers are getting rejected. That means mSuppressedPointerIds is not a
+    // subset of oldSuppressedIds.
+    if (!std::includes(oldSuppressedIds.begin(), oldSuppressedIds.end(),
+                       mSuppressedPointerIds.begin(), mSuppressedPointerIds.end())) {
+        ALOGI("Palm detected, removing pointer ids %s after %" PRId64 "ms from %s",
+              dumpSet(mSuppressedPointerIds).c_str(), ns2ms(args.eventTime - args.downTime),
+              args.dump().c_str());
     }
 
     return argsWithoutUnwantedPointers;
 }
 
-const AndroidPalmFilterDeviceInfo& PalmRejector::getPalmFilterDeviceInfo() {
+const AndroidPalmFilterDeviceInfo& PalmRejector::getPalmFilterDeviceInfo() const {
     return mDeviceInfo;
 }
 
 std::string PalmRejector::dump() const {
     std::string out;
     out += "mDeviceInfo:\n";
-    out += addLinePrefix(dumpDeviceInfo(mDeviceInfo), "  ");
+    std::stringstream deviceInfo;
+    deviceInfo << mDeviceInfo << ", touch_major_res=" << mDeviceInfo.touch_major_res
+               << ", touch_minor_res=" << mDeviceInfo.touch_minor_res << "\n";
+    out += addLinePrefix(deviceInfo.str(), "  ");
     out += "mSlotState:\n";
     out += addLinePrefix(mSlotState.dump(), "  ");
     out += "mSuppressedPointerIds: ";
     out += dumpSet(mSuppressedPointerIds) + "\n";
+    std::stringstream state;
+    state << *mSharedPalmState;
+    out += "mSharedPalmState: " + state.str() + "\n";
+    std::stringstream filter;
+    filter << static_cast<const PalmFilterImplementation&>(*mPalmDetectionFilter);
+    out += "mPalmDetectionFilter:\n";
+    out += addLinePrefix(filter.str(), "  ") + "\n";
     return out;
 }
 
diff --git a/services/inputflinger/UnwantedInteractionBlocker.h b/services/inputflinger/UnwantedInteractionBlocker.h
index a433764..5d0dde8 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.h
+++ b/services/inputflinger/UnwantedInteractionBlocker.h
@@ -43,6 +43,25 @@
 
 static constexpr int32_t ACTION_UNKNOWN = -1;
 
+/**
+ * Remove the data for the provided pointers from the args. The pointers are identified by their
+ * pointerId, not by the index inside the array.
+ * Return the new NotifyMotionArgs struct that has the remaining pointers.
+ * The only fields that may be different in the returned args from the provided args are:
+ *     - action
+ *     - pointerCount
+ *     - pointerProperties
+ *     - pointerCoords
+ * Action might change because it contains a pointer index. If another pointer is removed, the
+ * active pointer index would be shifted.
+ *
+ * If the active pointer id is removed (for example, for events like
+ * POINTER_UP or POINTER_DOWN), then the action is set to ACTION_UNKNOWN. It is up to the caller
+ * to set the action appropriately after the call.
+ *
+ * @param args the args from which the pointers should be removed
+ * @param pointerIds the pointer ids of the pointers that should be removed
+ */
 NotifyMotionArgs removePointerIds(const NotifyMotionArgs& args,
                                   const std::set<int32_t>& pointerIds);
 
@@ -101,6 +120,9 @@
     std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors GUARDED_BY(mLock);
     // TODO(b/210159205): delete this when simultaneous stylus and touch is supported
     void notifyMotionLocked(const NotifyMotionArgs* args) REQUIRES(mLock);
+
+    // Call this function for outbound events so that they can be logged when logging is enabled.
+    void enqueueOutboundMotionLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
 };
 
 class SlotState {
@@ -144,13 +166,21 @@
     std::vector<NotifyMotionArgs> processMotion(const NotifyMotionArgs& args);
 
     // Get the device info of this device, for comparison purposes
-    const AndroidPalmFilterDeviceInfo& getPalmFilterDeviceInfo();
+    const AndroidPalmFilterDeviceInfo& getPalmFilterDeviceInfo() const;
     std::string dump() const;
 
 private:
     PalmRejector(const PalmRejector&) = delete;
     PalmRejector& operator=(const PalmRejector&) = delete;
 
+    /**
+     * Update the slot state and send this event to the palm rejection model for palm detection.
+     * Return the pointer ids that should be suppressed.
+     *
+     * This function is not const because it has side-effects. It will update the slot state using
+     * the incoming args! Also, it will call Filter(..), which has side-effects.
+     */
+    std::set<int32_t> detectPalmPointers(const NotifyMotionArgs& args);
     std::unique_ptr<::ui::SharedPalmDetectionFilterState> mSharedPalmState;
     AndroidPalmFilterDeviceInfo mDeviceInfo;
     std::unique_ptr<::ui::PalmDetectionFilter> mPalmDetectionFilter;
diff --git a/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h
index 4f8995f..9a2aea6 100644
--- a/services/inputflinger/dispatcher/DebugConfig.h
+++ b/services/inputflinger/dispatcher/DebugConfig.h
@@ -75,11 +75,8 @@
 
 /**
  * Log debug messages about touch occlusion
- * Enable this via "adb shell setprop log.tag.InputDispatcherTouchOcclusion DEBUG" (requires
- * restart)
  */
-const bool DEBUG_TOUCH_OCCLUSION =
-        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "TouchOcclusion", ANDROID_LOG_INFO);
+constexpr bool DEBUG_TOUCH_OCCLUSION = true;
 
 /**
  * Log debug messages about the app switch latency optimization.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 564acc0..b0f5932 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2195,10 +2195,7 @@
 
             // Update the temporary touch state.
             BitSet32 pointerIds;
-            if (isSplit) {
-                uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
-                pointerIds.markBit(pointerId);
-            }
+            pointerIds.markBit(entry.pointerProperties[pointerIndex].id);
 
             tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds);
         }
@@ -2275,9 +2272,7 @@
                 }
 
                 BitSet32 pointerIds;
-                if (isSplit) {
-                    pointerIds.markBit(entry.pointerProperties[0].id);
-                }
+                pointerIds.markBit(entry.pointerProperties[0].id);
                 tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
             }
         }
@@ -2453,21 +2448,28 @@
             }
         } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
             // One pointer went up.
-            if (isSplit) {
-                int32_t pointerIndex = getMotionEventActionPointerIndex(action);
-                uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
+            int32_t pointerIndex = getMotionEventActionPointerIndex(action);
+            uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
 
-                for (size_t i = 0; i < tempTouchState.windows.size();) {
-                    TouchedWindow& touchedWindow = tempTouchState.windows[i];
-                    if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {
-                        touchedWindow.pointerIds.clearBit(pointerId);
-                        if (touchedWindow.pointerIds.isEmpty()) {
-                            tempTouchState.windows.erase(tempTouchState.windows.begin() + i);
-                            continue;
-                        }
-                    }
-                    i += 1;
+            for (size_t i = 0; i < tempTouchState.windows.size();) {
+                TouchedWindow& touchedWindow = tempTouchState.windows[i];
+                touchedWindow.pointerIds.clearBit(pointerId);
+                if (touchedWindow.pointerIds.isEmpty()) {
+                    tempTouchState.windows.erase(tempTouchState.windows.begin() + i);
+                    continue;
                 }
+                i += 1;
+            }
+        } else if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) {
+            // If no split, we suppose all touched windows should receive pointer down.
+            const int32_t pointerIndex = getMotionEventActionPointerIndex(action);
+            for (size_t i = 0; i < tempTouchState.windows.size(); i++) {
+                TouchedWindow& touchedWindow = tempTouchState.windows[i];
+                // Ignore drag window for it should just track one pointer.
+                if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) {
+                    continue;
+                }
+                touchedWindow.pointerIds.markBit(entry.pointerProperties[pointerIndex].id);
             }
         }
 
@@ -4479,6 +4481,14 @@
     if (it == mDisplayInfos.end()) return;
     const auto& transformToDisplay = it->second.transform.inverse() * injectedTransform;
 
+    if (entry.xCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION &&
+        entry.yCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION) {
+        const vec2 cursor =
+                MotionEvent::calculateTransformedXY(entry.source, transformToDisplay,
+                                                    {entry.xCursorPosition, entry.yCursorPosition});
+        entry.xCursorPosition = cursor.x;
+        entry.yCursorPosition = cursor.y;
+    }
     for (uint32_t i = 0; i < entry.pointerCount; i++) {
         entry.pointerCoords[i] =
                 MotionEvent::calculateTransformedCoords(entry.source, transformToDisplay,
@@ -4721,10 +4731,13 @@
     updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId);
 
     const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
-    if (mLastHoverWindowHandle &&
-        std::find(windowHandles.begin(), windowHandles.end(), mLastHoverWindowHandle) ==
-                windowHandles.end()) {
-        mLastHoverWindowHandle = nullptr;
+    if (mLastHoverWindowHandle) {
+        const WindowInfo* lastHoverWindowInfo = mLastHoverWindowHandle->getInfo();
+        if (lastHoverWindowInfo->displayId == displayId &&
+            std::find(windowHandles.begin(), windowHandles.end(), mLastHoverWindowHandle) ==
+                    windowHandles.end()) {
+            mLastHoverWindowHandle = nullptr;
+        }
     }
 
     std::optional<FocusResolver::FocusChanges> changes =
@@ -5088,14 +5101,13 @@
 
         // Store the dragging window.
         if (isDragDrop) {
-            if (pointerIds.count() > 1) {
-                ALOGW("The drag and drop cannot be started when there is more than 1 pointer on the"
-                      " window.");
+            if (pointerIds.count() != 1) {
+                ALOGW("The drag and drop cannot be started when there is no pointer or more than 1"
+                      " pointer on the window.");
                 return false;
             }
-            // If the window didn't not support split or the source is mouse, the pointerIds count
-            // would be 0, so we have to track the pointer 0.
-            const int32_t id = pointerIds.count() == 0 ? 0 : pointerIds.firstMarkedBit();
+            // Track the pointer id for drag window and generate the drag state.
+            const int32_t id = pointerIds.firstMarkedBit();
             mDragState = std::make_unique<DragState>(toWindowHandle, id);
         }
 
@@ -6331,6 +6343,13 @@
 
     { // acquire lock
         std::scoped_lock _l(mLock);
+
+        // Ensure that we have an entry created for all existing displays so that if a displayId has
+        // no windows, we can tell that the windows were removed from the display.
+        for (const auto& [displayId, _] : mWindowHandlesByDisplay) {
+            handlesPerDisplay[displayId];
+        }
+
         mDisplayInfos.clear();
         for (const auto& displayInfo : displayInfos) {
             mDisplayInfos.emplace(displayInfo.displayId, displayInfo);
diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp
index d39113b..2df97d9 100644
--- a/services/inputflinger/dispatcher/InputTarget.cpp
+++ b/services/inputflinger/dispatcher/InputTarget.cpp
@@ -43,8 +43,8 @@
 }
 
 void InputTarget::addPointers(BitSet32 newPointerIds, const ui::Transform& transform) {
-    // The pointerIds can be empty, but still a valid InputTarget. This can happen for Monitors
-    // and non splittable windows since we will just use all the pointers from the input event.
+    // The pointerIds can be empty, but still a valid InputTarget. This can happen when there is no
+    // valid pointer property from the input event.
     if (newPointerIds.isEmpty()) {
         setDefaultPointerTransform(transform);
         return;
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
index 4c31ec3..6783022 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -29,7 +29,7 @@
 struct TouchedWindow {
     sp<gui::WindowInfoHandle> windowHandle;
     int32_t targetFlags;
-    BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set
+    BitSet32 pointerIds;
 };
 
 } // namespace inputdispatcher
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 0d73e07..3f26aaa 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -110,7 +110,8 @@
         dump += "<none>\n";
     }
     dump += StringPrintf(INDENT2 "HasMic:     %s\n", toString(mHasMic));
-    dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
+    dump += StringPrintf(INDENT2 "Sources: %s\n",
+                         inputEventSourceToString(deviceInfo.getSources()).c_str());
     dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
     dump += StringPrintf(INDENT2 "ControllerNum: %d\n", deviceInfo.getControllerNumber());
 
@@ -128,10 +129,10 @@
                 snprintf(name, sizeof(name), "%d", range.axis);
             }
             dump += StringPrintf(INDENT3
-                                 "%s: source=0x%08x, "
+                                 "%s: source=%s, "
                                  "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n",
-                                 name, range.source, range.min, range.max, range.flat, range.fuzz,
-                                 range.resolution);
+                                 name, inputEventSourceToString(range.source).c_str(), range.min,
+                                 range.max, range.flat, range.fuzz, range.resolution);
         }
     }
 
@@ -231,6 +232,10 @@
 }
 
 void InputDevice::removeEventHubDevice(int32_t eventHubId) {
+    if (mController != nullptr && mController->getEventHubId() == eventHubId) {
+        // Delete mController, since the corresponding eventhub device is going away
+        mController = nullptr;
+    }
     mDevices.erase(eventHubId);
 }
 
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index e9a82b4..905b348 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -216,9 +216,9 @@
               "(ignored non-input device)",
               device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str());
     } else {
-        ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s',sources=0x%08x",
+        ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s',sources=%s",
               device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str(),
-              device->getSources());
+              inputEventSourceToString(device->getSources()).c_str());
     }
 
     mDevices.emplace(eventHubId, device);
@@ -270,9 +270,10 @@
               device->getId(), eventHubId, device->getName().c_str(),
               device->getDescriptor().c_str());
     } else {
-        ALOGI("Device removed: id=%d, eventHubId=%d, name='%s', descriptor='%s', sources=0x%08x",
+        ALOGI("Device removed: id=%d, eventHubId=%d, name='%s', descriptor='%s', sources=%s",
               device->getId(), eventHubId, device->getName().c_str(),
-              device->getDescriptor().c_str(), device->getSources());
+              device->getDescriptor().c_str(),
+              inputEventSourceToString(device->getSources()).c_str());
     }
 
     device->removeEventHubDevice(eventHubId);
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 76a87bb..f4f3ae9 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -25,6 +25,8 @@
 #include "PointerControllerInterface.h"
 #include "TouchCursorInputMapperCommon.h"
 
+#include "input/PrintTools.h"
+
 namespace android {
 
 // The default velocity control parameters that has no effect.
@@ -80,7 +82,7 @@
 void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
     InputMapper::populateDeviceInfo(info);
 
-    if (mParameters.mode == Parameters::MODE_POINTER) {
+    if (mParameters.mode == Parameters::Mode::POINTER) {
         float minX, minY, maxX, maxY;
         if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
             info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f);
@@ -117,6 +119,7 @@
                          toString(mCursorScrollAccumulator.haveRelativeHWheel()));
     dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
     dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
+    dump += StringPrintf(INDENT3 "DisplayId: %s\n", toString(mDisplayId).c_str());
     dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation);
     dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
     dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
@@ -135,12 +138,12 @@
 
         // Configure device mode.
         switch (mParameters.mode) {
-            case Parameters::MODE_POINTER_RELATIVE:
+            case Parameters::Mode::POINTER_RELATIVE:
                 // Should not happen during first time configuration.
                 ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER");
-                mParameters.mode = Parameters::MODE_POINTER;
+                mParameters.mode = Parameters::Mode::POINTER;
                 [[fallthrough]];
-            case Parameters::MODE_POINTER:
+            case Parameters::Mode::POINTER:
                 mSource = AINPUT_SOURCE_MOUSE;
                 mXPrecision = 1.0f;
                 mYPrecision = 1.0f;
@@ -148,7 +151,7 @@
                 mYScale = 1.0f;
                 mPointerController = getContext()->getPointerController(getDeviceId());
                 break;
-            case Parameters::MODE_NAVIGATION:
+            case Parameters::Mode::NAVIGATION:
                 mSource = AINPUT_SOURCE_TRACKBALL;
                 mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
                 mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
@@ -161,12 +164,13 @@
         mHWheelScale = 1.0f;
     }
 
-    const bool configurePointerCapture = (!changes && config->pointerCaptureRequest.enable) ||
-            (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    const bool configurePointerCapture = mParameters.mode != Parameters::Mode::NAVIGATION &&
+            ((!changes && config->pointerCaptureRequest.enable) ||
+             (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE));
     if (configurePointerCapture) {
         if (config->pointerCaptureRequest.enable) {
-            if (mParameters.mode == Parameters::MODE_POINTER) {
-                mParameters.mode = Parameters::MODE_POINTER_RELATIVE;
+            if (mParameters.mode == Parameters::Mode::POINTER) {
+                mParameters.mode = Parameters::Mode::POINTER_RELATIVE;
                 mSource = AINPUT_SOURCE_MOUSE_RELATIVE;
                 // Keep PointerController around in order to preserve the pointer position.
                 mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
@@ -174,8 +178,8 @@
                 ALOGE("Cannot request pointer capture, device is not in MODE_POINTER");
             }
         } else {
-            if (mParameters.mode == Parameters::MODE_POINTER_RELATIVE) {
-                mParameters.mode = Parameters::MODE_POINTER;
+            if (mParameters.mode == Parameters::Mode::POINTER_RELATIVE) {
+                mParameters.mode = Parameters::Mode::POINTER;
                 mSource = AINPUT_SOURCE_MOUSE;
             } else {
                 ALOGE("Cannot release pointer capture, device is not in MODE_POINTER_RELATIVE");
@@ -190,8 +194,8 @@
 
     if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED) ||
         configurePointerCapture) {
-        if (config->pointerCaptureRequest.enable) {
-            // Disable any acceleration or scaling when Pointer Capture is enabled.
+        if (mParameters.mode == Parameters::Mode::POINTER_RELATIVE) {
+            // Disable any acceleration or scaling for the pointer when Pointer Capture is enabled.
             mPointerVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
             mWheelXVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
             mWheelYVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
@@ -202,21 +206,36 @@
         }
     }
 
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+    if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) ||
+        configurePointerCapture) {
+        const bool isPointer = mParameters.mode == Parameters::Mode::POINTER;
+
+        mDisplayId = ADISPLAY_ID_NONE;
+        if (auto viewport = mDeviceContext.getAssociatedViewport(); viewport) {
+            // This InputDevice is associated with a viewport.
+            // Only generate events for the associated display.
+            const bool mismatchedPointerDisplay =
+                    isPointer && (viewport->displayId != mPointerController->getDisplayId());
+            mDisplayId = mismatchedPointerDisplay ? std::nullopt
+                                                  : std::make_optional(viewport->displayId);
+        } else if (isPointer) {
+            // The InputDevice is not associated with a viewport, but it controls the mouse pointer.
+            mDisplayId = mPointerController->getDisplayId();
+        }
+
         mOrientation = DISPLAY_ORIENTATION_0;
         const bool isOrientedDevice =
                 (mParameters.orientationAware && mParameters.hasAssociatedDisplay);
-
         // InputReader works in the un-rotated display coordinate space, so we don't need to do
         // anything if the device is already orientation-aware. If the device is not
         // orientation-aware, then we need to apply the inverse rotation of the display so that
         // when the display rotation is applied later as a part of the per-window transform, we
-        // get the expected screen coordinates.
-        if (!isOrientedDevice) {
-            std::optional<DisplayViewport> internalViewport =
-                    config->getDisplayViewportByType(ViewportType::INTERNAL);
-            if (internalViewport) {
-                mOrientation = getInverseRotation(internalViewport->orientation);
+        // get the expected screen coordinates. When pointer capture is enabled, we do not apply any
+        // rotations and report values directly from the input device.
+        if (!isOrientedDevice && mDisplayId &&
+            mParameters.mode != Parameters::Mode::POINTER_RELATIVE) {
+            if (auto viewport = config->getDisplayViewportById(*mDisplayId); viewport) {
+                mOrientation = getInverseRotation(viewport->orientation);
             }
         }
 
@@ -225,12 +244,12 @@
 }
 
 void CursorInputMapper::configureParameters() {
-    mParameters.mode = Parameters::MODE_POINTER;
+    mParameters.mode = Parameters::Mode::POINTER;
     String8 cursorModeString;
     if (getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.mode"),
                                                              cursorModeString)) {
         if (cursorModeString == "navigation") {
-            mParameters.mode = Parameters::MODE_NAVIGATION;
+            mParameters.mode = Parameters::Mode::NAVIGATION;
         } else if (cursorModeString != "pointer" && cursorModeString != "default") {
             ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string());
         }
@@ -241,7 +260,7 @@
                                                          mParameters.orientationAware);
 
     mParameters.hasAssociatedDisplay = false;
-    if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
+    if (mParameters.mode == Parameters::Mode::POINTER || mParameters.orientationAware) {
         mParameters.hasAssociatedDisplay = true;
     }
 }
@@ -250,21 +269,7 @@
     dump += INDENT3 "Parameters:\n";
     dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n",
                          toString(mParameters.hasAssociatedDisplay));
-
-    switch (mParameters.mode) {
-        case Parameters::MODE_POINTER:
-            dump += INDENT4 "Mode: pointer\n";
-            break;
-        case Parameters::MODE_POINTER_RELATIVE:
-            dump += INDENT4 "Mode: relative pointer\n";
-            break;
-        case Parameters::MODE_NAVIGATION:
-            dump += INDENT4 "Mode: navigation\n";
-            break;
-        default:
-            ALOG_ASSERT(false);
-    }
-
+    dump += StringPrintf(INDENT4 "Mode: %s\n", ftl::enum_string(mParameters.mode).c_str());
     dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
 }
 
@@ -294,6 +299,11 @@
 }
 
 void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) {
+    if (!mDisplayId) {
+        // Ignore events when there is no target display configured.
+        return;
+    }
+
     int32_t lastButtonState = mButtonState;
     int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
     mButtonState = currentButtonState;
@@ -339,7 +349,6 @@
 
     mPointerVelocityControl.move(when, &deltaX, &deltaY);
 
-    int32_t displayId = ADISPLAY_ID_NONE;
     float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
     float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
     if (mSource == AINPUT_SOURCE_MOUSE) {
@@ -363,7 +372,6 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
-        displayId = mPointerController->getDisplayId();
     } else {
         // Pointer capture and navigation modes
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
@@ -385,7 +393,7 @@
 
     // Synthesize key down from buttons if needed.
     synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(),
-                         mSource, displayId, policyFlags, lastButtonState, currentButtonState);
+                         mSource, *mDisplayId, policyFlags, lastButtonState, currentButtonState);
 
     // Send motion event.
     if (downChanged || moved || scrolled || buttonsChanged) {
@@ -406,7 +414,7 @@
                 int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
                 buttonState &= ~actionButton;
                 NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, readTime,
-                                             getDeviceId(), mSource, displayId, policyFlags,
+                                             getDeviceId(), mSource, *mDisplayId, policyFlags,
                                              AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
                                              metaState, buttonState, MotionClassification::NONE,
                                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -418,7 +426,7 @@
         }
 
         NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
-                              displayId, policyFlags, motionEventAction, 0, 0, metaState,
+                              *mDisplayId, policyFlags, motionEventAction, 0, 0, metaState,
                               currentButtonState, MotionClassification::NONE,
                               AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
                               mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime,
@@ -431,7 +439,7 @@
                 int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
                 buttonState |= actionButton;
                 NotifyMotionArgs pressArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
-                                           mSource, displayId, policyFlags,
+                                           mSource, *mDisplayId, policyFlags,
                                            AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
                                            metaState, buttonState, MotionClassification::NONE,
                                            AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -447,7 +455,7 @@
         // Send hover move after UP to tell the application that the mouse is hovering now.
         if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {
             NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
-                                       mSource, displayId, policyFlags,
+                                       mSource, *mDisplayId, policyFlags,
                                        AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
                                        currentButtonState, MotionClassification::NONE,
                                        AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -462,7 +470,7 @@
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
             NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
-                                        mSource, displayId, policyFlags,
+                                        mSource, *mDisplayId, policyFlags,
                                         AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
                                         currentButtonState, MotionClassification::NONE,
                                         AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -474,7 +482,7 @@
 
     // Synthesize key up from buttons if needed.
     synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(), mSource,
-                         displayId, policyFlags, lastButtonState, currentButtonState);
+                         *mDisplayId, policyFlags, lastButtonState, currentButtonState);
 
     mCursorMotionAccumulator.finishSync();
     mCursorScrollAccumulator.finishSync();
@@ -489,16 +497,7 @@
 }
 
 std::optional<int32_t> CursorInputMapper::getAssociatedDisplayId() {
-    if (mParameters.hasAssociatedDisplay) {
-        if (mParameters.mode == Parameters::MODE_POINTER) {
-            return std::make_optional(mPointerController->getDisplayId());
-        } else {
-            // If the device is orientationAware and not a mouse,
-            // it expects to dispatch events to any display
-            return std::make_optional(ADISPLAY_ID_NONE);
-        }
-    }
-    return std::nullopt;
+    return mDisplayId;
 }
 
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index c84c6c4..60b3dd9 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -74,10 +74,17 @@
 
     // Immutable configuration parameters.
     struct Parameters {
-        enum Mode {
-            MODE_POINTER,
-            MODE_POINTER_RELATIVE,
-            MODE_NAVIGATION,
+        enum class Mode {
+            // In POINTER mode, the device is a mouse that controls the mouse cursor on the screen,
+            // reporting absolute screen locations using SOURCE_MOUSE.
+            POINTER,
+            // A mouse device in POINTER mode switches to the POINTER_RELATIVE mode when Pointer
+            // Capture is enabled, and reports relative values only using SOURCE_MOUSE_RELATIVE.
+            POINTER_RELATIVE,
+            // A device in NAVIGATION mode emits relative values using SOURCE_TRACKBALL.
+            NAVIGATION,
+
+            ftl_last = NAVIGATION,
         };
 
         Mode mode;
@@ -104,6 +111,10 @@
     VelocityControl mWheelXVelocityControl;
     VelocityControl mWheelYVelocityControl;
 
+    // The display that events generated by this mapper should target. This can be set to
+    // ADISPLAY_ID_NONE to target the focused display. If there is no display target (i.e.
+    // std::nullopt), all events will be ignored.
+    std::optional<int32_t> mDisplayId;
     int32_t mOrientation;
 
     std::shared_ptr<PointerControllerInterface> mPointerController;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 00fc288..2ddacef 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -44,6 +44,8 @@
 
 // --- Static Definitions ---
 
+static const DisplayViewport kUninitializedViewport;
+
 template <typename T>
 inline static void swap(T& a, T& b) {
     T temp = a;
@@ -390,10 +392,10 @@
     }
 
     if (changes && resetNeeded) {
-        // If device was reset, cancel touch event and update touch spot state.
-        cancelTouch(mCurrentRawState.when, mCurrentRawState.readTime);
-        mCurrentCookedState.clear();
-        updateTouchSpots();
+        // If the device needs to be reset, cancel any ongoing gestures and reset the state.
+        cancelTouch(when, when);
+        reset(when);
+
         // Send reset, unless this is the first time the device has been configured,
         // in which case the reader will call reset itself after all mappers are ready.
         NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
@@ -881,7 +883,7 @@
 }
 
 void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) {
-    DeviceMode oldDeviceMode = mDeviceMode;
+    const DeviceMode oldDeviceMode = mDeviceMode;
 
     resolveExternalStylusPresence();
 
@@ -910,43 +912,37 @@
         mDeviceMode = DeviceMode::UNSCALED;
     }
 
-    // Ensure we have valid X and Y axes.
+    const std::optional<DisplayViewport> newViewportOpt = findViewport();
+
+    // Ensure the device is valid and can be used.
     if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) {
         ALOGW("Touch device '%s' did not report support for X or Y axis!  "
               "The device will be inoperable.",
               getDeviceName().c_str());
         mDeviceMode = DeviceMode::DISABLED;
-        return;
-    }
-
-    // Get associated display dimensions.
-    std::optional<DisplayViewport> newViewport = findViewport();
-    if (!newViewport) {
+    } else if (!newViewportOpt) {
         ALOGI("Touch device '%s' could not query the properties of its associated "
               "display.  The device will be inoperable until the display size "
               "becomes available.",
               getDeviceName().c_str());
         mDeviceMode = DeviceMode::DISABLED;
-        return;
-    }
-
-    if (!newViewport->isActive) {
+    } else if (!newViewportOpt->isActive) {
         ALOGI("Disabling %s (device %i) because the associated viewport is not active",
               getDeviceName().c_str(), getDeviceId());
         mDeviceMode = DeviceMode::DISABLED;
-        return;
     }
 
     // Raw width and height in the natural orientation.
     const int32_t rawWidth = mRawPointerAxes.getRawWidth();
     const int32_t rawHeight = mRawPointerAxes.getRawHeight();
 
-    const bool viewportChanged = mViewport != *newViewport;
+    const DisplayViewport& newViewport = newViewportOpt.value_or(kUninitializedViewport);
+    const bool viewportChanged = mViewport != newViewport;
     bool skipViewportUpdate = false;
     if (viewportChanged) {
-        const bool viewportOrientationChanged = mViewport.orientation != newViewport->orientation;
-        const bool viewportDisplayIdChanged = mViewport.displayId != newViewport->displayId;
-        mViewport = *newViewport;
+        const bool viewportOrientationChanged = mViewport.orientation != newViewport.orientation;
+        const bool viewportDisplayIdChanged = mViewport.displayId != newViewport.displayId;
+        mViewport = newViewport;
 
         if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) {
             // Convert rotated viewport to the natural orientation.
@@ -1105,10 +1101,6 @@
             // of the diagonal axis of the touch pad.  Touches that are wider than this are
             // translated into freeform gestures.
             mPointerGestureMaxSwipeWidth = mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal;
-
-            // Abort current pointer usages because the state has changed.
-            const nsecs_t readTime = when; // synthetic event
-            abortPointerUsage(when, readTime, 0 /*policyFlags*/);
         }
 
         // Inform the dispatcher about the changes.
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 76a7c19..75cd9da 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -60,6 +60,7 @@
     },
     static_libs: [
         "libc++fs",
+        "libgmock",
     ],
     require_root: true,
     test_suites: ["device-tests"],
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index df43071..4977c39 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -2131,6 +2131,59 @@
                          ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */);
 }
 
+TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) {
+    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+    sp<FakeWindowHandle> windowDefaultDisplay =
+            sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
+                                       ADISPLAY_ID_DEFAULT);
+    windowDefaultDisplay->setFrame(Rect(0, 0, 600, 800));
+    sp<FakeWindowHandle> windowSecondDisplay =
+            sp<FakeWindowHandle>::make(application, mDispatcher, "SecondDisplay",
+                                       SECOND_DISPLAY_ID);
+    windowSecondDisplay->setFrame(Rect(0, 0, 600, 800));
+
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowDefaultDisplay}},
+                                  {SECOND_DISPLAY_ID, {windowSecondDisplay}}});
+
+    // Set cursor position in window in default display and check that hover enter and move
+    // events are generated.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher,
+                                MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
+                                                   AINPUT_SOURCE_MOUSE)
+                                        .displayId(ADISPLAY_ID_DEFAULT)
+                                        .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE)
+                                                         .x(300)
+                                                         .y(600))
+                                        .build()));
+    windowDefaultDisplay->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_HOVER_ENTER,
+                                       ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */);
+    windowDefaultDisplay->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_HOVER_MOVE,
+                                       ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */);
+
+    // Remove all windows in secondary display and check that no event happens on window in
+    // primary display.
+    mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {}}});
+    windowDefaultDisplay->assertNoEvents();
+
+    // Move cursor position in window in default display and check that only hover move
+    // event is generated and not hover enter event.
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowDefaultDisplay}},
+                                  {SECOND_DISPLAY_ID, {windowSecondDisplay}}});
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher,
+                                MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
+                                                   AINPUT_SOURCE_MOUSE)
+                                        .displayId(ADISPLAY_ID_DEFAULT)
+                                        .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE)
+                                                         .x(400)
+                                                         .y(700))
+                                        .build()));
+    windowDefaultDisplay->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_HOVER_MOVE,
+                                       ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */);
+    windowDefaultDisplay->assertNoEvents();
+}
+
 TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
@@ -2293,6 +2346,35 @@
     thirdWindow->consumeMotionDown();
 }
 
+TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
+    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+    sp<FakeWindowHandle> window =
+            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    window->setFocusable(true);
+
+    mDispatcher->onWindowInfosChanged({*window->getInfo()}, {});
+    setFocusedWindow(window);
+
+    window->consumeFocusEvent(true);
+
+    NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+    NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+    mDispatcher->notifyKey(&keyDown);
+    mDispatcher->notifyKey(&keyUp);
+
+    window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+    window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
+
+    // All windows are removed from the display. Ensure that we can no longer dispatch to it.
+    mDispatcher->onWindowInfosChanged({}, {});
+
+    window->consumeFocusEvent(false);
+
+    mDispatcher->notifyKey(&keyDown);
+    mDispatcher->notifyKey(&keyUp);
+    window->assertNoEvents();
+}
+
 /**
  * Ensure the correct coordinate spaces are used by InputDispatcher.
  *
@@ -6096,6 +6178,8 @@
     sp<FakeWindowHandle> mWindow;
     sp<FakeWindowHandle> mSecondWindow;
     sp<FakeWindowHandle> mDragWindow;
+    // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
+    static constexpr int32_t MOUSE_POINTER_ID = 1;
 
     void SetUp() override {
         InputDispatcherTest::SetUp();
@@ -6110,11 +6194,41 @@
         mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
     }
 
-    void injectDown() {
-        ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-                  injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
-                                   {50, 50}))
-                << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
+        switch (fromSource) {
+            case AINPUT_SOURCE_TOUCHSCREEN:
+                ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+                          injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
+                                           ADISPLAY_ID_DEFAULT, {50, 50}))
+                        << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+                break;
+            case AINPUT_SOURCE_STYLUS:
+                ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+                          injectMotionEvent(
+                                  mDispatcher,
+                                  MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
+                                                     AINPUT_SOURCE_STYLUS)
+                                          .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
+                                          .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS)
+                                                           .x(50)
+                                                           .y(50))
+                                          .build()));
+                break;
+            case AINPUT_SOURCE_MOUSE:
+                ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+                          injectMotionEvent(
+                                  mDispatcher,
+                                  MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
+                                          .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+                                          .pointer(PointerBuilder(MOUSE_POINTER_ID,
+                                                                  AMOTION_EVENT_TOOL_TYPE_MOUSE)
+                                                           .x(50)
+                                                           .y(50))
+                                          .build()));
+                break;
+            default:
+                FAIL() << "Source " << fromSource << " doesn't support drag and drop";
+        }
 
         // Window should receive motion event.
         mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
@@ -6123,9 +6237,9 @@
     // Start performing drag, we will create a drag window and transfer touch to it.
     // @param sendDown : if true, send a motion down on first window before perform drag and drop.
     // Returns true on success.
-    bool performDrag(bool sendDown = true) {
+    bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
         if (sendDown) {
-            injectDown();
+            injectDown(fromSource);
         }
 
         // The drag window covers the entire display
@@ -6143,36 +6257,10 @@
         }
         return transferred;
     }
-
-    // Start performing drag, we will create a drag window and transfer touch to it.
-    void performStylusDrag() {
-        ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-                  injectMotionEvent(mDispatcher,
-                                    MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
-                                                       AINPUT_SOURCE_STYLUS)
-                                            .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
-                                            .pointer(PointerBuilder(0,
-                                                                    AMOTION_EVENT_TOOL_TYPE_STYLUS)
-                                                             .x(50)
-                                                             .y(50))
-                                            .build()));
-        mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
-
-        // The drag window covers the entire display
-        mDragWindow = new FakeWindowHandle(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
-        mDispatcher->setInputWindows(
-                {{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}});
-
-        // Transfer touch focus to the drag window
-        mDispatcher->transferTouchFocus(mWindow->getToken(), mDragWindow->getToken(),
-                                        true /* isDragDrop */);
-        mWindow->consumeMotionCancel();
-        mDragWindow->consumeMotionDown();
-    }
 };
 
 TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
-    performDrag();
+    startDrag();
 
     // Move on window.
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6210,7 +6298,7 @@
 }
 
 TEST_F(InputDispatcherDragTests, DragAndDrop) {
-    performDrag();
+    startDrag();
 
     // Move on window.
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6242,7 +6330,7 @@
 }
 
 TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
-    performStylusDrag();
+    startDrag(true, AINPUT_SOURCE_STYLUS);
 
     // Move on window and keep button pressed.
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6289,7 +6377,7 @@
 }
 
 TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
-    performDrag();
+    startDrag();
 
     // Set second window invisible.
     mSecondWindow->setVisible(false);
@@ -6325,6 +6413,9 @@
 }
 
 TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
+    // Ensure window could track pointerIds if it didn't support split touch.
+    mWindow->setPreventSplitting(true);
+
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
               injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                                {50, 50}))
@@ -6345,7 +6436,7 @@
     mWindow->consumeMotionPointerDown(1 /* pointerIndex */);
 
     // Should not perform drag and drop when window has multi fingers.
-    ASSERT_FALSE(performDrag(false));
+    ASSERT_FALSE(startDrag(false));
 }
 
 TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
@@ -6373,7 +6464,7 @@
     mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
 
     // Perform drag and drop from first window.
-    ASSERT_TRUE(performDrag(false));
+    ASSERT_TRUE(startDrag(false));
 
     // Move on window.
     const MotionEvent secondFingerMoveEvent =
@@ -6408,7 +6499,7 @@
 }
 
 TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
-    performDrag();
+    startDrag();
 
     // Update window of second display.
     sp<FakeWindowHandle> windowInSecondary =
@@ -6459,6 +6550,55 @@
     mSecondWindow->assertNoEvents();
 }
 
+TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
+    startDrag(true, AINPUT_SOURCE_MOUSE);
+    // Move on window.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher,
+                                MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
+                                        .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+                                        .pointer(PointerBuilder(MOUSE_POINTER_ID,
+                                                                AMOTION_EVENT_TOOL_TYPE_MOUSE)
+                                                         .x(50)
+                                                         .y(50))
+                                        .build()))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+    mWindow->consumeDragEvent(false, 50, 50);
+    mSecondWindow->assertNoEvents();
+
+    // Move to another window.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher,
+                                MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
+                                        .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+                                        .pointer(PointerBuilder(MOUSE_POINTER_ID,
+                                                                AMOTION_EVENT_TOOL_TYPE_MOUSE)
+                                                         .x(150)
+                                                         .y(50))
+                                        .build()))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+    mWindow->consumeDragEvent(true, 150, 50);
+    mSecondWindow->consumeDragEvent(false, 50, 50);
+
+    // drop to another window.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher,
+                                MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
+                                        .buttonState(0)
+                                        .pointer(PointerBuilder(MOUSE_POINTER_ID,
+                                                                AMOTION_EVENT_TOOL_TYPE_MOUSE)
+                                                         .x(150)
+                                                         .y(50))
+                                        .build()))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+    mFakePolicy->assertDropTargetEquals(mSecondWindow->getToken());
+    mWindow->assertNoEvents();
+    mSecondWindow->assertNoEvents();
+}
+
 class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
 
 TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index db46699..3afa52c 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -56,7 +56,9 @@
 
 // Arbitrary display properties.
 static constexpr int32_t DISPLAY_ID = 0;
+static const std::string DISPLAY_UNIQUE_ID = "local:1";
 static constexpr int32_t SECONDARY_DISPLAY_ID = DISPLAY_ID + 1;
+static const std::string SECONDARY_DISPLAY_UNIQUE_ID = "local:2";
 static constexpr int32_t DISPLAY_WIDTH = 480;
 static constexpr int32_t DISPLAY_HEIGHT = 800;
 static constexpr int32_t VIRTUAL_DISPLAY_ID = 1;
@@ -91,6 +93,24 @@
 // Error tolerance for floating point assertions.
 static const float EPSILON = 0.001f;
 
+using ::testing::AllOf;
+
+MATCHER_P(WithAction, action, "InputEvent with specified action") {
+    return arg.action == action;
+}
+
+MATCHER_P(WithSource, source, "InputEvent with specified source") {
+    return arg.source == source;
+}
+
+MATCHER_P(WithDisplayId, displayId, "InputEvent with specified displayId") {
+    return arg.displayId == displayId;
+}
+
+MATCHER_P2(WithCoords, x, y, "MotionEvent with specified action") {
+    return arg.pointerCoords[0].getX() == x && arg.pointerCoords[0].getY();
+}
+
 template<typename T>
 static inline T min(T a, T b) {
     return a < b ? a : b;
@@ -2877,7 +2897,6 @@
 
     // Device should be disabled because it is associated with a specific display, but the
     // corresponding display is not found.
-    const std::string DISPLAY_UNIQUE_ID = "displayUniqueId";
     mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
     mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
                        InputReaderConfiguration::CHANGE_DISPLAY_INFO);
@@ -2908,7 +2927,6 @@
     mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD);
     mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
 
-    const std::string DISPLAY_UNIQUE_ID = "displayUniqueId";
     mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
     mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
                                     DISPLAY_ORIENTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID,
@@ -2918,6 +2936,21 @@
     ASSERT_EQ(DISPLAY_UNIQUE_ID, mDevice->getAssociatedDisplayUniqueId());
 }
 
+/**
+ * This test reproduces a crash caused by a dangling reference that remains after device is added
+ * and removed. The reference is accessed in InputDevice::dump(..);
+ */
+TEST_F(InputDeviceTest, DumpDoesNotCrash) {
+    constexpr int32_t TEST_EVENTHUB_ID = 10;
+    mFakeEventHub->addDevice(TEST_EVENTHUB_ID, "Test EventHub device", InputDeviceClass::BATTERY);
+
+    InputDevice device(mReader->getContext(), 1 /*id*/, 2 /*generation*/, {} /*identifier*/);
+    device.addEventHubDevice(TEST_EVENTHUB_ID, true /*populateMappers*/);
+    device.removeEventHubDevice(TEST_EVENTHUB_ID);
+    std::string dumpStr, eventHubDevStr;
+    device.dump(dumpStr, eventHubDevStr);
+}
+
 // --- InputMapperTest ---
 
 class InputMapperTest : public testing::Test {
@@ -2943,6 +2976,8 @@
         mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
                                                             *mFakeListener);
         mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes);
+        // Consume the device reset notification generated when adding a new device.
+        mFakeListener->assertNotifyDeviceResetWasCalled();
     }
 
     void SetUp() override {
@@ -2967,6 +3002,8 @@
             mReader->loopOnce();
         }
         mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
+        // Loop the reader to flush the input listener queue.
+        mReader->loopOnce();
     }
 
     std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
@@ -2990,6 +3027,8 @@
         configureDevice(0);
         mDevice->reset(ARBITRARY_TIME);
         mapper.reset(ARBITRARY_TIME);
+        // Loop the reader to flush the input listener queue.
+        mReader->loopOnce();
         return mapper;
     }
 
@@ -3015,6 +3054,7 @@
         event.code = code;
         event.value = value;
         mapper.process(&event);
+        // Loop the reader to flush the input listener queue.
         mReader->loopOnce();
     }
 
@@ -4186,10 +4226,14 @@
                             int32_t rotatedX, int32_t rotatedY);
 
     void prepareDisplay(int32_t orientation) {
-        const std::string uniqueId = "local:0";
-        const ViewportType viewportType = ViewportType::INTERNAL;
-        setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                orientation, uniqueId, NO_PORT, viewportType);
+        setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation,
+                                     DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::INTERNAL);
+    }
+
+    void prepareSecondaryDisplay() {
+        setDisplayInfoAndReconfigure(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+                                     DISPLAY_ORIENTATION_0, SECONDARY_DISPLAY_UNIQUE_ID, NO_PORT,
+                                     ViewportType::EXTERNAL);
     }
 
     static void assertCursorPointerCoords(const PointerCoords& coords, float x, float y,
@@ -4466,6 +4510,7 @@
 }
 
 TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldNotRotateMotions) {
+    mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
     addConfigurationProperty("cursor.mode", "navigation");
     // InputReader works in the un-rotated coordinate space, so orientation-aware devices do not
     // need to be rotated.
@@ -4484,11 +4529,13 @@
 }
 
 TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotions) {
+    mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
     addConfigurationProperty("cursor.mode", "navigation");
     // Since InputReader works in the un-rotated coordinate space, only devices that are not
     // orientation-aware are affected by display rotation.
     CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
 
+    clearViewports();
     prepareDisplay(DISPLAY_ORIENTATION_0);
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  0,  1));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1,  1,  1));
@@ -4499,6 +4546,7 @@
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  0, -1,  0));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1, -1,  1));
 
+    clearViewports();
     prepareDisplay(DISPLAY_ORIENTATION_90);
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1, -1,  0));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1, -1,  1));
@@ -4509,6 +4557,7 @@
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  0,  0, -1));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1, -1, -1));
 
+    clearViewports();
     prepareDisplay(DISPLAY_ORIENTATION_180);
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  0, -1));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1, -1, -1));
@@ -4519,6 +4568,7 @@
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  0,  1,  0));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1,  1,  1, -1));
 
+    clearViewports();
     prepareDisplay(DISPLAY_ORIENTATION_270);
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  0,  1,  1,  0));
     ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper,  1,  1,  1, -1));
@@ -4912,7 +4962,6 @@
     ASSERT_TRUE(mReader->getContext()->getGeneration() != generation);
 
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
-    ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
     ASSERT_EQ(DEVICE_ID, resetArgs.deviceId);
 
     process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
@@ -4974,33 +5023,118 @@
     ASSERT_EQ(20, args.pointerCoords[0].getY());
 }
 
-TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) {
+TEST_F(CursorInputMapperTest, PointerCaptureDisablesOrientationChanges) {
+    addConfigurationProperty("cursor.mode", "pointer");
     CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
 
-    // Setup for second display.
-    constexpr int32_t SECOND_DISPLAY_ID = 1;
-    const std::string SECOND_DISPLAY_UNIQUE_ID = "local:1";
-    mFakePolicy->addDisplayViewport(SECOND_DISPLAY_ID, 800, 480, DISPLAY_ORIENTATION_0,
-                                    true /*isActive*/, SECOND_DISPLAY_UNIQUE_ID, NO_PORT,
-                                    ViewportType::EXTERNAL);
-    mFakePolicy->setDefaultPointerDisplayId(SECOND_DISPLAY_ID);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    NotifyDeviceResetArgs resetArgs;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+    ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+    ASSERT_EQ(DEVICE_ID, resetArgs.deviceId);
 
-    mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
-    mFakePointerController->setPosition(100, 200);
-    mFakePointerController->setButtonState(0);
+    // Ensure the display is rotated.
+    prepareDisplay(DISPLAY_ORIENTATION_90);
 
     NotifyMotionArgs args;
+
+    // Verify that the coordinates are rotated.
     process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
     process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
     process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
     ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source);
     ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
-    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
-            110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+    ASSERT_EQ(-20, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X));
+    ASSERT_EQ(10, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
+
+    // Enable Pointer Capture.
+    mFakePolicy->setPointerCapture(true);
+    configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    NotifyPointerCaptureChangedArgs captureArgs;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyCaptureWasCalled(&captureArgs));
+    ASSERT_TRUE(captureArgs.request.enable);
+
+    // Move and verify rotation is not applied.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+    ASSERT_EQ(10, args.pointerCoords[0].getX());
+    ASSERT_EQ(20, args.pointerCoords[0].getY());
+}
+
+TEST_F(CursorInputMapperTest, ConfigureDisplayId_NoAssociatedViewport) {
+    CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+    // Set up the default display.
+    prepareDisplay(DISPLAY_ORIENTATION_90);
+
+    // Set up the secondary display as the display on which the pointer should be shown.
+    // The InputDevice is not associated with any display.
+    prepareSecondaryDisplay();
+    mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
+    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+    mFakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
+    mFakePointerController->setPosition(100, 200);
+    mFakePointerController->setButtonState(0);
+
+    // Ensure input events are generated for the secondary display.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+            AllOf(WithAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE),
+                  WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(110.0f, 220.0f))));
     ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
-    ASSERT_EQ(SECOND_DISPLAY_ID, args.displayId);
+}
+
+TEST_F(CursorInputMapperTest, ConfigureDisplayId_WithAssociatedViewport) {
+    CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+    // Set up the default display.
+    prepareDisplay(DISPLAY_ORIENTATION_90);
+
+    // Set up the secondary display as the display on which the pointer should be shown,
+    // and associate the InputDevice with the secondary display.
+    prepareSecondaryDisplay();
+    mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
+    mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, SECONDARY_DISPLAY_UNIQUE_ID);
+    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+    mFakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
+    mFakePointerController->setPosition(100, 200);
+    mFakePointerController->setButtonState(0);
+
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+            AllOf(WithAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE),
+                  WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(110.0f, 220.0f))));
+    ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
+}
+
+TEST_F(CursorInputMapperTest, ConfigureDisplayId_IgnoresEventsForMismatchedPointerDisplay) {
+    CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+    // Set up the default display as the display on which the pointer should be shown.
+    prepareDisplay(DISPLAY_ORIENTATION_90);
+    mFakePolicy->setDefaultPointerDisplayId(DISPLAY_ID);
+
+    // Associate the InputDevice with the secondary display.
+    prepareSecondaryDisplay();
+    mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, SECONDARY_DISPLAY_UNIQUE_ID);
+    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+    // The mapper should not generate any events because it is associated with a display that is
+    // different from the pointer display.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
 }
 
 // --- TouchInputMapperTest ---
@@ -6683,6 +6817,61 @@
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
 }
 
+TEST_F(SingleTouchInputMapperTest,
+       Process_WhenViewportActiveStatusChanged_TouchIsCanceledAndDeviceIsReset) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareButtons();
+    prepareAxes(POSITION);
+    SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
+    NotifyMotionArgs motionArgs;
+
+    // Start a new gesture.
+    processDown(mapper, 100, 200);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+
+    // Make the viewport inactive. This will put the device in disabled mode.
+    auto viewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL);
+    viewport->isActive = false;
+    mFakePolicy->updateViewport(*viewport);
+    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+    // We should receive a cancel event for the ongoing gesture.
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+    // Then we should be notified that the device was reset.
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
+
+    // No events are generated while the viewport is inactive.
+    processMove(mapper, 101, 201);
+    processSync(mapper);
+    processDown(mapper, 102, 202);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+    // Make the viewport active again. The device should resume processing events.
+    viewport->isActive = true;
+    mFakePolicy->updateViewport(*viewport);
+    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+    // The device is reset because it changes back to direct mode, without generating any events.
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+    // Start a new gesture.
+    processDown(mapper, 100, 200);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+
+    // No more events.
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasNotCalled());
+}
+
 // --- TouchDisplayProjectionTest ---
 
 class TouchDisplayProjectionTest : public SingleTouchInputMapperTest {
@@ -8540,27 +8729,27 @@
     ASSERT_TRUE(mFakePolicy->updateViewport(displayViewport));
     configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
 
-    // Finger move
+    // The ongoing touch should be canceled immediately
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+
+    // Finger move is ignored
     x += 10, y += 10;
     processPosition(mapper, x, y);
     processSync(mapper);
-
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
-    EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
 
     // Reactivate display viewport
     displayViewport.isActive = true;
     ASSERT_TRUE(mFakePolicy->updateViewport(displayViewport));
     configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
 
-    // Finger move again
+    // Finger move again starts new gesture
     x += 10, y += 10;
     processPosition(mapper, x, y);
     processSync(mapper);
-
-    // Gesture is aborted, so events after display is activated won't be dispatched until there is
-    // no pointer on the touch device.
-    mFakeListener->assertNotifyMotionWasNotCalled();
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
 }
 
 TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) {
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index 6a26c63..57b382c 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -69,6 +69,13 @@
                                            "Expected notifyMotion() to have been called."));
 }
 
+void TestInputListener::assertNotifyMotionWasCalled(
+        const ::testing::Matcher<NotifyMotionArgs>& matcher) {
+    NotifyMotionArgs outEventArgs;
+    ASSERT_NO_FATAL_FAILURE(assertNotifyMotionWasCalled(&outEventArgs));
+    ASSERT_THAT(outEventArgs, matcher);
+}
+
 void TestInputListener::assertNotifyMotionWasNotCalled() {
     ASSERT_NO_FATAL_FAILURE(
             assertNotCalled<NotifyMotionArgs>("notifyMotion() should not be called."));
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index 626cdfc..0bdfc6b 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -18,6 +18,7 @@
 #define _UI_TEST_INPUT_LISTENER_H
 
 #include <android-base/thread_annotations.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include "InputListener.h"
 
@@ -48,6 +49,8 @@
 
     void assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs = nullptr);
 
+    void assertNotifyMotionWasCalled(const ::testing::Matcher<NotifyMotionArgs>& matcher);
+
     void assertNotifyMotionWasNotCalled();
 
     void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = nullptr);
diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
index 0062f42..29fa001 100644
--- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
+++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
@@ -16,13 +16,17 @@
 
 #include "../UnwantedInteractionBlocker.h"
 #include <android-base/silent_death_test.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <gui/constants.h>
 #include <linux/input.h>
 #include <thread>
+#include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter.h"
 
 #include "TestInputListener.h"
 
+using ::testing::AllOf;
+
 namespace android {
 
 constexpr int32_t DEVICE_ID = 3;
@@ -30,6 +34,8 @@
 constexpr int32_t Y_RESOLUTION = 11;
 constexpr int32_t MAJOR_RESOLUTION = 1;
 
+const nsecs_t RESAMPLE_PERIOD = ::ui::kResamplePeriod.InNanoseconds();
+
 constexpr int POINTER_0_DOWN =
         AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
 constexpr int POINTER_1_DOWN =
@@ -47,6 +53,27 @@
 constexpr int UP = AMOTION_EVENT_ACTION_UP;
 constexpr int CANCEL = AMOTION_EVENT_ACTION_CANCEL;
 
+constexpr int32_t FLAG_CANCELED = AMOTION_EVENT_FLAG_CANCELED;
+
+MATCHER_P(WithAction, action, "MotionEvent with specified action") {
+    bool result = true;
+    if (action == CANCEL) {
+        result &= (arg.flags & FLAG_CANCELED) != 0;
+    }
+    result &= arg.action == action;
+    *result_listener << "expected to receive " << MotionEvent::actionToString(action)
+                     << " but received " << MotionEvent::actionToString(arg.action) << " instead.";
+    return result;
+}
+
+MATCHER_P(WithFlags, flags, "MotionEvent with specified flags") {
+    return arg.flags == flags;
+}
+
+static nsecs_t toNs(std::chrono::nanoseconds duration) {
+    return duration.count();
+}
+
 struct PointerData {
     float x;
     float y;
@@ -252,7 +279,7 @@
                                      /*newSuppressedPointerIds*/ {1});
     ASSERT_EQ(2u, result.size());
     assertArgs(result[0], POINTER_1_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}, {2, {7, 8, 9}}});
-    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+    ASSERT_EQ(FLAG_CANCELED, result[0].flags);
     assertArgs(result[1], MOVE, {{0, {1, 2, 3}}, {2, {7, 8, 9}}});
 }
 
@@ -267,7 +294,7 @@
                                      /*newSuppressedPointerIds*/ {0});
     ASSERT_EQ(1u, result.size());
     assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}});
-    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+    ASSERT_EQ(FLAG_CANCELED, result[0].flags);
 }
 
 /**
@@ -282,7 +309,7 @@
                                      /*newSuppressedPointerIds*/ {1});
     ASSERT_EQ(1u, result.size());
     assertArgs(result[0], POINTER_1_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}, {2, {7, 8, 9}}});
-    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+    ASSERT_EQ(FLAG_CANCELED, result[0].flags);
 }
 
 /**
@@ -297,7 +324,7 @@
                                      /*newSuppressedPointerIds*/ {0});
     ASSERT_EQ(1u, result.size());
     assertArgs(result[0], POINTER_0_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}});
-    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+    ASSERT_EQ(FLAG_CANCELED, result[0].flags);
 }
 
 /**
@@ -312,7 +339,7 @@
                                      /*newSuppressedPointerIds*/ {0, 1});
     ASSERT_EQ(1u, result.size());
     assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}, {1, {4, 5, 6}}});
-    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+    ASSERT_EQ(FLAG_CANCELED, result[0].flags);
 }
 
 /**
@@ -328,7 +355,7 @@
                                      /*newSuppressedPointerIds*/ {0, 1});
     ASSERT_EQ(1u, result.size());
     assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}});
-    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+    ASSERT_EQ(FLAG_CANCELED, result[0].flags);
 }
 
 /**
@@ -384,7 +411,7 @@
     expected.reported_tool_type = ::ui::EventPointerType::kTouch;
     expected.stylus_button = false;
 
-    ASSERT_EQ(expected, touches[0]) << toString(touches[0]);
+    ASSERT_EQ(expected, touches[0]) << touches[0];
 }
 
 // --- UnwantedInteractionBlockerTest ---
@@ -569,6 +596,114 @@
     dumpThread.join();
 }
 
+/**
+ * Heuristic filter that's present in the palm rejection model blocks touches early if the size
+ * of the touch is large. This is an integration test that checks that this filter kicks in.
+ */
+TEST_F(UnwantedInteractionBlockerTest, HeuristicFilterWorks) {
+    mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()});
+    // Small touch down
+    NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
+    mBlocker->notifyMotion(&args1);
+    mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN));
+
+    // Large touch oval on the next move
+    NotifyMotionArgs args2 =
+            generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, MOVE, {{4, 5, 200}});
+    mBlocker->notifyMotion(&args2);
+    mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));
+
+    // Lift up the touch to force the model to decide on whether it's a palm
+    NotifyMotionArgs args3 =
+            generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, UP, {{4, 5, 200}});
+    mBlocker->notifyMotion(&args3);
+    mTestListener.assertNotifyMotionWasCalled(WithAction(CANCEL));
+}
+
+/**
+ * Send a stylus event that would have triggered the heuristic palm detector if it were a touch
+ * event. However, since it's a stylus event, it should propagate without being canceled through
+ * the blocker.
+ * This is similar to `HeuristicFilterWorks` test, but for stylus tool.
+ */
+TEST_F(UnwantedInteractionBlockerTest, StylusIsNotBlocked) {
+    InputDeviceInfo info = generateTestDeviceInfo();
+    info.addSource(AINPUT_SOURCE_STYLUS);
+    mBlocker->notifyInputDevicesChanged({info});
+    NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
+    args1.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    mBlocker->notifyMotion(&args1);
+    mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN));
+
+    // Move the stylus, setting large TOUCH_MAJOR/TOUCH_MINOR dimensions
+    NotifyMotionArgs args2 =
+            generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, MOVE, {{4, 5, 200}});
+    args2.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    mBlocker->notifyMotion(&args2);
+    mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));
+
+    // Lift up the stylus. If it were a touch event, this would force the model to decide on whether
+    // it's a palm.
+    NotifyMotionArgs args3 =
+            generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, UP, {{4, 5, 200}});
+    args3.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    mBlocker->notifyMotion(&args3);
+    mTestListener.assertNotifyMotionWasCalled(WithAction(UP));
+}
+
+/**
+ * Send a mixed touch and stylus event.
+ * The touch event goes first, and is a palm. The stylus event goes down after.
+ * Stylus event should continue to work even after touch is detected as a palm.
+ */
+TEST_F(UnwantedInteractionBlockerTest, TouchIsBlockedWhenMixedWithStylus) {
+    InputDeviceInfo info = generateTestDeviceInfo();
+    info.addSource(AINPUT_SOURCE_STYLUS);
+    mBlocker->notifyInputDevicesChanged({info});
+
+    // Touch down
+    NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
+    mBlocker->notifyMotion(&args1);
+    mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN));
+
+    // Stylus pointer down
+    NotifyMotionArgs args2 = generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, POINTER_1_DOWN,
+                                                {{1, 2, 3}, {10, 20, 30}});
+    args2.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    mBlocker->notifyMotion(&args2);
+    mTestListener.assertNotifyMotionWasCalled(WithAction(POINTER_1_DOWN));
+
+    // Large touch oval on the next finger move
+    NotifyMotionArgs args3 = generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, MOVE,
+                                                {{1, 2, 300}, {11, 21, 30}});
+    args3.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    mBlocker->notifyMotion(&args3);
+    mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));
+
+    // Lift up the finger pointer. It should be canceled due to the heuristic filter.
+    NotifyMotionArgs args4 = generateMotionArgs(0 /*downTime*/, 3 * RESAMPLE_PERIOD, POINTER_0_UP,
+                                                {{1, 2, 300}, {11, 21, 30}});
+    args4.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    mBlocker->notifyMotion(&args4);
+    mTestListener.assertNotifyMotionWasCalled(
+            AllOf(WithAction(POINTER_0_UP), WithFlags(FLAG_CANCELED)));
+
+    NotifyMotionArgs args5 =
+            generateMotionArgs(0 /*downTime*/, 4 * RESAMPLE_PERIOD, MOVE, {{12, 22, 30}});
+    args5.pointerProperties[0].id = args4.pointerProperties[1].id;
+    args5.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    mBlocker->notifyMotion(&args5);
+    mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));
+
+    // Lift up the stylus pointer
+    NotifyMotionArgs args6 =
+            generateMotionArgs(0 /*downTime*/, 5 * RESAMPLE_PERIOD, UP, {{4, 5, 200}});
+    args6.pointerProperties[0].id = args4.pointerProperties[1].id;
+    args6.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    mBlocker->notifyMotion(&args6);
+    mTestListener.assertNotifyMotionWasCalled(WithAction(UP));
+}
+
 using UnwantedInteractionBlockerTestDeathTest = UnwantedInteractionBlockerTest;
 
 /**
@@ -630,138 +765,138 @@
  */
 TEST_F(PalmRejectorTest, TwoPointersAreCanceled) {
     std::vector<NotifyMotionArgs> argsList;
-    constexpr nsecs_t downTime = 255955749837000;
+    const nsecs_t downTime = toNs(0ms);
 
     mPalmRejector->processMotion(
             generateMotionArgs(downTime, downTime, DOWN, {{1342.0, 613.0, 79.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955759313000, MOVE, {{1406.0, 650.0, 52.0}}));
+            generateMotionArgs(downTime, toNs(8ms), MOVE, {{1406.0, 650.0, 52.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955766361000, MOVE, {{1429.0, 672.0, 46.0}}));
+            generateMotionArgs(downTime, toNs(16ms), MOVE, {{1429.0, 672.0, 46.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955775989000, MOVE, {{1417.0, 685.0, 41.0}}));
+            generateMotionArgs(downTime, toNs(24ms), MOVE, {{1417.0, 685.0, 41.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955775989000, POINTER_1_DOWN,
+            generateMotionArgs(downTime, toNs(32ms), POINTER_1_DOWN,
                                {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955783039000, MOVE,
+            generateMotionArgs(downTime, toNs(40ms), MOVE,
                                {{1414.0, 702.0, 41.0}, {1059.0, 731.0, 12.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955792536000, MOVE,
+            generateMotionArgs(downTime, toNs(48ms), MOVE,
                                {{1415.0, 719.0, 44.0}, {1060.0, 760.0, 11.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955799474000, MOVE,
+            generateMotionArgs(downTime, toNs(56ms), MOVE,
                                {{1421.0, 733.0, 42.0}, {1065.0, 769.0, 13.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955809177000, MOVE,
+            generateMotionArgs(downTime, toNs(64ms), MOVE,
                                {{1426.0, 742.0, 43.0}, {1068.0, 771.0, 13.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955816131000, MOVE,
+            generateMotionArgs(downTime, toNs(72ms), MOVE,
                                {{1430.0, 748.0, 45.0}, {1069.0, 772.0, 13.0}}));
     argsList = mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955825907000, MOVE,
+            generateMotionArgs(downTime, toNs(80ms), MOVE,
                                {{1432.0, 750.0, 44.0}, {1069.0, 772.0, 13.0}}));
     ASSERT_EQ(1u, argsList.size());
     ASSERT_EQ(0 /* No FLAG_CANCELED */, argsList[0].flags);
     argsList = mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955832736000, MOVE,
+            generateMotionArgs(downTime, toNs(88ms), MOVE,
                                {{1433.0, 751.0, 44.0}, {1070.0, 771.0, 13.0}}));
     ASSERT_EQ(2u, argsList.size());
     ASSERT_EQ(POINTER_0_UP, argsList[0].action);
-    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+    ASSERT_EQ(FLAG_CANCELED, argsList[0].flags);
     ASSERT_EQ(MOVE, argsList[1].action);
     ASSERT_EQ(1u, argsList[1].pointerCount);
     ASSERT_EQ(0, argsList[1].flags);
 
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955842432000, MOVE,
+            generateMotionArgs(downTime, toNs(96ms), MOVE,
                                {{1433.0, 751.0, 42.0}, {1071.0, 770.0, 13.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955849380000, MOVE,
+            generateMotionArgs(downTime, toNs(104ms), MOVE,
                                {{1433.0, 751.0, 45.0}, {1072.0, 769.0, 13.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955859046000, MOVE,
+            generateMotionArgs(downTime, toNs(112ms), MOVE,
                                {{1433.0, 751.0, 43.0}, {1072.0, 768.0, 13.0}}));
     argsList = mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955869823000, MOVE,
+            generateMotionArgs(downTime, toNs(120ms), MOVE,
                                {{1433.0, 751.0, 45.0}, {1072.0, 767.0, 13.0}}));
     ASSERT_EQ(1u, argsList.size());
     ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, argsList[0].action);
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955875641000, MOVE,
+            generateMotionArgs(downTime, toNs(128ms), MOVE,
                                {{1433.0, 751.0, 43.0}, {1072.0, 766.0, 13.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955882693000, MOVE,
+            generateMotionArgs(downTime, toNs(136ms), MOVE,
                                {{1433.0, 750.0, 44.0}, {1072.0, 765.0, 13.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955892324000, MOVE,
+            generateMotionArgs(downTime, toNs(144ms), MOVE,
                                {{1433.0, 750.0, 42.0}, {1072.0, 763.0, 14.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955899425000, MOVE,
+            generateMotionArgs(downTime, toNs(152ms), MOVE,
                                {{1434.0, 750.0, 44.0}, {1073.0, 761.0, 14.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955909400000, MOVE,
+            generateMotionArgs(downTime, toNs(160ms), MOVE,
                                {{1435.0, 750.0, 43.0}, {1073.0, 759.0, 15.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955915885000, MOVE,
+            generateMotionArgs(downTime, toNs(168ms), MOVE,
                                {{1436.0, 750.0, 45.0}, {1074.0, 757.0, 15.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955925607000, MOVE,
+            generateMotionArgs(downTime, toNs(176ms), MOVE,
                                {{1436.0, 750.0, 44.0}, {1074.0, 755.0, 15.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955932580000, MOVE,
+            generateMotionArgs(downTime, toNs(184ms), MOVE,
                                {{1436.0, 750.0, 45.0}, {1074.0, 753.0, 15.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955942231000, MOVE,
+            generateMotionArgs(downTime, toNs(192ms), MOVE,
                                {{1436.0, 749.0, 44.0}, {1074.0, 751.0, 15.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955949204000, MOVE,
+            generateMotionArgs(downTime, toNs(200ms), MOVE,
                                {{1435.0, 748.0, 45.0}, {1074.0, 749.0, 15.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955959103000, MOVE,
+            generateMotionArgs(downTime, toNs(208ms), MOVE,
                                {{1434.0, 746.0, 44.0}, {1074.0, 747.0, 14.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955965884000, MOVE,
+            generateMotionArgs(downTime, toNs(216ms), MOVE,
                                {{1433.0, 744.0, 44.0}, {1075.0, 745.0, 14.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955975649000, MOVE,
+            generateMotionArgs(downTime, toNs(224ms), MOVE,
                                {{1431.0, 741.0, 43.0}, {1075.0, 742.0, 13.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955982537000, MOVE,
+            generateMotionArgs(downTime, toNs(232ms), MOVE,
                                {{1428.0, 738.0, 43.0}, {1076.0, 739.0, 12.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955992284000, MOVE,
+            generateMotionArgs(downTime, toNs(240ms), MOVE,
                                {{1400.0, 726.0, 54.0}, {1076.0, 739.0, 13.0}}));
     argsList = mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955999348000, POINTER_1_UP,
+            generateMotionArgs(downTime, toNs(248ms), POINTER_1_UP,
                                {{1362.0, 716.0, 55.0}, {1076.0, 739.0, 13.0}}));
     ASSERT_TRUE(argsList.empty());
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255955999348000, MOVE, {{1362.0, 716.0, 55.0}}));
+            generateMotionArgs(downTime, toNs(256ms), MOVE, {{1362.0, 716.0, 55.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255956008885000, MOVE, {{1347.0, 707.0, 54.0}}));
+            generateMotionArgs(downTime, toNs(264ms), MOVE, {{1347.0, 707.0, 54.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255956015791000, MOVE, {{1340.0, 698.0, 54.0}}));
+            generateMotionArgs(downTime, toNs(272ms), MOVE, {{1340.0, 698.0, 54.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255956025804000, MOVE, {{1338.0, 694.0, 55.0}}));
+            generateMotionArgs(downTime, toNs(280ms), MOVE, {{1338.0, 694.0, 55.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255956032314000, MOVE, {{1336.0, 690.0, 53.0}}));
+            generateMotionArgs(downTime, toNs(288ms), MOVE, {{1336.0, 690.0, 53.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255956042329000, MOVE, {{1334.0, 685.0, 47.0}}));
+            generateMotionArgs(downTime, toNs(296ms), MOVE, {{1334.0, 685.0, 47.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255956048979000, MOVE, {{1333.0, 679.0, 46.0}}));
+            generateMotionArgs(downTime, toNs(304ms), MOVE, {{1333.0, 679.0, 46.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255956058813000, MOVE, {{1332.0, 672.0, 45.0}}));
+            generateMotionArgs(downTime, toNs(312ms), MOVE, {{1332.0, 672.0, 45.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255956065592000, MOVE, {{1333.0, 666.0, 40.0}}));
+            generateMotionArgs(downTime, toNs(320ms), MOVE, {{1333.0, 666.0, 40.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255956075276000, MOVE, {{1336.0, 661.0, 24.0}}));
+            generateMotionArgs(downTime, toNs(328ms), MOVE, {{1336.0, 661.0, 24.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255956082198000, MOVE, {{1338.0, 656.0, 16.0}}));
+            generateMotionArgs(downTime, toNs(336ms), MOVE, {{1338.0, 656.0, 16.0}}));
     mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255956092059000, MOVE, {{1341.0, 649.0, 1.0}}));
+            generateMotionArgs(downTime, toNs(344ms), MOVE, {{1341.0, 649.0, 1.0}}));
     argsList = mPalmRejector->processMotion(
-            generateMotionArgs(downTime, 255956098764000, UP, {{1341.0, 649.0, 1.0}}));
+            generateMotionArgs(downTime, toNs(352ms), UP, {{1341.0, 649.0, 1.0}}));
     ASSERT_TRUE(argsList.empty());
 }
 
@@ -845,7 +980,7 @@
     ASSERT_EQ(2u, argsList.size());
     // First event - cancel pointer 1
     ASSERT_EQ(POINTER_1_UP, argsList[0].action);
-    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+    ASSERT_EQ(FLAG_CANCELED, argsList[0].flags);
     // Second event - send MOVE for the remaining pointer
     ASSERT_EQ(MOVE, argsList[1].action);
     ASSERT_EQ(0, argsList[1].flags);
@@ -886,7 +1021,7 @@
     // Cancel all
     ASSERT_EQ(CANCEL, argsList[0].action);
     ASSERT_EQ(2u, argsList[0].pointerCount);
-    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+    ASSERT_EQ(FLAG_CANCELED, argsList[0].flags);
 
     // Future move events are ignored
     argsList = mPalmRejector->processMotion(
@@ -932,7 +1067,7 @@
                                {{1414.0, 702.0, 41.0}, {1059.0, 731.0, 12.0}}));
     ASSERT_EQ(1u, argsList.size());
     ASSERT_EQ(CANCEL, argsList[0].action) << MotionEvent::actionToString(argsList[0].action);
-    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+    ASSERT_EQ(FLAG_CANCELED, argsList[0].flags);
 
     // Future move events should not go to the listener.
     argsList = mPalmRejector->processMotion(
@@ -966,7 +1101,7 @@
                                {{1417.0, 685.0, 41.0}, {1060, 700, 10.0}}));
     ASSERT_EQ(2u, argsList.size());
     ASSERT_EQ(POINTER_1_UP, argsList[0].action);
-    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+    ASSERT_EQ(FLAG_CANCELED, argsList[0].flags);
 
     ASSERT_EQ(MOVE, argsList[1].action) << MotionEvent::actionToString(argsList[1].action);
     ASSERT_EQ(0, argsList[1].flags);
diff --git a/services/sensorservice/AidlSensorHalWrapper.cpp b/services/sensorservice/AidlSensorHalWrapper.cpp
index 4d1de96..f5b360f 100644
--- a/services/sensorservice/AidlSensorHalWrapper.cpp
+++ b/services/sensorservice/AidlSensorHalWrapper.cpp
@@ -23,6 +23,7 @@
 #include <aidlcommonsupport/NativeHandle.h>
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
+#include <aidl/sensors/convert.h>
 
 using ::aidl::android::hardware::sensors::AdditionalInfo;
 using ::aidl::android::hardware::sensors::DynamicSensorInfo;
@@ -34,469 +35,16 @@
 using ::android::AidlMessageQueue;
 using ::android::hardware::EventFlag;
 using ::android::hardware::sensors::V2_1::implementation::MAX_RECEIVE_BUFFER_EVENT_COUNT;
+using ::android::hardware::sensors::implementation::convertToStatus;
+using ::android::hardware::sensors::implementation::convertToSensor;
+using ::android::hardware::sensors::implementation::convertToSensorEvent;
+using ::android::hardware::sensors::implementation::convertFromSensorEvent;
+
 
 namespace android {
 
 namespace {
 
-status_t convertToStatus(ndk::ScopedAStatus status) {
-    if (status.isOk()) {
-        return OK;
-    } else {
-        switch (status.getExceptionCode()) {
-            case EX_ILLEGAL_ARGUMENT: {
-                return BAD_VALUE;
-            }
-            case EX_SECURITY: {
-                return PERMISSION_DENIED;
-            }
-            case EX_UNSUPPORTED_OPERATION: {
-                return INVALID_OPERATION;
-            }
-            case EX_SERVICE_SPECIFIC: {
-                switch (status.getServiceSpecificError()) {
-                    case ISensors::ERROR_BAD_VALUE: {
-                        return BAD_VALUE;
-                    }
-                    case ISensors::ERROR_NO_MEMORY: {
-                        return NO_MEMORY;
-                    }
-                    default: {
-                        return UNKNOWN_ERROR;
-                    }
-                }
-            }
-            default: {
-                return UNKNOWN_ERROR;
-            }
-        }
-    }
-}
-
-void convertToSensor(const SensorInfo &src, sensor_t *dst) {
-    dst->name = strdup(src.name.c_str());
-    dst->vendor = strdup(src.vendor.c_str());
-    dst->version = src.version;
-    dst->handle = src.sensorHandle;
-    dst->type = (int)src.type;
-    dst->maxRange = src.maxRange;
-    dst->resolution = src.resolution;
-    dst->power = src.power;
-    dst->minDelay = src.minDelayUs;
-    dst->fifoReservedEventCount = src.fifoReservedEventCount;
-    dst->fifoMaxEventCount = src.fifoMaxEventCount;
-    dst->stringType = strdup(src.typeAsString.c_str());
-    dst->requiredPermission = strdup(src.requiredPermission.c_str());
-    dst->maxDelay = src.maxDelayUs;
-    dst->flags = src.flags;
-    dst->reserved[0] = dst->reserved[1] = 0;
-}
-
-void convertToSensorEvent(const Event &src, sensors_event_t *dst) {
-    *dst = {.version = sizeof(sensors_event_t),
-            .sensor = src.sensorHandle,
-            .type = (int32_t)src.sensorType,
-            .reserved0 = 0,
-            .timestamp = src.timestamp};
-
-    switch (src.sensorType) {
-        case SensorType::META_DATA: {
-            // Legacy HALs expect the handle reference in the meta data field.
-            // Copy it over from the handle of the event.
-            dst->meta_data.what = (int32_t)src.payload.get<Event::EventPayload::meta>().what;
-            dst->meta_data.sensor = src.sensorHandle;
-            // Set the sensor handle to 0 to maintain compatibility.
-            dst->sensor = 0;
-            break;
-        }
-
-        case SensorType::ACCELEROMETER:
-        case SensorType::MAGNETIC_FIELD:
-        case SensorType::ORIENTATION:
-        case SensorType::GYROSCOPE:
-        case SensorType::GRAVITY:
-        case SensorType::LINEAR_ACCELERATION: {
-            dst->acceleration.x = src.payload.get<Event::EventPayload::vec3>().x;
-            dst->acceleration.y = src.payload.get<Event::EventPayload::vec3>().y;
-            dst->acceleration.z = src.payload.get<Event::EventPayload::vec3>().z;
-            dst->acceleration.status = (int32_t)src.payload.get<Event::EventPayload::vec3>().status;
-            break;
-        }
-
-        case SensorType::GAME_ROTATION_VECTOR: {
-            dst->data[0] = src.payload.get<Event::EventPayload::vec4>().x;
-            dst->data[1] = src.payload.get<Event::EventPayload::vec4>().y;
-            dst->data[2] = src.payload.get<Event::EventPayload::vec4>().z;
-            dst->data[3] = src.payload.get<Event::EventPayload::vec4>().w;
-            break;
-        }
-
-        case SensorType::ROTATION_VECTOR:
-        case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
-            dst->data[0] = src.payload.get<Event::EventPayload::data>().values[0];
-            dst->data[1] = src.payload.get<Event::EventPayload::data>().values[1];
-            dst->data[2] = src.payload.get<Event::EventPayload::data>().values[2];
-            dst->data[3] = src.payload.get<Event::EventPayload::data>().values[3];
-            dst->data[4] = src.payload.get<Event::EventPayload::data>().values[4];
-            break;
-        }
-
-        case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
-        case SensorType::GYROSCOPE_UNCALIBRATED:
-        case SensorType::ACCELEROMETER_UNCALIBRATED: {
-            dst->uncalibrated_gyro.x_uncalib = src.payload.get<Event::EventPayload::uncal>().x;
-            dst->uncalibrated_gyro.y_uncalib = src.payload.get<Event::EventPayload::uncal>().y;
-            dst->uncalibrated_gyro.z_uncalib = src.payload.get<Event::EventPayload::uncal>().z;
-            dst->uncalibrated_gyro.x_bias = src.payload.get<Event::EventPayload::uncal>().xBias;
-            dst->uncalibrated_gyro.y_bias = src.payload.get<Event::EventPayload::uncal>().yBias;
-            dst->uncalibrated_gyro.z_bias = src.payload.get<Event::EventPayload::uncal>().zBias;
-            break;
-        }
-
-        case SensorType::HINGE_ANGLE:
-        case SensorType::DEVICE_ORIENTATION:
-        case SensorType::LIGHT:
-        case SensorType::PRESSURE:
-        case SensorType::PROXIMITY:
-        case SensorType::RELATIVE_HUMIDITY:
-        case SensorType::AMBIENT_TEMPERATURE:
-        case SensorType::SIGNIFICANT_MOTION:
-        case SensorType::STEP_DETECTOR:
-        case SensorType::TILT_DETECTOR:
-        case SensorType::WAKE_GESTURE:
-        case SensorType::GLANCE_GESTURE:
-        case SensorType::PICK_UP_GESTURE:
-        case SensorType::WRIST_TILT_GESTURE:
-        case SensorType::STATIONARY_DETECT:
-        case SensorType::MOTION_DETECT:
-        case SensorType::HEART_BEAT:
-        case SensorType::LOW_LATENCY_OFFBODY_DETECT: {
-            dst->data[0] = src.payload.get<Event::EventPayload::scalar>();
-            break;
-        }
-
-        case SensorType::STEP_COUNTER: {
-            dst->u64.step_counter = src.payload.get<Event::EventPayload::stepCount>();
-            break;
-        }
-
-        case SensorType::HEART_RATE: {
-            dst->heart_rate.bpm = src.payload.get<Event::EventPayload::heartRate>().bpm;
-            dst->heart_rate.status =
-                    (int8_t)src.payload.get<Event::EventPayload::heartRate>().status;
-            break;
-        }
-
-        case SensorType::POSE_6DOF: { // 15 floats
-            for (size_t i = 0; i < 15; ++i) {
-                dst->data[i] = src.payload.get<Event::EventPayload::pose6DOF>().values[i];
-            }
-            break;
-        }
-
-        case SensorType::DYNAMIC_SENSOR_META: {
-            dst->dynamic_sensor_meta.connected =
-                    src.payload.get<Event::EventPayload::dynamic>().connected;
-            dst->dynamic_sensor_meta.handle =
-                    src.payload.get<Event::EventPayload::dynamic>().sensorHandle;
-            dst->dynamic_sensor_meta.sensor = NULL; // to be filled in later
-
-            memcpy(dst->dynamic_sensor_meta.uuid,
-                   src.payload.get<Event::EventPayload::dynamic>().uuid.values.data(), 16);
-
-            break;
-        }
-
-        case SensorType::ADDITIONAL_INFO: {
-            const AdditionalInfo &srcInfo = src.payload.get<Event::EventPayload::additional>();
-
-            additional_info_event_t *dstInfo = &dst->additional_info;
-            dstInfo->type = (int32_t)srcInfo.type;
-            dstInfo->serial = srcInfo.serial;
-
-            switch (srcInfo.payload.getTag()) {
-                case AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32: {
-                    const auto &values =
-                            srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataInt32>()
-                                    .values;
-                    CHECK_EQ(values.size() * sizeof(int32_t), sizeof(dstInfo->data_int32));
-                    memcpy(dstInfo->data_int32, values.data(), sizeof(dstInfo->data_int32));
-                    break;
-                }
-                case AdditionalInfo::AdditionalInfoPayload::Tag::dataFloat: {
-                    const auto &values =
-                            srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataFloat>()
-                                    .values;
-                    CHECK_EQ(values.size() * sizeof(float), sizeof(dstInfo->data_float));
-                    memcpy(dstInfo->data_float, values.data(), sizeof(dstInfo->data_float));
-                    break;
-                }
-                default: {
-                    ALOGE("Invalid sensor additional info tag: %d", (int)srcInfo.payload.getTag());
-                }
-            }
-            break;
-        }
-
-        case SensorType::HEAD_TRACKER: {
-            const auto &ht = src.payload.get<Event::EventPayload::headTracker>();
-            dst->head_tracker.rx = ht.rx;
-            dst->head_tracker.ry = ht.ry;
-            dst->head_tracker.rz = ht.rz;
-            dst->head_tracker.vx = ht.vx;
-            dst->head_tracker.vy = ht.vy;
-            dst->head_tracker.vz = ht.vz;
-            dst->head_tracker.discontinuity_count = ht.discontinuityCount;
-            break;
-        }
-
-        case SensorType::ACCELEROMETER_LIMITED_AXES:
-        case SensorType::GYROSCOPE_LIMITED_AXES:
-            dst->limited_axes_imu.x = src.payload.get<Event::EventPayload::limitedAxesImu>().x;
-            dst->limited_axes_imu.y = src.payload.get<Event::EventPayload::limitedAxesImu>().y;
-            dst->limited_axes_imu.z = src.payload.get<Event::EventPayload::limitedAxesImu>().z;
-            dst->limited_axes_imu.x_supported =
-                    src.payload.get<Event::EventPayload::limitedAxesImu>().xSupported;
-            dst->limited_axes_imu.y_supported =
-                    src.payload.get<Event::EventPayload::limitedAxesImu>().ySupported;
-            dst->limited_axes_imu.z_supported =
-                    src.payload.get<Event::EventPayload::limitedAxesImu>().zSupported;
-            break;
-
-        case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
-        case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
-            dst->limited_axes_imu_uncalibrated.x_uncalib =
-                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().x;
-            dst->limited_axes_imu_uncalibrated.y_uncalib =
-                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().y;
-            dst->limited_axes_imu_uncalibrated.z_uncalib =
-                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().z;
-            dst->limited_axes_imu_uncalibrated.x_bias =
-                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xBias;
-            dst->limited_axes_imu_uncalibrated.y_bias =
-                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().yBias;
-            dst->limited_axes_imu_uncalibrated.z_bias =
-                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zBias;
-            dst->limited_axes_imu_uncalibrated.x_supported =
-                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xSupported;
-            dst->limited_axes_imu_uncalibrated.y_supported =
-                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().ySupported;
-            dst->limited_axes_imu_uncalibrated.z_supported =
-                    src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zSupported;
-            break;
-
-        case SensorType::HEADING:
-            dst->heading.heading = src.payload.get<Event::EventPayload::heading>().heading;
-            dst->heading.accuracy = src.payload.get<Event::EventPayload::heading>().accuracy;
-            break;
-
-        default: {
-            CHECK_GE((int32_t)src.sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
-
-            memcpy(dst->data, src.payload.get<Event::EventPayload::data>().values.data(),
-                   16 * sizeof(float));
-            break;
-        }
-    }
-}
-
-void convertFromSensorEvent(const sensors_event_t &src, Event *dst) {
-    *dst = {
-            .timestamp = src.timestamp,
-            .sensorHandle = src.sensor,
-            .sensorType = (SensorType)src.type,
-    };
-
-    switch (dst->sensorType) {
-        case SensorType::META_DATA: {
-            Event::EventPayload::MetaData meta;
-            meta.what = (Event::EventPayload::MetaData::MetaDataEventType)src.meta_data.what;
-            // Legacy HALs contain the handle reference in the meta data field.
-            // Copy that over to the handle of the event. In legacy HALs this
-            // field was expected to be 0.
-            dst->sensorHandle = src.meta_data.sensor;
-            dst->payload.set<Event::EventPayload::Tag::meta>(meta);
-            break;
-        }
-
-        case SensorType::ACCELEROMETER:
-        case SensorType::MAGNETIC_FIELD:
-        case SensorType::ORIENTATION:
-        case SensorType::GYROSCOPE:
-        case SensorType::GRAVITY:
-        case SensorType::LINEAR_ACCELERATION: {
-            Event::EventPayload::Vec3 vec3;
-            vec3.x = src.acceleration.x;
-            vec3.y = src.acceleration.y;
-            vec3.z = src.acceleration.z;
-            vec3.status = (SensorStatus)src.acceleration.status;
-            dst->payload.set<Event::EventPayload::Tag::vec3>(vec3);
-            break;
-        }
-
-        case SensorType::GAME_ROTATION_VECTOR: {
-            Event::EventPayload::Vec4 vec4;
-            vec4.x = src.data[0];
-            vec4.y = src.data[1];
-            vec4.z = src.data[2];
-            vec4.w = src.data[3];
-            dst->payload.set<Event::EventPayload::Tag::vec4>(vec4);
-            break;
-        }
-
-        case SensorType::ROTATION_VECTOR:
-        case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
-            Event::EventPayload::Data data;
-            memcpy(data.values.data(), src.data, 5 * sizeof(float));
-            dst->payload.set<Event::EventPayload::Tag::data>(data);
-            break;
-        }
-
-        case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
-        case SensorType::GYROSCOPE_UNCALIBRATED:
-        case SensorType::ACCELEROMETER_UNCALIBRATED: {
-            Event::EventPayload::Uncal uncal;
-            uncal.x = src.uncalibrated_gyro.x_uncalib;
-            uncal.y = src.uncalibrated_gyro.y_uncalib;
-            uncal.z = src.uncalibrated_gyro.z_uncalib;
-            uncal.xBias = src.uncalibrated_gyro.x_bias;
-            uncal.yBias = src.uncalibrated_gyro.y_bias;
-            uncal.zBias = src.uncalibrated_gyro.z_bias;
-            dst->payload.set<Event::EventPayload::Tag::uncal>(uncal);
-            break;
-        }
-
-        case SensorType::DEVICE_ORIENTATION:
-        case SensorType::LIGHT:
-        case SensorType::PRESSURE:
-        case SensorType::PROXIMITY:
-        case SensorType::RELATIVE_HUMIDITY:
-        case SensorType::AMBIENT_TEMPERATURE:
-        case SensorType::SIGNIFICANT_MOTION:
-        case SensorType::STEP_DETECTOR:
-        case SensorType::TILT_DETECTOR:
-        case SensorType::WAKE_GESTURE:
-        case SensorType::GLANCE_GESTURE:
-        case SensorType::PICK_UP_GESTURE:
-        case SensorType::WRIST_TILT_GESTURE:
-        case SensorType::STATIONARY_DETECT:
-        case SensorType::MOTION_DETECT:
-        case SensorType::HEART_BEAT:
-        case SensorType::LOW_LATENCY_OFFBODY_DETECT:
-        case SensorType::HINGE_ANGLE: {
-            dst->payload.set<Event::EventPayload::Tag::scalar>((float)src.data[0]);
-            break;
-        }
-
-        case SensorType::STEP_COUNTER: {
-            dst->payload.set<Event::EventPayload::Tag::stepCount>(src.u64.step_counter);
-            break;
-        }
-
-        case SensorType::HEART_RATE: {
-            Event::EventPayload::HeartRate heartRate;
-            heartRate.bpm = src.heart_rate.bpm;
-            heartRate.status = (SensorStatus)src.heart_rate.status;
-            dst->payload.set<Event::EventPayload::Tag::heartRate>(heartRate);
-            break;
-        }
-
-        case SensorType::POSE_6DOF: { // 15 floats
-            Event::EventPayload::Pose6Dof pose6DOF;
-            for (size_t i = 0; i < 15; ++i) {
-                pose6DOF.values[i] = src.data[i];
-            }
-            dst->payload.set<Event::EventPayload::Tag::pose6DOF>(pose6DOF);
-            break;
-        }
-
-        case SensorType::DYNAMIC_SENSOR_META: {
-            DynamicSensorInfo dynamic;
-            dynamic.connected = src.dynamic_sensor_meta.connected;
-            dynamic.sensorHandle = src.dynamic_sensor_meta.handle;
-
-            memcpy(dynamic.uuid.values.data(), src.dynamic_sensor_meta.uuid, 16);
-            dst->payload.set<Event::EventPayload::Tag::dynamic>(dynamic);
-            break;
-        }
-
-        case SensorType::ADDITIONAL_INFO: {
-            AdditionalInfo info;
-            const additional_info_event_t &srcInfo = src.additional_info;
-            info.type = (AdditionalInfo::AdditionalInfoType)srcInfo.type;
-            info.serial = srcInfo.serial;
-
-            AdditionalInfo::AdditionalInfoPayload::Int32Values data;
-            CHECK_EQ(data.values.size() * sizeof(int32_t), sizeof(srcInfo.data_int32));
-            memcpy(data.values.data(), srcInfo.data_int32, sizeof(srcInfo.data_int32));
-            info.payload.set<AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32>(data);
-
-            dst->payload.set<Event::EventPayload::Tag::additional>(info);
-            break;
-        }
-
-        case SensorType::HEAD_TRACKER: {
-            Event::EventPayload::HeadTracker headTracker;
-            headTracker.rx = src.head_tracker.rx;
-            headTracker.ry = src.head_tracker.ry;
-            headTracker.rz = src.head_tracker.rz;
-            headTracker.vx = src.head_tracker.vx;
-            headTracker.vy = src.head_tracker.vy;
-            headTracker.vz = src.head_tracker.vz;
-            headTracker.discontinuityCount = src.head_tracker.discontinuity_count;
-
-            dst->payload.set<Event::EventPayload::Tag::headTracker>(headTracker);
-            break;
-        }
-
-        case SensorType::ACCELEROMETER_LIMITED_AXES:
-        case SensorType::GYROSCOPE_LIMITED_AXES: {
-            Event::EventPayload::LimitedAxesImu limitedAxesImu;
-            limitedAxesImu.x = src.limited_axes_imu.x;
-            limitedAxesImu.y = src.limited_axes_imu.y;
-            limitedAxesImu.z = src.limited_axes_imu.z;
-            limitedAxesImu.xSupported = src.limited_axes_imu.x_supported;
-            limitedAxesImu.ySupported = src.limited_axes_imu.y_supported;
-            limitedAxesImu.zSupported = src.limited_axes_imu.z_supported;
-            dst->payload.set<Event::EventPayload::Tag::limitedAxesImu>(limitedAxesImu);
-            break;
-        }
-
-        case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
-        case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED: {
-            Event::EventPayload::LimitedAxesImuUncal limitedAxesImuUncal;
-            limitedAxesImuUncal.x = src.limited_axes_imu_uncalibrated.x_uncalib;
-            limitedAxesImuUncal.y = src.limited_axes_imu_uncalibrated.y_uncalib;
-            limitedAxesImuUncal.z = src.limited_axes_imu_uncalibrated.z_uncalib;
-            limitedAxesImuUncal.xBias = src.limited_axes_imu_uncalibrated.x_bias;
-            limitedAxesImuUncal.yBias = src.limited_axes_imu_uncalibrated.y_bias;
-            limitedAxesImuUncal.zBias = src.limited_axes_imu_uncalibrated.z_bias;
-            limitedAxesImuUncal.xSupported = src.limited_axes_imu_uncalibrated.x_supported;
-            limitedAxesImuUncal.ySupported = src.limited_axes_imu_uncalibrated.y_supported;
-            limitedAxesImuUncal.zSupported = src.limited_axes_imu_uncalibrated.z_supported;
-            dst->payload.set<Event::EventPayload::Tag::limitedAxesImuUncal>(limitedAxesImuUncal);
-            break;
-        }
-
-        case SensorType::HEADING: {
-            Event::EventPayload::Heading heading;
-            heading.heading = src.heading.heading;
-            heading.accuracy = src.heading.accuracy;
-            dst->payload.set<Event::EventPayload::heading>(heading);
-            break;
-        }
-
-        default: {
-            CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
-
-            Event::EventPayload::Data data;
-            memcpy(data.values.data(), src.data, 16 * sizeof(float));
-            dst->payload.set<Event::EventPayload::Tag::data>(data);
-            break;
-        }
-    }
-}
-
 void serviceDied(void *cookie) {
     ALOGW("Sensors HAL died, attempting to reconnect.");
     ((AidlSensorHalWrapper *)cookie)->prepareForReconnect();
@@ -726,7 +274,7 @@
             .type = type,
             .format = format,
             .size = static_cast<int32_t>(memory->size),
-            .memoryHandle = makeToAidl(memory->handle),
+            .memoryHandle = dupToAidl(memory->handle),
     };
 
     return convertToStatus(mSensors->registerDirectChannel(mem, channelHandle));
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 3c4f8d9..a2042d6 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -75,6 +75,7 @@
     static_libs: [
         "libaidlcommonsupport",
         "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors-V1-convert",
         "android.hardware.sensors-V1-ndk",
     ],
 
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 948692b..e0a4f03 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1328,6 +1328,7 @@
             mSensors.getUserDebugSensors() : mSensors.getUserSensors();
     Vector<Sensor> accessibleSensorList;
 
+    resetTargetSdkVersionCache(opPackageName);
     bool isCapped = isRateCappedBasedOnPermission(opPackageName);
     for (size_t i = 0; i < initialSensorList.size(); i++) {
         Sensor sensor = initialSensorList[i];
@@ -1367,6 +1368,7 @@
     if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) {
         return nullptr;
     }
+    resetTargetSdkVersionCache(opPackageName);
 
     Mutex::Autolock _l(mLock);
     // To create a client in DATA_INJECTION mode to inject data, SensorService should already be
@@ -1402,6 +1404,7 @@
 sp<ISensorEventConnection> SensorService::createSensorDirectConnection(
         const String16& opPackageName, uint32_t size, int32_t type, int32_t format,
         const native_handle *resource) {
+    resetTargetSdkVersionCache(opPackageName);
     ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
 
     // No new direct connections are allowed when sensor privacy is enabled
@@ -1643,14 +1646,6 @@
         checkWakeLockStateLocked(&connLock);
     }
 
-    {
-        Mutex::Autolock packageLock(sPackageTargetVersionLock);
-        auto iter = sPackageTargetVersion.find(c->mOpPackageName);
-        if (iter != sPackageTargetVersion.end()) {
-            sPackageTargetVersion.erase(iter);
-        }
-    }
-
     SensorDevice& dev(SensorDevice::getInstance());
     dev.notifyConnectionDestroyed(c);
 }
@@ -2091,6 +2086,14 @@
     return targetSdkVersion;
 }
 
+void SensorService::resetTargetSdkVersionCache(const String16& opPackageName) {
+    Mutex::Autolock packageLock(sPackageTargetVersionLock);
+    auto iter = sPackageTargetVersion.find(opPackageName);
+    if (iter != sPackageTargetVersion.end()) {
+        sPackageTargetVersion.erase(iter);
+    }
+}
+
 void SensorService::checkWakeLockState() {
     ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
     checkWakeLockStateLocked(&connLock);
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 234dc9c..4ba3c51 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -377,6 +377,7 @@
             const String16& opPackageName);
     static bool hasPermissionForSensor(const Sensor& sensor);
     static int getTargetSdkVersion(const String16& opPackageName);
+    static void resetTargetSdkVersionCache(const String16& opPackageName);
     // SensorService acquires a partial wakelock for delivering events from wake up sensors. This
     // method checks whether all the events from these wake up sensors have been delivered to the
     // corresponding applications, if yes the wakelock is released.
diff --git a/services/sensorservice/aidl/Android.bp b/services/sensorservice/aidl/Android.bp
new file mode 100644
index 0000000..34d1de7
--- /dev/null
+++ b/services/sensorservice/aidl/Android.bp
@@ -0,0 +1,44 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library {
+    name: "libsensorserviceaidl",
+    srcs: [
+        "EventQueue.cpp",
+        "DirectReportChannel.cpp",
+        "SensorManager.cpp",
+        "utils.cpp",
+    ],
+    host_supported: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    header_libs: ["jni_headers"],
+    shared_libs: [
+        "libbase",
+        "libutils",
+        "libcutils",
+        "libbinder_ndk",
+        "libsensor",
+        "android.frameworks.sensorservice-V1-ndk",
+        "android.hardware.sensors-V1-ndk",
+    ],
+    export_include_dirs: [
+        "include/",
+    ],
+    static_libs: [
+        "android.hardware.sensors-V1-convert",
+    ],
+
+    export_header_lib_headers: ["jni_headers"],
+    local_include_dirs: [
+        "include/sensorserviceaidl/",
+    ],
+}
diff --git a/services/sensorservice/aidl/DirectReportChannel.cpp b/services/sensorservice/aidl/DirectReportChannel.cpp
new file mode 100644
index 0000000..cab53c1
--- /dev/null
+++ b/services/sensorservice/aidl/DirectReportChannel.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "DirectReportChannel.h"
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+DirectReportChannel::DirectReportChannel(::android::SensorManager& manager, int channelId)
+      : mManager(manager), mId(channelId) {}
+
+DirectReportChannel::~DirectReportChannel() {
+    mManager.destroyDirectChannel(mId);
+}
+
+ndk::ScopedAStatus DirectReportChannel::configure(
+        int32_t sensorHandle, ::aidl::android::hardware::sensors::ISensors::RateLevel rate,
+        int32_t* _aidl_return) {
+    int token = mManager.configureDirectChannel(mId, sensorHandle, static_cast<int>(rate));
+    if (token <= 0) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(token);
+    }
+    *_aidl_return = token;
+    return ndk::ScopedAStatus::ok();
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/DirectReportChannel.h b/services/sensorservice/aidl/DirectReportChannel.h
new file mode 100644
index 0000000..d9ea73d
--- /dev/null
+++ b/services/sensorservice/aidl/DirectReportChannel.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <aidl/android/frameworks/sensorservice/BnDirectReportChannel.h>
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <sensor/SensorManager.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+class DirectReportChannel final
+      : public ::aidl::android::frameworks::sensorservice::BnDirectReportChannel {
+public:
+    DirectReportChannel(::android::SensorManager& manager, int channelId);
+    ~DirectReportChannel();
+
+    ndk::ScopedAStatus configure(int32_t sensorHandle,
+                                 ::aidl::android::hardware::sensors::ISensors::RateLevel rate,
+                                 int32_t* _aidl_return) override;
+
+private:
+    ::android::SensorManager& mManager;
+    const int mId;
+};
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/EventQueue.cpp b/services/sensorservice/aidl/EventQueue.cpp
new file mode 100644
index 0000000..c394709
--- /dev/null
+++ b/services/sensorservice/aidl/EventQueue.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "EventQueue.h"
+#include "utils.h"
+
+#include <android-base/logging.h>
+#include <utils/Looper.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+using ::aidl::android::frameworks::sensorservice::IEventQueueCallback;
+using ::aidl::android::hardware::sensors::Event;
+
+class EventQueueLooperCallback : public ::android::LooperCallback {
+public:
+    EventQueueLooperCallback(sp<::android::SensorEventQueue> queue,
+                             std::shared_ptr<IEventQueueCallback> callback)
+          : mQueue(queue), mCallback(callback) {}
+
+    int handleEvent(int /* fd */, int /* events */, void* /* data */) {
+        ASensorEvent event;
+        ssize_t actual;
+
+        auto internalQueue = mQueue.promote();
+        if (internalQueue == nullptr) {
+            return 1;
+        }
+
+        while ((actual = internalQueue->read(&event, 1)) > 0) {
+            internalQueue->sendAck(&event, actual);
+            ndk::ScopedAStatus ret = mCallback->onEvent(convertEvent(event));
+            if (!ret.isOk()) {
+                LOG(ERROR) << "Failed to envoke EventQueueCallback: " << ret;
+            }
+        }
+
+        return 1; // continue to receive callbacks
+    }
+
+private:
+    wp<::android::SensorEventQueue> mQueue;
+    std::shared_ptr<IEventQueueCallback> mCallback;
+};
+
+EventQueue::EventQueue(std::shared_ptr<IEventQueueCallback> callback, sp<::android::Looper> looper,
+                       sp<::android::SensorEventQueue> internalQueue)
+      : mLooper(looper), mInternalQueue(internalQueue) {
+    mLooper->addFd(internalQueue->getFd(), ALOOPER_POLL_CALLBACK, ALOOPER_EVENT_INPUT,
+                   new EventQueueLooperCallback(internalQueue, callback), nullptr);
+}
+
+EventQueue::~EventQueue() {
+    mLooper->removeFd(mInternalQueue->getFd());
+}
+
+ndk::ScopedAStatus EventQueue::enableSensor(int32_t in_sensorHandle, int32_t in_samplingPeriodUs,
+                                            int64_t in_maxBatchReportLatencyUs) {
+    return convertResult(mInternalQueue->enableSensor(in_sensorHandle, in_samplingPeriodUs,
+                                                      in_maxBatchReportLatencyUs, 0));
+}
+
+ndk::ScopedAStatus EventQueue::disableSensor(int32_t in_sensorHandle) {
+    return convertResult(mInternalQueue->disableSensor(in_sensorHandle));
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/EventQueue.h b/services/sensorservice/aidl/EventQueue.h
new file mode 100644
index 0000000..0ae1eba
--- /dev/null
+++ b/services/sensorservice/aidl/EventQueue.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "SensorManagerAidl.h"
+
+#include <aidl/android/frameworks/sensorservice/BnEventQueue.h>
+#include <sensor/SensorManager.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+struct EventQueue final : public aidl::android::frameworks::sensorservice::BnEventQueue {
+    EventQueue(
+            std::shared_ptr<aidl::android::frameworks::sensorservice::IEventQueueCallback> callback,
+            sp<::android::Looper> looper, sp<::android::SensorEventQueue> internalQueue);
+    ~EventQueue();
+
+    ndk::ScopedAStatus enableSensor(int32_t in_sensorHandle, int32_t in_samplingPeriodUs,
+                                    int64_t in_maxBatchReportLatencyUs) override;
+    ndk::ScopedAStatus disableSensor(int32_t sensorHandle) override;
+
+private:
+    friend class EventQueueLooperCallback;
+    sp<::android::Looper> mLooper;
+    sp<::android::SensorEventQueue> mInternalQueue;
+};
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/SensorManager.cpp b/services/sensorservice/aidl/SensorManager.cpp
new file mode 100644
index 0000000..9b03344
--- /dev/null
+++ b/services/sensorservice/aidl/SensorManager.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// LOG_TAG defined via build flag.
+#ifndef LOG_TAG
+#define LOG_TAG "AidlSensorManager"
+#endif
+
+#include "DirectReportChannel.h"
+#include "EventQueue.h"
+#include "SensorManagerAidl.h"
+#include "utils.h"
+
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <android-base/logging.h>
+#include <android/binder_ibinder.h>
+#include <sched.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+using ::aidl::android::frameworks::sensorservice::IDirectReportChannel;
+using ::aidl::android::frameworks::sensorservice::IEventQueue;
+using ::aidl::android::frameworks::sensorservice::IEventQueueCallback;
+using ::aidl::android::frameworks::sensorservice::ISensorManager;
+using ::aidl::android::hardware::common::Ashmem;
+using ::aidl::android::hardware::sensors::ISensors;
+using ::aidl::android::hardware::sensors::SensorInfo;
+using ::aidl::android::hardware::sensors::SensorType;
+using ::android::frameworks::sensorservice::implementation::SensorManagerAidl;
+
+static const char* POLL_THREAD_NAME = "aidl_ssvc_poll";
+
+SensorManagerAidl::SensorManagerAidl(JavaVM* vm)
+      : mLooper(new Looper(false)), mStopThread(true), mJavaVm(vm) {}
+SensorManagerAidl::~SensorManagerAidl() {
+    // Stops pollAll inside the thread.
+    std::lock_guard<std::mutex> lock(mThreadMutex);
+
+    mStopThread = true;
+    if (mLooper != nullptr) {
+        mLooper->wake();
+    }
+    if (mPollThread.joinable()) {
+        mPollThread.join();
+    }
+}
+
+ndk::ScopedAStatus createDirectChannel(::android::SensorManager& manager, size_t size, int type,
+                                       const native_handle_t* handle,
+                                       std::shared_ptr<IDirectReportChannel>* chan) {
+    int channelId = manager.createDirectChannel(size, type, handle);
+    if (channelId < 0) {
+        return convertResult(channelId);
+    }
+    if (channelId == 0) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+    }
+    *chan = ndk::SharedRefBase::make<DirectReportChannel>(manager, channelId);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SensorManagerAidl::createAshmemDirectChannel(
+        const Ashmem& in_mem, int64_t in_size,
+        std::shared_ptr<IDirectReportChannel>* _aidl_return) {
+    if (in_size > in_mem.size || in_size < ISensors::DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_BAD_VALUE);
+    }
+    native_handle_t* handle = native_handle_create(1, 0);
+    handle->data[0] = dup(in_mem.fd.get());
+
+    auto status = createDirectChannel(getInternalManager(), in_size, SENSOR_DIRECT_MEM_TYPE_ASHMEM,
+                                      handle, _aidl_return);
+    int result = native_handle_close(handle);
+    CHECK(result == 0) << "Failed to close the native_handle_t: " << result;
+    result = native_handle_delete(handle);
+    CHECK(result == 0) << "Failed to delete the native_handle_t: " << result;
+
+    return status;
+}
+
+ndk::ScopedAStatus SensorManagerAidl::createGrallocDirectChannel(
+        const ndk::ScopedFileDescriptor& in_mem, int64_t in_size,
+        std::shared_ptr<IDirectReportChannel>* _aidl_return) {
+    native_handle_t* handle = native_handle_create(1, 0);
+    handle->data[0] = dup(in_mem.get());
+
+    auto status = createDirectChannel(getInternalManager(), in_size, SENSOR_DIRECT_MEM_TYPE_GRALLOC,
+                                      handle, _aidl_return);
+    int result = native_handle_close(handle);
+    CHECK(result == 0) << "Failed to close the native_handle_t: " << result;
+    result = native_handle_delete(handle);
+    CHECK(result == 0) << "Failed to delete the native_handle_t: " << result;
+
+    return status;
+}
+
+ndk::ScopedAStatus SensorManagerAidl::createEventQueue(
+        const std::shared_ptr<IEventQueueCallback>& in_callback,
+        std::shared_ptr<IEventQueue>* _aidl_return) {
+    if (in_callback == nullptr) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_BAD_VALUE);
+    }
+
+    sp<::android::Looper> looper = getLooper();
+    if (looper == nullptr) {
+        LOG(ERROR) << "::android::SensorManagerAidl::createEventQueue cannot initialize looper";
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+    }
+
+    String8 package(String8::format("aidl_client_pid_%d", AIBinder_getCallingPid()));
+    sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue(package);
+    if (internalQueue == nullptr) {
+        LOG(ERROR) << "::android::SensorManagerAidl::createEventQueue returns nullptr.";
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+    }
+
+    *_aidl_return = ndk::SharedRefBase::make<EventQueue>(in_callback, looper, internalQueue);
+
+    return ndk::ScopedAStatus::ok();
+}
+
+SensorInfo convertSensor(Sensor src) {
+    SensorInfo dst;
+    dst.sensorHandle = src.getHandle();
+    dst.name = src.getName();
+    dst.vendor = src.getVendor();
+    dst.version = src.getVersion();
+    dst.type = static_cast<SensorType>(src.getType());
+    dst.typeAsString = src.getStringType();
+    // maxRange uses maxValue because ::android::Sensor wraps the
+    // internal sensor_t in this way.
+    dst.maxRange = src.getMaxValue();
+    dst.resolution = src.getResolution();
+    dst.power = src.getPowerUsage();
+    dst.minDelayUs = src.getMinDelay();
+    dst.fifoReservedEventCount = src.getFifoReservedEventCount();
+    dst.fifoMaxEventCount = src.getFifoMaxEventCount();
+    dst.requiredPermission = src.getRequiredPermission();
+    dst.maxDelayUs = src.getMaxDelay();
+    dst.flags = src.getFlags();
+    return dst;
+}
+
+ndk::ScopedAStatus SensorManagerAidl::getDefaultSensor(SensorType in_type,
+                                                       SensorInfo* _aidl_return) {
+    ::android::Sensor const* sensor =
+            getInternalManager().getDefaultSensor(static_cast<int>(in_type));
+    if (!sensor) {
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_NOT_EXIST);
+    }
+    *_aidl_return = convertSensor(*sensor);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SensorManagerAidl::getSensorList(std::vector<SensorInfo>* _aidl_return) {
+    Sensor const* const* list;
+    _aidl_return->clear();
+    ssize_t count = getInternalManager().getSensorList(&list);
+    if (count < 0 || list == nullptr) {
+        LOG(ERROR) << "SensorMAanger::getSensorList failed with count: " << count;
+        return ndk::ScopedAStatus::fromServiceSpecificError(ISensorManager::RESULT_UNKNOWN_ERROR);
+    }
+    _aidl_return->reserve(static_cast<size_t>(count));
+    for (ssize_t i = 0; i < count; ++i) {
+        _aidl_return->push_back(convertSensor(*list[i]));
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+::android::SensorManager& SensorManagerAidl::getInternalManager() {
+    std::lock_guard<std::mutex> lock(mInternalManagerMutex);
+    if (mInternalManager == nullptr) {
+        mInternalManager = &::android::SensorManager::getInstanceForPackage(
+                String16(ISensorManager::descriptor));
+    }
+    return *mInternalManager;
+}
+
+/* One global looper for all event queues created from this SensorManager. */
+sp<Looper> SensorManagerAidl::getLooper() {
+    std::lock_guard<std::mutex> lock(mThreadMutex);
+
+    if (!mPollThread.joinable()) {
+        // if thread not initialized, start thread
+        mStopThread = false;
+        std::thread pollThread{[&stopThread = mStopThread, looper = mLooper, javaVm = mJavaVm] {
+            struct sched_param p = {};
+            p.sched_priority = 10;
+            if (sched_setscheduler(0 /* current thread*/, SCHED_FIFO, &p) != 0) {
+                LOG(ERROR) << "Could not use SCHED_FIFO for looper thread: " << strerror(errno);
+            }
+
+            // set looper
+            Looper::setForThread(looper);
+
+            // Attach the thread to JavaVM so that pollAll do not crash if the thread
+            // eventually calls into Java.
+            JavaVMAttachArgs args{.version = JNI_VERSION_1_2,
+                                  .name = POLL_THREAD_NAME,
+                                  .group = nullptr};
+            JNIEnv* env;
+            if (javaVm->AttachCurrentThread(&env, &args) != JNI_OK) {
+                LOG(FATAL) << "Cannot attach SensorManager looper thread to Java VM.";
+            }
+
+            LOG(INFO) << POLL_THREAD_NAME << " started.";
+            for (;;) {
+                int pollResult = looper->pollAll(-1 /* timeout */);
+                if (pollResult == Looper::POLL_WAKE) {
+                    if (stopThread == true) {
+                        LOG(INFO) << POLL_THREAD_NAME << ": requested to stop";
+                        break;
+                    } else {
+                        LOG(INFO) << POLL_THREAD_NAME << ": spurious wake up, back to work";
+                    }
+                } else {
+                    LOG(ERROR) << POLL_THREAD_NAME << ": Looper::pollAll returns unexpected "
+                               << pollResult;
+                    break;
+                }
+            }
+
+            if (javaVm->DetachCurrentThread() != JNI_OK) {
+                LOG(ERROR) << "Cannot detach SensorManager looper thread from Java VM.";
+            }
+
+            LOG(INFO) << POLL_THREAD_NAME << " is terminated.";
+        }};
+        mPollThread = std::move(pollThread);
+    }
+    return mLooper;
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/fuzzer/Android.bp b/services/sensorservice/aidl/fuzzer/Android.bp
new file mode 100644
index 0000000..0d6e476
--- /dev/null
+++ b/services/sensorservice/aidl/fuzzer/Android.bp
@@ -0,0 +1,52 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_fuzz {
+    name: "libsensorserviceaidl_fuzzer",
+    defaults: [
+        "service_fuzzer_defaults",
+    ],
+    host_supported: true,
+    static_libs: [
+        "libsensorserviceaidl",
+        "libpermission",
+        "android.frameworks.sensorservice-V1-ndk",
+        "android.hardware.sensors-V1-convert",
+        "android.hardware.sensors-V1-ndk",
+        "android.hardware.common-V2-ndk",
+        "libsensor",
+        "libfakeservicemanager",
+        "libcutils",
+        "liblog",
+    ],
+    srcs: [
+        "fuzzer.cpp",
+    ],
+    fuzz_config: {
+        cc: [
+            "android-sensors@google.com",
+            "devinmoore@google.com",
+        ],
+    },
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        diag: {
+            misc_undefined: [
+                "signed-integer-overflow",
+                "unsigned-integer-overflow",
+            ],
+        },
+        address: true,
+        integer_overflow: true,
+    },
+
+}
diff --git a/services/sensorservice/aidl/fuzzer/fuzzer.cpp b/services/sensorservice/aidl/fuzzer/fuzzer.cpp
new file mode 100644
index 0000000..1b63d76
--- /dev/null
+++ b/services/sensorservice/aidl/fuzzer/fuzzer.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <ServiceManager.h>
+#include <android-base/logging.h>
+#include <android/binder_interface_utils.h>
+#include <fuzzbinder/random_binder.h>
+#include <sensorserviceaidl/SensorManagerAidl.h>
+
+using android::fuzzService;
+using android::frameworks::sensorservice::implementation::SensorManagerAidl;
+using ndk::SharedRefBase;
+
+[[clang::no_destroy]] static std::once_flag gSmOnce;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    static android::sp<android::ServiceManager> fakeServiceManager = new android::ServiceManager();
+    std::call_once(gSmOnce, [&] { setDefaultServiceManager(fakeServiceManager); });
+    fakeServiceManager->clear();
+
+    FuzzedDataProvider fdp(data, size);
+    android::sp<android::IBinder> binder = android::getRandomBinder(&fdp);
+    if (binder == nullptr) {
+        // Nothing to do if we get a null binder. It will cause SensorManager to
+        // hang while trying to get sensorservice.
+        return 0;
+    }
+
+    CHECK(android::NO_ERROR == fakeServiceManager->addService(android::String16("sensorservice"),
+                                   binder));
+
+    std::shared_ptr<SensorManagerAidl> sensorService =
+            ndk::SharedRefBase::make<SensorManagerAidl>(nullptr);
+
+    fuzzService(sensorService->asBinder().get(), std::move(fdp));
+
+    return 0;
+}
diff --git a/services/sensorservice/aidl/include/sensorserviceaidl/SensorManagerAidl.h b/services/sensorservice/aidl/include/sensorserviceaidl/SensorManagerAidl.h
new file mode 100644
index 0000000..c77ee88
--- /dev/null
+++ b/services/sensorservice/aidl/include/sensorserviceaidl/SensorManagerAidl.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/frameworks/sensorservice/BnSensorManager.h>
+#include <jni.h>
+#include <sensor/SensorManager.h>
+#include <utils/Looper.h>
+#include <mutex>
+#include <thread>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+class SensorManagerAidl : public ::aidl::android::frameworks::sensorservice::BnSensorManager {
+public:
+    explicit SensorManagerAidl(JavaVM* vm);
+    ~SensorManagerAidl();
+
+    ::ndk::ScopedAStatus createAshmemDirectChannel(
+            const ::aidl::android::hardware::common::Ashmem& in_mem, int64_t in_size,
+            std::shared_ptr<::aidl::android::frameworks::sensorservice::IDirectReportChannel>*
+                    _aidl_return) override;
+    ::ndk::ScopedAStatus createEventQueue(
+            const std::shared_ptr<::aidl::android::frameworks::sensorservice::IEventQueueCallback>&
+                    in_callback,
+            std::shared_ptr<::aidl::android::frameworks::sensorservice::IEventQueue>* _aidl_return)
+            override;
+    ::ndk::ScopedAStatus createGrallocDirectChannel(
+            const ::ndk::ScopedFileDescriptor& in_buffer, int64_t in_size,
+            std::shared_ptr<::aidl::android::frameworks::sensorservice::IDirectReportChannel>*
+                    _aidl_return) override;
+    ::ndk::ScopedAStatus getDefaultSensor(
+            ::aidl::android::hardware::sensors::SensorType in_type,
+            ::aidl::android::hardware::sensors::SensorInfo* _aidl_return) override;
+    ::ndk::ScopedAStatus getSensorList(
+            std::vector<::aidl::android::hardware::sensors::SensorInfo>* _aidl_return) override;
+
+private:
+    // Block until ::android::SensorManager is initialized.
+    ::android::SensorManager& getInternalManager();
+    sp<Looper> getLooper();
+
+    std::mutex mInternalManagerMutex;
+    ::android::SensorManager* mInternalManager = nullptr; // does not own
+    sp<Looper> mLooper;
+
+    volatile bool mStopThread;
+    std::mutex mThreadMutex; // protects mPollThread
+    std::thread mPollThread;
+
+    JavaVM* mJavaVm;
+};
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/utils.cpp b/services/sensorservice/aidl/utils.cpp
new file mode 100644
index 0000000..beb38b9
--- /dev/null
+++ b/services/sensorservice/aidl/utils.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "utils.h"
+
+#include <aidl/android/frameworks/sensorservice/ISensorManager.h>
+#include <aidl/sensors/convert.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+ndk::ScopedAStatus convertResult(status_t src) {
+    using ::aidl::android::frameworks::sensorservice::ISensorManager;
+
+    int err = 0;
+    switch (src) {
+        case OK:
+            return ndk::ScopedAStatus::ok();
+        case NAME_NOT_FOUND:
+            err = ISensorManager::RESULT_NOT_EXIST;
+            break;
+        case NO_MEMORY:
+            err = ISensorManager::RESULT_NO_MEMORY;
+            break;
+        case NO_INIT:
+            err = ISensorManager::RESULT_NO_INIT;
+            break;
+        case PERMISSION_DENIED:
+            err = ISensorManager::RESULT_PERMISSION_DENIED;
+            break;
+        case BAD_VALUE:
+            err = ISensorManager::RESULT_BAD_VALUE;
+            break;
+        case INVALID_OPERATION:
+            err = ISensorManager::RESULT_INVALID_OPERATION;
+            break;
+        default:
+            err = ISensorManager::RESULT_UNKNOWN_ERROR;
+    }
+    return ndk::ScopedAStatus::fromServiceSpecificError(err);
+}
+
+::aidl::android::hardware::sensors::Event convertEvent(const ::ASensorEvent& src) {
+    ::aidl::android::hardware::sensors::Event dst;
+    ::android::hardware::sensors::implementation::
+            convertFromASensorEvent(src, &dst);
+    return dst;
+}
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/aidl/utils.h b/services/sensorservice/aidl/utils.h
new file mode 100644
index 0000000..06ba59e
--- /dev/null
+++ b/services/sensorservice/aidl/utils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <aidl/android/hardware/sensors/Event.h>
+#include <sensor/Sensor.h>
+
+namespace android {
+namespace frameworks {
+namespace sensorservice {
+namespace implementation {
+
+::ndk::ScopedAStatus convertResult(status_t status);
+::aidl::android::hardware::sensors::Event convertEvent(const ::ASensorEvent& event);
+
+} // namespace implementation
+} // namespace sensorservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/sensorservice/hidl/utils.cpp b/services/sensorservice/hidl/utils.cpp
index 2f9e922..5fa594d 100644
--- a/services/sensorservice/hidl/utils.cpp
+++ b/services/sensorservice/hidl/utils.cpp
@@ -76,8 +76,8 @@
 
 ::android::hardware::sensors::V1_0::Event convertEvent(const ::ASensorEvent& src) {
     ::android::hardware::sensors::V1_0::Event dst;
-    ::android::hardware::sensors::V1_0::implementation::convertFromSensorEvent(
-            reinterpret_cast<const sensors_event_t&>(src), &dst);
+    ::android::hardware::sensors::V1_0::implementation::convertFromASensorEvent(
+            src, &dst);
     return dst;
 }
 
diff --git a/services/stats/Android.bp b/services/stats/Android.bp
index 7fea616..7d358e1 100644
--- a/services/stats/Android.bp
+++ b/services/stats/Android.bp
@@ -13,10 +13,13 @@
         "StatsAidl.cpp",
         "StatsHal.cpp",
     ],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     shared_libs: [
         "android.frameworks.stats@1.0",
-        "android.frameworks.stats-V1-ndk",
+        "android.frameworks.stats-V2-ndk",
         "libbinder_ndk",
         "libhidlbase",
         "liblog",
@@ -29,10 +32,12 @@
     ],
     export_shared_lib_headers: [
         "android.frameworks.stats@1.0",
-        "android.frameworks.stats-V1-ndk",
+        "android.frameworks.stats-V2-ndk",
     ],
     local_include_dirs: [
         "include/stats",
     ],
-    vintf_fragments: ["android.frameworks.stats@1.0-service.xml"]
+    vintf_fragments: [
+        "android.frameworks.stats-service.xml",
+    ],
 }
diff --git a/services/stats/StatsAidl.cpp b/services/stats/StatsAidl.cpp
index a3b68f1..410a5af 100644
--- a/services/stats/StatsAidl.cpp
+++ b/services/stats/StatsAidl.cpp
@@ -30,14 +30,14 @@
 StatsHal::StatsHal() {}
 
 ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) {
-    std::string reverseDomainName = (std::string) vendorAtom.reverseDomainName;
     if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
         ALOGE("Atom ID %ld is not a valid vendor atom ID", (long) vendorAtom.atomId);
         return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
             -1, "Not a valid vendor atom ID");
     }
-    if (reverseDomainName.length() > 50) {
-        ALOGE("Vendor atom reverse domain name %s is too long.", reverseDomainName.c_str());
+    if (vendorAtom.reverseDomainName.length() > 50) {
+        ALOGE("Vendor atom reverse domain name %s is too long.",
+            vendorAtom.reverseDomainName.c_str());
         return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
             -1, "Vendor atom reverse domain name is too long");
     }
@@ -62,6 +62,90 @@
                 AStatsEvent_writeString(event,
                     atomValue.get<VendorAtomValue::stringValue>().c_str());
                 break;
+            case VendorAtomValue::boolValue:
+                AStatsEvent_writeBool(event,
+                    atomValue.get<VendorAtomValue::boolValue>());
+                break;
+            case VendorAtomValue::repeatedIntValue: {
+                const std::optional<std::vector<int>>& repeatedIntValue =
+                        atomValue.get<VendorAtomValue::repeatedIntValue>();
+                if (!repeatedIntValue) {
+                    AStatsEvent_writeInt32Array(event, {}, 0);
+                    break;
+                }
+                AStatsEvent_writeInt32Array(event, repeatedIntValue->data(),
+                                            repeatedIntValue->size());
+                break;
+            }
+            case VendorAtomValue::repeatedLongValue: {
+                const std::optional<std::vector<int64_t>>& repeatedLongValue =
+                        atomValue.get<VendorAtomValue::repeatedLongValue>();
+                if (!repeatedLongValue) {
+                    AStatsEvent_writeInt64Array(event, {}, 0);
+                    break;
+                }
+                AStatsEvent_writeInt64Array(event, repeatedLongValue->data(),
+                                            repeatedLongValue->size());
+                break;
+            }
+            case VendorAtomValue::repeatedFloatValue: {
+                const std::optional<std::vector<float>>& repeatedFloatValue =
+                        atomValue.get<VendorAtomValue::repeatedFloatValue>();
+                if (!repeatedFloatValue) {
+                    AStatsEvent_writeFloatArray(event, {}, 0);
+                    break;
+                }
+                AStatsEvent_writeFloatArray(event, repeatedFloatValue->data(),
+                                            repeatedFloatValue->size());
+                break;
+            }
+            case VendorAtomValue::repeatedStringValue: {
+                const std::optional<std::vector<std::optional<std::string>>>& repeatedStringValue =
+                        atomValue.get<VendorAtomValue::repeatedStringValue>();
+                if (!repeatedStringValue) {
+                    AStatsEvent_writeStringArray(event, {}, 0);
+                    break;
+                }
+                const std::vector<std::optional<std::string>>& repeatedStringVector =
+                        *repeatedStringValue;
+                const char* cStringArray[repeatedStringVector.size()];
+
+                for (int i = 0; i < repeatedStringVector.size(); ++i) {
+                    cStringArray[i] = repeatedStringVector[i].has_value()
+                            ? repeatedStringVector[i]->c_str()
+                            : "";
+                }
+
+                AStatsEvent_writeStringArray(event, cStringArray, repeatedStringVector.size());
+                break;
+            }
+            case VendorAtomValue::repeatedBoolValue: {
+                const std::optional<std::vector<bool>>& repeatedBoolValue =
+                        atomValue.get<VendorAtomValue::repeatedBoolValue>();
+                if (!repeatedBoolValue) {
+                    AStatsEvent_writeBoolArray(event, {}, 0);
+                    break;
+                }
+                const std::vector<bool>& repeatedBoolVector = *repeatedBoolValue;
+                bool boolArray[repeatedBoolValue->size()];
+
+                for (int i = 0; i < repeatedBoolVector.size(); ++i) {
+                    boolArray[i] = repeatedBoolVector[i];
+                }
+
+                AStatsEvent_writeBoolArray(event, boolArray, repeatedBoolVector.size());
+                break;
+            }
+            case VendorAtomValue::byteArrayValue: {
+                const std::optional<std::vector<uint8_t>>& byteArrayValue =
+                        atomValue.get<VendorAtomValue::byteArrayValue>();
+                if (!byteArrayValue) {
+                    AStatsEvent_writeByteArray(event, {}, 0);
+                    break;
+                }
+                AStatsEvent_writeByteArray(event, byteArrayValue->data(), byteArrayValue->size());
+                break;
+            }
         }
     }
     AStatsEvent_build(event);
diff --git a/services/stats/StatsHal.cpp b/services/stats/StatsHal.cpp
index ae0a984..d27d989 100644
--- a/services/stats/StatsHal.cpp
+++ b/services/stats/StatsHal.cpp
@@ -112,13 +112,13 @@
 }
 
 hardware::Return<void> StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) {
-    std::string reverseDomainName = (std::string) vendorAtom.reverseDomainName;
     if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
         ALOGE("Atom ID %ld is not a valid vendor atom ID", (long) vendorAtom.atomId);
         return hardware::Void();
     }
-    if (reverseDomainName.length() > 50) {
-        ALOGE("Vendor atom reverse domain name %s is too long.", reverseDomainName.c_str());
+    if (vendorAtom.reverseDomainName.size() > 50) {
+        ALOGE("Vendor atom reverse domain name %s is too long.",
+              vendorAtom.reverseDomainName.c_str());
         return hardware::Void();
     }
     AStatsEvent* event = AStatsEvent_obtain();
diff --git a/services/stats/android.frameworks.stats@1.0-service.xml b/services/stats/android.frameworks.stats-service.xml
similarity index 93%
rename from services/stats/android.frameworks.stats@1.0-service.xml
rename to services/stats/android.frameworks.stats-service.xml
index c564b7b..7e2635e 100644
--- a/services/stats/android.frameworks.stats@1.0-service.xml
+++ b/services/stats/android.frameworks.stats-service.xml
@@ -11,7 +11,7 @@
 
     <hal format="aidl">
         <name>android.frameworks.stats</name>
-        <version>1</version>
+        <version>2</version>
         <fqname>IStats/default</fqname>
     </hal>
 </manifest>
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
index 16cb41b..5e84be1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
@@ -56,6 +56,9 @@
     // similar requests if needed.
     virtual void createClientCompositionCache(uint32_t cacheSize) = 0;
 
+    // Sends the brightness setting to HWC
+    virtual void applyDisplayBrightness(const bool applyImmediately) = 0;
+
 protected:
     ~Display() = default;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index db2fd1b..2203639 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -27,6 +27,7 @@
 #include <compositionengine/LayerFE.h>
 #include <renderengine/LayerSettings.h>
 #include <ui/Fence.h>
+#include <ui/FenceTime.h>
 #include <ui/GraphicTypes.h>
 #include <ui/LayerStack.h>
 #include <ui/Region.h>
@@ -311,6 +312,8 @@
             const Region& flashRegion,
             std::vector<LayerFE::LayerSettings>& clientCompositionLayers) = 0;
     virtual void setExpensiveRenderingExpected(bool enabled) = 0;
+    virtual void setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) = 0;
+    virtual bool isPowerHintSessionEnabled() = 0;
     virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0;
     virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 61a0e6a..33a10a3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -72,6 +72,7 @@
             const compositionengine::DisplayColorProfileCreationArgs&) override;
     void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override;
     void createClientCompositionCache(uint32_t cacheSize) override;
+    void applyDisplayBrightness(const bool applyImmediately) override;
 
     // Internal helpers used by chooseCompositionStrategy()
     using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes;
@@ -89,6 +90,8 @@
     std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(const sp<LayerFE>&) const;
 
 private:
+    bool isPowerHintSessionEnabled() override;
+    void setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) override;
     DisplayId mId;
     bool mIsDisconnected = false;
     Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 31c51e6..df721cd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -140,6 +140,8 @@
           std::vector<LayerFE*> &outLayerFEs) override;
     void appendRegionFlashRequests(const Region&, std::vector<LayerFE::LayerSettings>&) override;
     void setExpensiveRenderingExpected(bool enabled) override;
+    void setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) override;
+    bool isPowerHintSessionEnabled() override;
     void dumpBase(std::string&) const;
 
     // Implemented by the final implementation for the final state it uses.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 2bfd3cf..24a7744 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -115,7 +115,7 @@
 
     // Renders the cached set with the supplied output composition state.
     void render(renderengine::RenderEngine& re, TexturePool& texturePool,
-                const OutputCompositionState& outputState);
+                const OutputCompositionState& outputState, bool deviceHandlesColorTransform);
 
     void dump(std::string& result) const;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index 92cc484..f934cb2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -106,7 +106,8 @@
 
     // Renders the newest cached sets with the supplied output composition state
     void renderCachedSets(const OutputCompositionState& outputState,
-                          std::optional<std::chrono::steady_clock::time_point> renderDeadline);
+                          std::optional<std::chrono::steady_clock::time_point> renderDeadline,
+                          bool deviceHandlesColorTransform);
 
     void setTexturePoolEnabled(bool enabled) { mTexturePool.setEnabled(enabled); }
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
index b7ebca6..c968df7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
@@ -65,7 +65,8 @@
     // Rendering a pending cached set is optional: if the renderDeadline is not far enough in the
     // future then the planner may opt to skip rendering the cached set.
     void renderCachedSets(const OutputCompositionState& outputState,
-                          std::optional<std::chrono::steady_clock::time_point> renderDeadline);
+                          std::optional<std::chrono::steady_clock::time_point> renderDeadline,
+                          bool deviceHandlesColorTransform);
 
     void setTexturePoolEnabled(bool enabled) { mFlattener.setTexturePoolEnabled(enabled); }
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
index 72e6f3b..7e99ec2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -41,6 +41,7 @@
     MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&));
     MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&));
     MOCK_METHOD1(createClientCompositionCache, void(uint32_t));
+    MOCK_METHOD1(applyDisplayBrightness, void(const bool));
     MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
 };
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index cb9fbad..2a04949 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -133,6 +133,8 @@
     MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
     MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
     MOCK_METHOD1(setTreat170mAsSrgb, void(bool));
+    MOCK_METHOD(void, setHintSessionGpuFence, (std::unique_ptr<FenceTime> && gpuFence));
+    MOCK_METHOD(bool, isPowerHintSessionEnabled, ());
 };
 
 } // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index b79b46b..1ec6449 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -203,6 +203,24 @@
     setReleasedLayers(std::move(releasedLayers));
 }
 
+void Display::applyDisplayBrightness(const bool applyImmediately) {
+    auto& hwc = getCompositionEngine().getHwComposer();
+    const auto halDisplayId = HalDisplayId::tryCast(*getDisplayId());
+    if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
+        physicalDisplayId && getState().displayBrightness) {
+        const status_t result =
+                hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness,
+                                         getState().displayBrightnessNits,
+                                         Hwc2::Composer::DisplayBrightnessOptions{
+                                                 .applyImmediately = applyImmediately})
+                        .get();
+        ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
+                 getName().c_str(), result, strerror(-result));
+    }
+    // Clear out the display brightness now that it's been communicated to composer.
+    editState().displayBrightness.reset();
+}
+
 void Display::beginFrame() {
     Output::beginFrame();
 
@@ -212,20 +230,7 @@
         return;
     }
 
-    auto& hwc = getCompositionEngine().getHwComposer();
-    if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
-        physicalDisplayId && getState().displayBrightness) {
-        const status_t result =
-                hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness,
-                                         getState().displayBrightnessNits,
-                                         Hwc2::Composer::DisplayBrightnessOptions{
-                                                 .applyImmediately = false})
-                        .get();
-        ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
-                 getName().c_str(), result, strerror(-result));
-    }
-    // Clear out the display brightness now that it's been communicated to composer.
-    editState().displayBrightness.reset();
+    applyDisplayBrightness(false);
 }
 
 bool Display::chooseCompositionStrategy(
@@ -243,11 +248,14 @@
         return false;
     }
 
+    const nsecs_t startTime = systemTime();
+
     // Get any composition changes requested by the HWC device, and apply them.
     std::optional<android::HWComposer::DeviceRequestedChanges> changes;
     auto& hwc = getCompositionEngine().getHwComposer();
+    const bool requiresClientComposition = anyLayersRequireClientComposition();
     if (status_t result =
-                hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(),
+                hwc.getDeviceCompositionChanges(*halDisplayId, requiresClientComposition,
                                                 getState().earliestPresentTime,
                                                 getState().previousPresentFence,
                                                 getState().expectedPresentTime, outChanges);
@@ -257,6 +265,11 @@
         return false;
     }
 
+    if (isPowerHintSessionEnabled()) {
+        mPowerAdvisor->setHwcValidateTiming(mId, startTime, systemTime());
+        mPowerAdvisor->setRequiresClientComposition(mId, requiresClientComposition);
+    }
+
     return true;
 }
 
@@ -356,9 +369,24 @@
     }
 
     auto& hwc = getCompositionEngine().getHwComposer();
+
+    const nsecs_t startTime = systemTime();
+
+    if (isPowerHintSessionEnabled()) {
+        if (!getCompositionEngine().getHwComposer().getComposer()->isSupported(
+                    Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
+            getState().previousPresentFence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) {
+            mPowerAdvisor->setHwcPresentDelayedTime(mId, getState().earliestPresentTime);
+        }
+    }
+
     hwc.presentAndGetReleaseFences(*halDisplayIdOpt, getState().earliestPresentTime,
                                    getState().previousPresentFence);
 
+    if (isPowerHintSessionEnabled()) {
+        mPowerAdvisor->setHwcPresentTiming(mId, startTime, systemTime());
+    }
+
     fences.presentFence = hwc.getPresentFence(*halDisplayIdOpt);
 
     // TODO(b/121291683): Change HWComposer call to return entire map
@@ -384,6 +412,14 @@
     }
 }
 
+bool Display::isPowerHintSessionEnabled() {
+    return mPowerAdvisor != nullptr && mPowerAdvisor->usePowerHintSession();
+}
+
+void Display::setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) {
+    mPowerAdvisor->setGpuFenceTime(mId, std::move(gpuFence));
+}
+
 void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs,
                           GpuCompositionResult&& result) {
     // We only need to actually compose the display if:
@@ -396,6 +432,13 @@
     }
 
     impl::Output::finishFrame(refreshArgs, std::move(result));
+
+    if (isPowerHintSessionEnabled()) {
+        auto& hwc = getCompositionEngine().getHwComposer();
+        if (auto halDisplayId = HalDisplayId::tryCast(mId)) {
+            mPowerAdvisor->setSkippedValidate(mId, hwc.getValidateSkipped(*halDisplayId));
+        }
+    }
 }
 
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index c3385a8..b724daa 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -586,8 +586,29 @@
     // Remove the transparent area from the visible region
     if (!layerFEState->isOpaque) {
         if (tr.preserveRects()) {
-            // transform the transparent region
-            transparentRegion = tr.transform(layerFEState->transparentRegionHint);
+            // Clip the transparent region to geomLayerBounds first
+            // The transparent region may be influenced by applications, for
+            // instance, by overriding ViewGroup#gatherTransparentRegion with a
+            // custom view. Once the layer stack -> display mapping is known, we
+            // must guard against very wrong inputs to prevent underflow or
+            // overflow errors. We do this here by constraining the transparent
+            // region to be within the pre-transform layer bounds, since the
+            // layer bounds are expected to play nicely with the full
+            // transform.
+            const Region clippedTransparentRegionHint =
+                    layerFEState->transparentRegionHint.intersect(
+                            Rect(layerFEState->geomLayerBounds));
+
+            if (clippedTransparentRegionHint.isEmpty()) {
+                if (!layerFEState->transparentRegionHint.isEmpty()) {
+                    ALOGD("Layer: %s had an out of bounds transparent region",
+                          layerFE->getDebugName());
+                    layerFEState->transparentRegionHint.dump("transparentRegionHint");
+                }
+                transparentRegion.clear();
+            } else {
+                transparentRegion = tr.transform(clippedTransparentRegionHint);
+            }
         } else {
             // transformation too complex, can't do the
             // transparent region optimization.
@@ -1099,6 +1120,10 @@
         return;
     }
 
+    if (isPowerHintSessionEnabled()) {
+        // get fence end time to know when gpu is complete in display
+        setHintSessionGpuFence(std::make_unique<FenceTime>(new Fence(dup(optReadyFence->get()))));
+    }
     // swap buffers (presentation)
     mRenderSurface->queueBuffer(std::move(*optReadyFence));
 }
@@ -1218,7 +1243,8 @@
             ATRACE_NAME("ClientCompositionCacheHit");
             outputCompositionState.reusedClientComposition = true;
             setExpensiveRenderingExpected(false);
-            return base::unique_fd();
+            // b/239944175 pass the fence associated with the buffer.
+            return base::unique_fd(std::move(fd));
         }
         ATRACE_NAME("ClientCompositionCacheMiss");
         mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay,
@@ -1403,6 +1429,14 @@
     // The base class does nothing with this call.
 }
 
+void Output::setHintSessionGpuFence(std::unique_ptr<FenceTime>&&) {
+    // The base class does nothing with this call.
+}
+
+bool Output::isPowerHintSessionEnabled() {
+    return false;
+}
+
 void Output::postFramebuffer() {
     ATRACE_CALL();
     ALOGV(__FUNCTION__);
@@ -1460,7 +1494,8 @@
 
 void Output::renderCachedSets(const CompositionRefreshArgs& refreshArgs) {
     if (mPlanner) {
-        mPlanner->renderCachedSets(getState(), refreshArgs.scheduledFrameTime);
+        mPlanner->renderCachedSets(getState(), refreshArgs.scheduledFrameTime,
+                                   getState().usesDeviceComposition || getSkipColorTransform());
     }
 }
 
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 641b806..d6f02ee 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -159,7 +159,8 @@
 }
 
 void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& texturePool,
-                       const OutputCompositionState& outputState) {
+                       const OutputCompositionState& outputState,
+                       bool deviceHandlesColorTransform) {
     ATRACE_CALL();
     const Rect& viewport = outputState.layerStackSpace.getContent();
     const ui::Dataspace& outputDataspace = outputState.dataspace;
@@ -170,6 +171,8 @@
             .physicalDisplay = outputState.framebufferSpace.getContent(),
             .clip = viewport,
             .outputDataspace = outputDataspace,
+            .colorTransform = outputState.colorTransformMatrix,
+            .deviceHandlesColorTransform = deviceHandlesColorTransform,
             .orientation = orientation,
             .targetLuminanceNits = outputState.displayBrightnessNits,
     };
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 1062b70..9175dd0 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -99,7 +99,8 @@
 
 void Flattener::renderCachedSets(
         const OutputCompositionState& outputState,
-        std::optional<std::chrono::steady_clock::time_point> renderDeadline) {
+        std::optional<std::chrono::steady_clock::time_point> renderDeadline,
+        bool deviceHandlesColorTransform) {
     ATRACE_CALL();
 
     if (!mNewCachedSet) {
@@ -136,7 +137,7 @@
         }
     }
 
-    mNewCachedSet->render(mRenderEngine, mTexturePool, outputState);
+    mNewCachedSet->render(mRenderEngine, mTexturePool, outputState, deviceHandlesColorTransform);
 }
 
 void Flattener::dumpLayers(std::string& result) const {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index c8413eb..54133d9 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -201,11 +201,11 @@
                             finalPlan);
 }
 
-void Planner::renderCachedSets(
-        const OutputCompositionState& outputState,
-        std::optional<std::chrono::steady_clock::time_point> renderDeadline) {
+void Planner::renderCachedSets(const OutputCompositionState& outputState,
+                               std::optional<std::chrono::steady_clock::time_point> renderDeadline,
+                               bool deviceHandlesColorTransform) {
     ATRACE_CALL();
-    mFlattener.renderCachedSets(outputState, renderDeadline);
+    mFlattener.renderCachedSets(outputState, renderDeadline, deviceHandlesColorTransform);
 }
 
 void Planner::dump(const Vector<String16>& args, std::string& result) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 0e5a7b6..344fea3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -169,6 +169,7 @@
         EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
         EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
         EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
+        EXPECT_CALL(mPowerAdvisor, usePowerHintSession()).WillRepeatedly(Return(false));
     }
 
     DisplayCreationArgs getDisplayCreationArgsForPhysicalDisplay() {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 9b12b08..d7704a8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -137,6 +137,7 @@
     MOCK_METHOD(bool, hasDisplayIdleTimerCapability, (PhysicalDisplayId), (const, override));
     MOCK_METHOD(Hwc2::AidlTransform, getPhysicalDisplayOrientation, (PhysicalDisplayId),
                 (const, override));
+    MOCK_METHOD(bool, getValidateSkipped, (HalDisplayId), (const, override));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index 50adcfb..c8bd5e4 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -38,11 +38,33 @@
     MOCK_METHOD(bool, usePowerHintSession, (), (override));
     MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
     MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
-    MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override));
-    MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp),
-                (override));
+    MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDuration), (override));
+    MOCK_METHOD(void, sendActualWorkDuration, (), (override));
+    MOCK_METHOD(void, sendPredictedWorkDuration, (), (override));
     MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
     MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override));
+    MOCK_METHOD(void, setGpuFenceTime,
+                (DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override));
+    MOCK_METHOD(void, setHwcValidateTiming,
+                (DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime),
+                (override));
+    MOCK_METHOD(void, setHwcPresentTiming,
+                (DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime),
+                (override));
+    MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override));
+    MOCK_METHOD(void, setRequiresClientComposition,
+                (DisplayId displayId, bool requiresClientComposition), (override));
+    MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override));
+    MOCK_METHOD(void, setSfPresentTiming, (nsecs_t presentFenceTime, nsecs_t presentEndTime),
+                (override));
+    MOCK_METHOD(void, setHwcPresentDelayedTime,
+                (DisplayId displayId,
+                 std::chrono::steady_clock::time_point earliestFrameStartTime));
+    MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override));
+    MOCK_METHOD(void, setCommitStart, (nsecs_t commitStartTime), (override));
+    MOCK_METHOD(void, setCompositeEnd, (nsecs_t compositeEndtime), (override));
+    MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override));
+    MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (int64_t targetDuration), (override));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 063726b..cf12890 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -1505,6 +1505,8 @@
     static const Region kTransparentRegionHint;
     static const Region kTransparentRegionHintTwo;
     static const Region kTransparentRegionHintTwo90Rotation;
+    static const Region kTransparentRegionHintNegative;
+    static const Region kTransparentRegionHintNegativeIntersectsBounds;
 
     StrictMock<OutputPartialMock> mOutput;
     LayerFESet mGeomSnapshots;
@@ -1528,6 +1530,10 @@
         Region(Rect(25, 20, 50, 75));
 const Region OutputEnsureOutputLayerIfVisibleTest::kTransparentRegionHintTwo90Rotation =
         Region(Rect(125, 25, 180, 50));
+const Region OutputEnsureOutputLayerIfVisibleTest::kTransparentRegionHintNegative =
+        Region(Rect(INT32_MIN, INT32_MIN, INT32_MIN + 100, INT32_MIN + 200));
+const Region OutputEnsureOutputLayerIfVisibleTest::kTransparentRegionHintNegativeIntersectsBounds =
+        Region(Rect(INT32_MIN, INT32_MIN, 100, 100));
 
 TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerIncluded) {
     EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
@@ -1997,6 +2003,41 @@
                 RegionEq(kTransparentRegionHintTwo90Rotation));
 }
 
+TEST_F(OutputEnsureOutputLayerIfVisibleTest, transparentRegionExcludesOutputLayer) {
+    mLayer.layerFEState.isOpaque = false;
+    mLayer.layerFEState.contentDirty = true;
+    mLayer.layerFEState.geomLayerBounds = kFullBoundsNoRotation.bounds().toFloatRect();
+    mLayer.layerFEState.transparentRegionHint = kFullBoundsNoRotation;
+
+    EXPECT_CALL(mOutput, ensureOutputLayer(_, _)).Times(0);
+}
+
+TEST_F(OutputEnsureOutputLayerIfVisibleTest, transparentRegionIgnoredWhenOutsideBounds) {
+    mLayer.layerFEState.isOpaque = false;
+    mLayer.layerFEState.contentDirty = true;
+    mLayer.layerFEState.geomLayerBounds = kFullBoundsNoRotation.bounds().toFloatRect();
+    mLayer.layerFEState.transparentRegionHint = kTransparentRegionHintNegative;
+
+    EXPECT_CALL(mOutput, ensureOutputLayer(_, _)).Times(0);
+}
+
+TEST_F(OutputEnsureOutputLayerIfVisibleTest, transparentRegionClipsWhenOutsideBounds) {
+    mLayer.layerFEState.isOpaque = false;
+    mLayer.layerFEState.contentDirty = true;
+    mLayer.layerFEState.compositionType =
+            aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
+    mLayer.layerFEState.transparentRegionHint = kTransparentRegionHintNegativeIntersectsBounds;
+
+    EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
+    EXPECT_CALL(mOutput, ensureOutputLayer(Eq(std::nullopt), Eq(mLayer.layerFE)))
+            .WillOnce(Return(&mLayer.outputLayer));
+    ensureOutputLayerIfVisible();
+
+    // Check that the blocking region clips an out-of-bounds transparent region.
+    EXPECT_THAT(mLayer.outputLayerState.outputSpaceBlockingRegionHint,
+                RegionEq(kTransparentRegionHint));
+}
+
 /*
  * Output::present()
  */
@@ -3319,6 +3360,9 @@
         MOCK_METHOD2(appendRegionFlashRequests,
                      void(const Region&, std::vector<LayerFE::LayerSettings>&));
         MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
+        MOCK_METHOD(void, setHintSessionGpuFence, (std::unique_ptr<FenceTime> && gpuFence),
+                    (override));
+        MOCK_METHOD(bool, isPowerHintSessionEnabled, (), (override));
     };
 
     OutputComposeSurfacesTest() {
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 8a99e4e..0e9db36 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -376,7 +376,7 @@
             .WillOnce(Return(clientCompList2));
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
     mOutputState.isSecure = false;
-    cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+    cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
     expectReadyBuffer(cachedSet);
 
     EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
@@ -429,7 +429,7 @@
             .WillOnce(Return(clientCompList2));
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
     mOutputState.isSecure = true;
-    cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+    cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
     expectReadyBuffer(cachedSet);
 
     EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
@@ -477,7 +477,58 @@
             .WillOnce(Return(clientCompList2));
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
     mOutputState.isSecure = true;
-    cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+    cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
+    expectReadyBuffer(cachedSet);
+
+    EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
+    EXPECT_EQ(Rect(kOutputSize.width, kOutputSize.height), cachedSet.getTextureBounds());
+
+    // Now check that appending a new cached set properly cleans up RenderEngine resources.
+    CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+    cachedSet.append(CachedSet(layer3));
+}
+
+TEST_F(CachedSetTest, renderWhitePointNoColorTransform) {
+    // Skip the 0th layer to ensure that the bounding box of the layers is offset from (0, 0)
+    // This is a duplicate of the "renderWhitePoint" test, but setting "deviceHandlesColorTransform"
+    // to false, in the render call.
+
+    CachedSet::Layer& layer1 = *mTestLayers[1]->cachedSetLayer.get();
+    sp<mock::LayerFE> layerFE1 = mTestLayers[1]->layerFE;
+    CachedSet::Layer& layer2 = *mTestLayers[2]->cachedSetLayer.get();
+    sp<mock::LayerFE> layerFE2 = mTestLayers[2]->layerFE;
+
+    CachedSet cachedSet(layer1);
+    cachedSet.append(CachedSet(layer2));
+
+    std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1;
+    clientCompList1.push_back({});
+
+    std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2;
+    clientCompList2.push_back({});
+
+    mOutputState.displayBrightnessNits = 400.f;
+
+    const auto drawLayers =
+            [&](const renderengine::DisplaySettings& displaySettings,
+                const std::vector<renderengine::LayerSettings>&,
+                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+        EXPECT_EQ(mOutputState.displayBrightnessNits, displaySettings.targetLuminanceNits);
+        return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+    };
+
+    EXPECT_CALL(*layerFE1,
+                prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq(
+                        mOutputState.displayBrightnessNits)))
+            .WillOnce(Return(clientCompList1));
+    EXPECT_CALL(*layerFE2,
+                prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq(
+                        mOutputState.displayBrightnessNits)))
+            .WillOnce(Return(clientCompList2));
+    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
+    mOutputState.isSecure = true;
+    cachedSet.render(mRenderEngine, mTexturePool, mOutputState, false);
     expectReadyBuffer(cachedSet);
 
     EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
@@ -527,7 +578,7 @@
     EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
     EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
-    cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+    cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
     expectReadyBuffer(cachedSet);
 
     EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
@@ -767,7 +818,7 @@
     };
 
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
-    cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+    cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
 }
 
 TEST_F(CachedSetTest, addHolePunch_noBuffer) {
@@ -829,7 +880,7 @@
     };
 
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
-    cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+    cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
 }
 
 TEST_F(CachedSetTest, append_removesHolePunch) {
@@ -969,7 +1020,7 @@
     };
 
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
-    cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+    cachedSet.render(mRenderEngine, mTexturePool, mOutputState, true);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 50e3a28..96021ec 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -159,13 +159,13 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // same geometry, update the internal layer stack
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 }
 
 void FlattenerTest::expectAllLayersFlattened(const std::vector<const LayerState*>& layers) {
@@ -177,7 +177,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     for (const auto layer : layers) {
         EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -187,7 +187,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     const auto buffer = layers[0]->getOutputLayer()->getState().overrideInfo.buffer;
     EXPECT_NE(nullptr, buffer);
@@ -222,7 +222,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 }
 
 TEST_F(FlattenerTest, flattenLayers_ActiveLayersWithLowFpsAreFlattened) {
@@ -284,7 +284,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -389,7 +389,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_EQ(nullptr, overrideBuffer1);
     EXPECT_EQ(nullptr, overrideBuffer2);
@@ -428,7 +428,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_EQ(nullptr, overrideBuffer1);
     EXPECT_EQ(nullptr, overrideBuffer2);
@@ -437,7 +437,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_EQ(nullptr, overrideBuffer1);
     EXPECT_NE(nullptr, overrideBuffer2);
@@ -452,7 +452,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_EQ(nullptr, overrideBuffer1);
     EXPECT_NE(nullptr, overrideBuffer2);
@@ -461,7 +461,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -505,7 +505,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_EQ(nullptr, overrideBuffer1);
     EXPECT_EQ(nullptr, overrideBuffer2);
@@ -521,7 +521,7 @@
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
     mOutputState.framebufferSpace.setOrientation(ui::ROTATION_90);
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -534,7 +534,7 @@
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
     mOutputState.framebufferSpace.setOrientation(ui::ROTATION_180);
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -550,7 +550,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -562,7 +562,7 @@
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
     mOutputState.framebufferSpace.setOrientation(ui::ROTATION_270);
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -603,7 +603,7 @@
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
     EXPECT_EQ(nullptr, overrideBuffer1);
@@ -616,7 +616,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -669,7 +669,7 @@
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
     EXPECT_EQ(nullptr, overrideBuffer1);
@@ -682,7 +682,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -743,7 +743,7 @@
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
     EXPECT_EQ(nullptr, overrideBuffer0);
@@ -753,7 +753,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer0); // got overridden
     EXPECT_EQ(nullptr, overrideBuffer1); // did not
@@ -815,7 +815,7 @@
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
     EXPECT_EQ(nullptr, overrideBuffer0);
@@ -825,7 +825,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer0); // got overridden
     EXPECT_EQ(nullptr, overrideBuffer1); // did not
@@ -871,7 +871,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     for (const auto layer : layers) {
         EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -881,7 +881,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
     EXPECT_EQ(nullptr, overrideBuffer3);
@@ -917,7 +917,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     for (const auto layer : layers) {
         EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -928,7 +928,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
     for (const auto layer : layers) {
         EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
     }
@@ -971,7 +971,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     for (const auto layer : layers) {
         EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -981,7 +981,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
     EXPECT_EQ(nullptr, overrideBuffer1);
     EXPECT_EQ(nullptr, blurOverrideBuffer);
     EXPECT_NE(nullptr, overrideBuffer3);
@@ -1020,7 +1020,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     const auto& cachedSet = mFlattener->getNewCachedSetForTesting();
     ASSERT_NE(std::nullopt, cachedSet);
@@ -1034,7 +1034,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer2, overrideBuffer1);
     EXPECT_EQ(nullptr, blurOverrideBuffer);
@@ -1063,7 +1063,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_EQ(nullptr, overrideBuffer1);
     EXPECT_EQ(nullptr, overrideBuffer2);
@@ -1071,12 +1071,12 @@
     // Simulate attempting to render prior to merging the new cached set with the layer stack.
     // Here we should not try to re-render.
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We provide the override buffer now that it's rendered
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer2, overrideBuffer1);
@@ -1120,7 +1120,8 @@
         EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
         mFlattener->renderCachedSets(mOutputState,
                                      std::chrono::steady_clock::now() -
-                                             (kCachedSetRenderDuration + 10ms));
+                                             (kCachedSetRenderDuration + 10ms),
+                                     true);
     }
 
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
@@ -1128,7 +1129,8 @@
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
     mFlattener->renderCachedSets(mOutputState,
                                  std::chrono::steady_clock::now() -
-                                         (kCachedSetRenderDuration + 10ms));
+                                         (kCachedSetRenderDuration + 10ms),
+                                 true);
 }
 
 TEST_F(FlattenerTest, flattenLayers_skipsBT601_625) {
@@ -1162,7 +1164,7 @@
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
     EXPECT_EQ(nullptr, overrideBuffer1);
@@ -1175,7 +1177,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -1213,7 +1215,7 @@
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
     EXPECT_EQ(nullptr, overrideBuffer1);
@@ -1226,7 +1228,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -1264,7 +1266,7 @@
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
     EXPECT_EQ(nullptr, overrideBuffer1);
@@ -1277,7 +1279,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -1318,7 +1320,7 @@
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
     EXPECT_EQ(nullptr, overrideBuffer1);
@@ -1332,7 +1334,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_EQ(nullptr, overrideBuffer1);
     EXPECT_EQ(nullptr, overrideBuffer2);
@@ -1371,7 +1373,7 @@
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     // We've rendered a CachedSet, but we haven't merged it in.
     EXPECT_EQ(nullptr, overrideBuffer1);
@@ -1384,7 +1386,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+    mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a915b61..26fbd55 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -104,7 +104,7 @@
 
     mCompositionDisplay->getRenderSurface()->initialize();
 
-    setPowerMode(args.initialPowerMode);
+    if (args.initialPowerMode.has_value()) setPowerMode(args.initialPowerMode.value());
 
     // initialize the display orientation transform.
     setProjection(ui::ROTATION_0, Rect::INVALID_RECT, Rect::INVALID_RECT);
@@ -173,20 +173,31 @@
 }
 
 void DisplayDevice::setPowerMode(hal::PowerMode mode) {
+    if (mode == hal::PowerMode::OFF || mode == hal::PowerMode::ON) {
+        if (mStagedBrightness && mBrightness != *mStagedBrightness) {
+            getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
+            mBrightness = *mStagedBrightness;
+        }
+        mStagedBrightness = std::nullopt;
+        getCompositionDisplay()->applyDisplayBrightness(true);
+    }
+
     mPowerMode = mode;
-    getCompositionDisplay()->setCompositionEnabled(mPowerMode != hal::PowerMode::OFF);
+
+    getCompositionDisplay()->setCompositionEnabled(mPowerMode.has_value() &&
+                                                   *mPowerMode != hal::PowerMode::OFF);
 }
 
 void DisplayDevice::enableLayerCaching(bool enable) {
     getCompositionDisplay()->setLayerCachingEnabled(enable);
 }
 
-hal::PowerMode DisplayDevice::getPowerMode() const {
+std::optional<hal::PowerMode> DisplayDevice::getPowerMode() const {
     return mPowerMode;
 }
 
 bool DisplayDevice::isPoweredOn() const {
-    return mPowerMode != hal::PowerMode::OFF;
+    return mPowerMode && *mPowerMode != hal::PowerMode::OFF;
 }
 
 void DisplayDevice::setActiveMode(DisplayModeId id) {
@@ -211,6 +222,7 @@
               to_string(getId()).c_str());
         return BAD_VALUE;
     }
+    mNumModeSwitchesInPolicy++;
     mUpcomingActiveMode = info;
     ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.mode->getFps().getIntValue());
     return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), info.mode->getHwcId(),
@@ -324,8 +336,10 @@
 }
 
 void DisplayDevice::persistBrightness(bool needsComposite) {
-    if (needsComposite && mStagedBrightness && mBrightness != *mStagedBrightness) {
-        getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
+    if (mStagedBrightness && mBrightness != *mStagedBrightness) {
+        if (needsComposite) {
+            getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
+        }
         mBrightness = *mStagedBrightness;
     }
     mStagedBrightness = std::nullopt;
@@ -372,7 +386,7 @@
     }
 
     result += "\n   powerMode="s;
-    result += to_string(mPowerMode);
+    result += mPowerMode.has_value() ? to_string(mPowerMode.value()) : "OFF(reset)";
     result += '\n';
 
     if (mRefreshRateConfigs) {
@@ -537,6 +551,27 @@
     mDesiredActiveModeChanged = false;
 }
 
+status_t DisplayDevice::setRefreshRatePolicy(
+        const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
+    const auto oldPolicy = mRefreshRateConfigs->getCurrentPolicy();
+    const status_t setPolicyResult = overridePolicy
+            ? mRefreshRateConfigs->setOverridePolicy(policy)
+            : mRefreshRateConfigs->setDisplayManagerPolicy(*policy);
+
+    if (setPolicyResult == OK) {
+        const int numModeChanges = mNumModeSwitchesInPolicy.exchange(0);
+
+        ALOGI("Display %s policy changed\n"
+              "Previous: {%s}\n"
+              "Current:  {%s}\n"
+              "%d mode changes were performed under the previous policy",
+              to_string(getId()).c_str(), oldPolicy.toString().c_str(),
+              policy ? policy->toString().c_str() : "null", numModeChanges);
+    }
+
+    return setPolicyResult;
+}
+
 std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
 
 }  // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index d5d87b4..fc24a9c 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -181,7 +181,7 @@
     /* ------------------------------------------------------------------------
      * Display power mode management.
      */
-    hardware::graphics::composer::hal::PowerMode getPowerMode() const;
+    std::optional<hardware::graphics::composer::hal::PowerMode> getPowerMode() const;
     void setPowerMode(hardware::graphics::composer::hal::PowerMode mode);
     bool isPoweredOn() const;
 
@@ -249,6 +249,10 @@
     nsecs_t getVsyncPeriodFromHWC() const;
     nsecs_t getRefreshTimestamp() const;
 
+    status_t setRefreshRatePolicy(
+            const std::optional<scheduler::RefreshRateConfigs::Policy>& policy,
+            bool overridePolicy);
+
     // release HWC resources (if any) for removable displays
     void disconnect();
 
@@ -277,8 +281,8 @@
 
     static ui::Transform::RotationFlags sPrimaryDisplayRotationFlags;
 
-    hardware::graphics::composer::hal::PowerMode mPowerMode =
-            hardware::graphics::composer::hal::PowerMode::OFF;
+     // allow initial power mode as null.
+    std::optional<hardware::graphics::composer::hal::PowerMode> mPowerMode;
     DisplayModePtr mActiveMode;
     std::optional<float> mStagedBrightness = std::nullopt;
     float mBrightness = -1.f;
@@ -303,6 +307,8 @@
     TracedOrdinal<bool> mDesiredActiveModeChanged
             GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
     ActiveModeInfo mUpcomingActiveMode GUARDED_BY(kMainThreadContext);
+
+    std::atomic_int mNumModeSwitchesInPolicy = 0;
 };
 
 struct DisplayDeviceState {
@@ -360,8 +366,7 @@
     HdrCapabilities hdrCapabilities;
     int32_t supportedPerFrameMetadata{0};
     std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
-    hardware::graphics::composer::hal::PowerMode initialPowerMode{
-            hardware::graphics::composer::hal::PowerMode::ON};
+    std::optional<hardware::graphics::composer::hal::PowerMode> initialPowerMode;
     bool isPrimary{false};
     DisplayModes supportedModes;
     DisplayModeId activeModeId;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 0da8ece..a6aee1f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -738,6 +738,13 @@
             });
 }
 
+bool HWComposer::getValidateSkipped(HalDisplayId displayId) const {
+    if (mDisplayData.count(displayId) == 0) {
+        return false;
+    }
+    return mDisplayData.at(displayId).validateWasSkipped;
+}
+
 status_t HWComposer::setBootDisplayMode(PhysicalDisplayId displayId,
                                         hal::HWConfigId displayModeId) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 4c0ecd8..92a8f30 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -199,6 +199,9 @@
             PhysicalDisplayId, float brightness, float brightnessNits,
             const Hwc2::Composer::DisplayBrightnessOptions&) = 0;
 
+    // Get whether the display skipped validation on the latest present
+    virtual bool getValidateSkipped(HalDisplayId displayId) const = 0;
+
     // Events handling ---------------------------------------------------------
 
     // Returns stable display ID (and display name on connection of new or previously disconnected
@@ -397,6 +400,8 @@
 
     status_t setActiveColorMode(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent) override;
 
+    bool getValidateSkipped(HalDisplayId displayId) const override;
+
     // Composer 2.4
     ui::DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override;
     bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const override;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index b5678b4..a0350b7 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -187,7 +187,7 @@
     if (!mSupportsPowerHint.has_value()) {
         std::lock_guard lock(mPowerHalMutex);
         HalWrapper* const halWrapper = getPowerHal();
-        mSupportsPowerHint = halWrapper->supportsPowerHintSession();
+        mSupportsPowerHint = halWrapper && halWrapper->supportsPowerHintSession();
     }
     return *mSupportsPowerHint;
 }
@@ -196,7 +196,7 @@
     return mPowerHintSessionRunning;
 }
 
-void PowerAdvisor::setTargetWorkDuration(int64_t targetDurationNanos) {
+void PowerAdvisor::setTargetWorkDuration(int64_t targetDuration) {
     if (!usePowerHintSession()) {
         ALOGV("Power hint session target duration cannot be set, skipping");
         return;
@@ -205,26 +205,45 @@
         std::lock_guard lock(mPowerHalMutex);
         HalWrapper* const halWrapper = getPowerHal();
         if (halWrapper != nullptr) {
-            halWrapper->setTargetWorkDuration(targetDurationNanos - kTargetSafetyMargin.count());
+            halWrapper->setTargetWorkDuration(targetDuration);
         }
     }
 }
 
-void PowerAdvisor::sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) {
+void PowerAdvisor::sendActualWorkDuration() {
     if (!mBootFinished || !usePowerHintSession()) {
         ALOGV("Actual work duration power hint cannot be sent, skipping");
         return;
     }
-    {
+    const std::optional<nsecs_t> actualDuration = estimateWorkDuration(false);
+    if (actualDuration.has_value()) {
         std::lock_guard lock(mPowerHalMutex);
         HalWrapper* const halWrapper = getPowerHal();
         if (halWrapper != nullptr) {
-            halWrapper->sendActualWorkDuration(actualDurationNanos, timeStampNanos);
+            halWrapper->sendActualWorkDuration(*actualDuration + kTargetSafetyMargin.count(),
+                                               systemTime());
         }
     }
 }
 
-// needs to be set after the flag is known but before PowerAdvisor enters onBootFinished
+void PowerAdvisor::sendPredictedWorkDuration() {
+    if (!mBootFinished || !usePowerHintSession()) {
+        ALOGV("Actual work duration power hint cannot be sent, skipping");
+        return;
+    }
+
+    const std::optional<nsecs_t> predictedDuration = estimateWorkDuration(true);
+
+    if (predictedDuration.has_value()) {
+        std::lock_guard lock(mPowerHalMutex);
+        HalWrapper* const halWrapper = getPowerHal();
+        if (halWrapper != nullptr) {
+            halWrapper->sendActualWorkDuration(*predictedDuration + kTargetSafetyMargin.count(),
+                                               systemTime());
+        }
+    }
+}
+
 void PowerAdvisor::enablePowerHint(bool enabled) {
     mPowerHintEnabled = enabled;
 }
@@ -244,6 +263,302 @@
     return mPowerHintSessionRunning;
 }
 
+void PowerAdvisor::setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) {
+    DisplayTimingData& displayData = mDisplayTimingData[displayId];
+    if (displayData.gpuEndFenceTime) {
+        nsecs_t signalTime = displayData.gpuEndFenceTime->getSignalTime();
+        if (signalTime != Fence::SIGNAL_TIME_INVALID && signalTime != Fence::SIGNAL_TIME_PENDING) {
+            for (auto&& [_, otherDisplayData] : mDisplayTimingData) {
+                // If the previous display started before us but ended after we should have
+                // started, then it likely delayed our start time and we must compensate for that.
+                // Displays finishing earlier should have already made their way through this call
+                // and swapped their timing into "lastValid" from "latest", so we check that here.
+                if (!otherDisplayData.lastValidGpuStartTime.has_value()) continue;
+                if ((*otherDisplayData.lastValidGpuStartTime < *displayData.gpuStartTime) &&
+                    (*otherDisplayData.lastValidGpuEndTime > *displayData.gpuStartTime)) {
+                    displayData.lastValidGpuStartTime = *otherDisplayData.lastValidGpuEndTime;
+                    break;
+                }
+            }
+            displayData.lastValidGpuStartTime = displayData.gpuStartTime;
+            displayData.lastValidGpuEndTime = signalTime;
+        }
+    }
+    displayData.gpuEndFenceTime = std::move(fenceTime);
+    displayData.gpuStartTime = systemTime();
+}
+
+void PowerAdvisor::setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime,
+                                        nsecs_t validateEndTime) {
+    DisplayTimingData& displayData = mDisplayTimingData[displayId];
+    displayData.hwcValidateStartTime = validateStartTime;
+    displayData.hwcValidateEndTime = validateEndTime;
+}
+
+void PowerAdvisor::setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
+                                       nsecs_t presentEndTime) {
+    DisplayTimingData& displayData = mDisplayTimingData[displayId];
+    displayData.hwcPresentStartTime = presentStartTime;
+    displayData.hwcPresentEndTime = presentEndTime;
+}
+
+void PowerAdvisor::setSkippedValidate(DisplayId displayId, bool skipped) {
+    mDisplayTimingData[displayId].skippedValidate = skipped;
+}
+
+void PowerAdvisor::setRequiresClientComposition(DisplayId displayId,
+                                                bool requiresClientComposition) {
+    mDisplayTimingData[displayId].usedClientComposition = requiresClientComposition;
+}
+
+void PowerAdvisor::setExpectedPresentTime(nsecs_t expectedPresentTime) {
+    mExpectedPresentTimes.append(expectedPresentTime);
+}
+
+void PowerAdvisor::setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) {
+    mLastSfPresentEndTime = presentEndTime;
+    mLastPresentFenceTime = presentFenceTime;
+}
+
+void PowerAdvisor::setFrameDelay(nsecs_t frameDelayDuration) {
+    mFrameDelayDuration = frameDelayDuration;
+}
+
+void PowerAdvisor::setHwcPresentDelayedTime(
+        DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) {
+    mDisplayTimingData[displayId].hwcPresentDelayedTime =
+            (earliestFrameStartTime - std::chrono::steady_clock::now()).count() + systemTime();
+}
+
+void PowerAdvisor::setCommitStart(nsecs_t commitStartTime) {
+    mCommitStartTimes.append(commitStartTime);
+}
+
+void PowerAdvisor::setCompositeEnd(nsecs_t compositeEnd) {
+    mLastPostcompDuration = compositeEnd - mLastSfPresentEndTime;
+}
+
+void PowerAdvisor::setDisplays(std::vector<DisplayId>& displayIds) {
+    mDisplayIds = displayIds;
+}
+
+void PowerAdvisor::setTotalFrameTargetWorkDuration(nsecs_t targetDuration) {
+    mTotalFrameTargetDuration = targetDuration;
+}
+
+std::vector<DisplayId> PowerAdvisor::getOrderedDisplayIds(
+        std::optional<nsecs_t> DisplayTimingData::*sortBy) {
+    std::vector<DisplayId> sortedDisplays;
+    std::copy_if(mDisplayIds.begin(), mDisplayIds.end(), std::back_inserter(sortedDisplays),
+                 [&](DisplayId id) {
+                     return mDisplayTimingData.count(id) &&
+                             (mDisplayTimingData[id].*sortBy).has_value();
+                 });
+    std::sort(sortedDisplays.begin(), sortedDisplays.end(), [&](DisplayId idA, DisplayId idB) {
+        return *(mDisplayTimingData[idA].*sortBy) < *(mDisplayTimingData[idB].*sortBy);
+    });
+    return sortedDisplays;
+}
+
+std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) {
+    if (earlyHint && (!mExpectedPresentTimes.isFull() || !mCommitStartTimes.isFull())) {
+        return std::nullopt;
+    }
+
+    // Tracks when we finish presenting to hwc
+    nsecs_t estimatedEndTime = mCommitStartTimes[0];
+
+    // How long we spent this frame not doing anything, waiting for fences or vsync
+    nsecs_t idleDuration = 0;
+
+    // Most recent previous gpu end time in the current frame, probably from a prior display, used
+    // as the start time for the next gpu operation if it ran over time since it probably blocked
+    std::optional<nsecs_t> previousValidGpuEndTime;
+
+    // The currently estimated gpu end time for the frame,
+    // used to accumulate gpu time as we iterate over the active displays
+    std::optional<nsecs_t> estimatedGpuEndTime;
+
+    // If we're predicting at the start of the frame, we use last frame as our reference point
+    // If we're predicting at the end of the frame, we use the current frame as a reference point
+    nsecs_t referenceFrameStartTime = (earlyHint ? mCommitStartTimes[-1] : mCommitStartTimes[0]);
+
+    // When the prior frame should be presenting to the display
+    // If we're predicting at the start of the frame, we use last frame's expected present time
+    // If we're predicting at the end of the frame, the present fence time is already known
+    nsecs_t lastFramePresentTime = (earlyHint ? mExpectedPresentTimes[-1] : mLastPresentFenceTime);
+
+    // The timing info for the previously calculated display, if there was one
+    std::optional<DisplayTimeline> previousDisplayReferenceTiming;
+    std::vector<DisplayId>&& displayIds =
+            getOrderedDisplayIds(&DisplayTimingData::hwcPresentStartTime);
+    DisplayTimeline referenceTiming, estimatedTiming;
+
+    // Iterate over the displays that use hwc in the same order they are presented
+    for (DisplayId displayId : displayIds) {
+        if (mDisplayTimingData.count(displayId) == 0) {
+            continue;
+        }
+
+        auto& displayData = mDisplayTimingData.at(displayId);
+
+        // mLastPresentFenceTime should always be the time of the reference frame, since it will be
+        // the previous frame's present fence if called at the start, and current frame's if called
+        // at the end
+        referenceTiming = displayData.calculateDisplayTimeline(mLastPresentFenceTime);
+
+        // If this is the first display, include the duration before hwc present starts
+        if (!previousDisplayReferenceTiming.has_value()) {
+            estimatedEndTime += referenceTiming.hwcPresentStartTime - referenceFrameStartTime;
+        } else { // Otherwise add the time since last display's hwc present finished
+            estimatedEndTime += referenceTiming.hwcPresentStartTime -
+                    previousDisplayReferenceTiming->hwcPresentEndTime;
+        }
+
+        // Late hint can re-use reference timing here since it's estimating its own reference frame
+        estimatedTiming = earlyHint
+                ? referenceTiming.estimateTimelineFromReference(lastFramePresentTime,
+                                                                estimatedEndTime)
+                : referenceTiming;
+
+        // Update predicted present finish time with this display's present time
+        estimatedEndTime = estimatedTiming.hwcPresentEndTime;
+
+        // Track how long we spent waiting for the fence, can be excluded from the timing estimate
+        idleDuration += estimatedTiming.probablyWaitsForPresentFence
+                ? lastFramePresentTime - estimatedTiming.presentFenceWaitStartTime
+                : 0;
+
+        // Track how long we spent waiting to present, can be excluded from the timing estimate
+        idleDuration += earlyHint ? 0 : referenceTiming.hwcPresentDelayDuration;
+
+        // Estimate the reference frame's gpu timing
+        auto gpuTiming = displayData.estimateGpuTiming(previousValidGpuEndTime);
+        if (gpuTiming.has_value()) {
+            previousValidGpuEndTime = gpuTiming->startTime + gpuTiming->duration;
+
+            // Estimate the prediction frame's gpu end time from the reference frame
+            estimatedGpuEndTime =
+                    std::max(estimatedTiming.hwcPresentStartTime, estimatedGpuEndTime.value_or(0)) +
+                    gpuTiming->duration;
+        }
+        previousDisplayReferenceTiming = referenceTiming;
+    }
+    ATRACE_INT64("Idle duration", idleDuration);
+
+    nsecs_t estimatedFlingerEndTime = earlyHint ? estimatedEndTime : mLastSfPresentEndTime;
+
+    // Don't count time spent idly waiting in the estimate as we could do more work in that time
+    estimatedEndTime -= idleDuration;
+    estimatedFlingerEndTime -= idleDuration;
+
+    // We finish the frame when both present and the gpu are done, so wait for the later of the two
+    // Also add the frame delay duration since the target did not move while we were delayed
+    nsecs_t totalDuration = mFrameDelayDuration +
+            std::max(estimatedEndTime, estimatedGpuEndTime.value_or(0)) - mCommitStartTimes[0];
+
+    // We finish SurfaceFlinger when post-composition finishes, so add that in here
+    nsecs_t flingerDuration =
+            estimatedFlingerEndTime + mLastPostcompDuration - mCommitStartTimes[0];
+
+    // Combine the two timings into a single normalized one
+    nsecs_t combinedDuration = combineTimingEstimates(totalDuration, flingerDuration);
+
+    return std::make_optional(combinedDuration);
+}
+
+nsecs_t PowerAdvisor::combineTimingEstimates(nsecs_t totalDuration, nsecs_t flingerDuration) {
+    nsecs_t targetDuration;
+    {
+        std::lock_guard lock(mPowerHalMutex);
+        targetDuration = *getPowerHal()->getTargetWorkDuration();
+    }
+    if (!mTotalFrameTargetDuration.has_value()) return flingerDuration;
+
+    // Normalize total to the flinger target (vsync period) since that's how often we actually send
+    // hints
+    nsecs_t normalizedTotalDuration = (targetDuration * totalDuration) / *mTotalFrameTargetDuration;
+    return std::max(flingerDuration, normalizedTotalDuration);
+}
+
+PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimeline::estimateTimelineFromReference(
+        nsecs_t fenceTime, nsecs_t displayStartTime) {
+    DisplayTimeline estimated;
+    estimated.hwcPresentStartTime = displayStartTime;
+
+    // We don't predict waiting for vsync alignment yet
+    estimated.hwcPresentDelayDuration = 0;
+
+    // How long we expect to run before we start waiting for the fence
+    // For now just re-use last frame's post-present duration and assume it will not change much
+    // Excludes time spent waiting for vsync since that's not going to be consistent
+    estimated.presentFenceWaitStartTime = estimated.hwcPresentStartTime +
+            (presentFenceWaitStartTime - (hwcPresentStartTime + hwcPresentDelayDuration));
+    estimated.probablyWaitsForPresentFence = fenceTime > estimated.presentFenceWaitStartTime;
+    estimated.hwcPresentEndTime = postPresentFenceHwcPresentDuration +
+            (estimated.probablyWaitsForPresentFence ? fenceTime
+                                                    : estimated.presentFenceWaitStartTime);
+    return estimated;
+}
+
+PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayTimeline(
+        nsecs_t fenceTime) {
+    DisplayTimeline timeline;
+    // How long between calling hwc present and trying to wait on the fence
+    const nsecs_t fenceWaitStartDelay =
+            (skippedValidate ? kFenceWaitStartDelaySkippedValidate : kFenceWaitStartDelayValidated)
+                    .count();
+
+    // Did our reference frame wait for an appropriate vsync before calling into hwc
+    const bool waitedOnHwcPresentTime = hwcPresentDelayedTime.has_value() &&
+            *hwcPresentDelayedTime > *hwcPresentStartTime &&
+            *hwcPresentDelayedTime < *hwcPresentEndTime;
+
+    // Use validate start here if we skipped it because we did validate + present together
+    timeline.hwcPresentStartTime = skippedValidate ? *hwcValidateStartTime : *hwcPresentStartTime;
+
+    // Use validate end here if we skipped it because we did validate + present together
+    timeline.hwcPresentEndTime = skippedValidate ? *hwcValidateEndTime : *hwcPresentEndTime;
+
+    // How long hwc present was delayed waiting for the next appropriate vsync
+    timeline.hwcPresentDelayDuration =
+            (waitedOnHwcPresentTime ? *hwcPresentDelayedTime - *hwcPresentStartTime : 0);
+    // When we started waiting for the present fence after calling into hwc present
+    timeline.presentFenceWaitStartTime =
+            timeline.hwcPresentStartTime + timeline.hwcPresentDelayDuration + fenceWaitStartDelay;
+    timeline.probablyWaitsForPresentFence = fenceTime > timeline.presentFenceWaitStartTime &&
+            fenceTime < timeline.hwcPresentEndTime;
+
+    // How long we ran after we finished waiting for the fence but before hwc present finished
+    timeline.postPresentFenceHwcPresentDuration = timeline.hwcPresentEndTime -
+            (timeline.probablyWaitsForPresentFence ? fenceTime
+                                                   : timeline.presentFenceWaitStartTime);
+    return timeline;
+}
+
+std::optional<PowerAdvisor::GpuTimeline> PowerAdvisor::DisplayTimingData::estimateGpuTiming(
+        std::optional<nsecs_t> previousEnd) {
+    if (!(usedClientComposition && lastValidGpuStartTime.has_value() && gpuEndFenceTime)) {
+        return std::nullopt;
+    }
+    const nsecs_t latestGpuStartTime = std::max(previousEnd.value_or(0), *gpuStartTime);
+    const nsecs_t latestGpuEndTime = gpuEndFenceTime->getSignalTime();
+    nsecs_t gpuDuration = 0;
+    if (latestGpuEndTime != Fence::SIGNAL_TIME_INVALID &&
+        latestGpuEndTime != Fence::SIGNAL_TIME_PENDING) {
+        // If we know how long the most recent gpu duration was, use that
+        gpuDuration = latestGpuEndTime - latestGpuStartTime;
+    } else if (lastValidGpuEndTime.has_value()) {
+        // If we don't have the fence data, use the most recent information we do have
+        gpuDuration = *lastValidGpuEndTime - *lastValidGpuStartTime;
+        if (latestGpuEndTime == Fence::SIGNAL_TIME_PENDING) {
+            // If pending but went over the previous duration, use current time as the end
+            gpuDuration = std::max(gpuDuration, systemTime() - latestGpuStartTime);
+        }
+    }
+    return GpuTimeline{.duration = gpuDuration, .startTime = latestGpuStartTime};
+}
+
 class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
 public:
     HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
@@ -325,6 +640,9 @@
     }
 
     mSupportsPowerHint = checkPowerHintSessionSupported();
+
+    // Currently set to 0 to disable rate limiter by default
+    mAllowedActualDeviation = base::GetIntProperty<nsecs_t>("debug.sf.allowed_actual_deviation", 0);
 }
 
 AidlPowerHalWrapper::~AidlPowerHalWrapper() {
@@ -332,7 +650,7 @@
         mPowerHintSession->close();
         mPowerHintSession = nullptr;
     }
-};
+}
 
 std::unique_ptr<PowerAdvisor::HalWrapper> AidlPowerHalWrapper::connect() {
     // This only waits if the service is actually declared
@@ -370,7 +688,7 @@
     return ret.isOk();
 }
 
-// only version 2+ of the aidl supports power hint sessions, hidl has no support
+// Only version 2+ of the aidl supports power hint sessions, hidl has no support
 bool AidlPowerHalWrapper::supportsPowerHintSession() {
     return mSupportsPowerHint;
 }
@@ -424,30 +742,14 @@
     return isPowerHintSessionRunning();
 }
 
-bool AidlPowerHalWrapper::shouldSetTargetDuration(int64_t targetDurationNanos) {
-    if (targetDurationNanos <= 0) {
-        return false;
-    }
-    // report if the change in target from our last submission to now exceeds the threshold
-    return abs(1.0 -
-               static_cast<double>(mLastTargetDurationSent) /
-                       static_cast<double>(targetDurationNanos)) >= kAllowedTargetDeviationPercent;
-}
-
-void AidlPowerHalWrapper::setTargetWorkDuration(int64_t targetDurationNanos) {
+void AidlPowerHalWrapper::setTargetWorkDuration(int64_t targetDuration) {
     ATRACE_CALL();
-    mTargetDuration = targetDurationNanos;
-    if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos);
-    if (!sNormalizeTarget && isPowerHintSessionRunning() &&
-        shouldSetTargetDuration(targetDurationNanos)) {
-        if (mLastActualDurationSent.has_value()) {
-            // update the error term here since we are actually sending an update to powerhal
-            if (sTraceHintSessionData)
-                ATRACE_INT64("Target error term", targetDurationNanos - *mLastActualDurationSent);
-        }
-        ALOGV("Sending target time: %" PRId64 "ns", targetDurationNanos);
-        mLastTargetDurationSent = targetDurationNanos;
-        auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
+    mTargetDuration = targetDuration;
+    if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration);
+    if (isPowerHintSessionRunning() && (targetDuration != mLastTargetDurationSent)) {
+        ALOGV("Sending target time: %" PRId64 "ns", targetDuration);
+        mLastTargetDurationSent = targetDuration;
+        auto ret = mPowerHintSession->updateTargetWorkDuration(targetDuration);
         if (!ret.isOk()) {
             ALOGW("Failed to set power hint target work duration with error: %s",
                   ret.exceptionMessage().c_str());
@@ -456,8 +758,8 @@
     }
 }
 
-bool AidlPowerHalWrapper::shouldReportActualDurationsNow() {
-    // report if we have never reported before or are approaching a stale session
+bool AidlPowerHalWrapper::shouldReportActualDurations() {
+    // Report if we have never reported before or are approaching a stale session
     if (!mLastActualDurationSent.has_value() ||
         (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
         return true;
@@ -466,65 +768,42 @@
     if (!mActualDuration.has_value()) {
         return false;
     }
-
-    // duration of most recent timing
-    const double mostRecentActualDuration = static_cast<double>(*mActualDuration);
-    // duration of the last timing actually reported to the powerhal
-    const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent);
-
-    // report if the change in duration from then to now exceeds the threshold
-    return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
-            kAllowedActualDeviationPercent;
+    // Report if the change in actual duration exceeds the threshold
+    return abs(*mActualDuration - *mLastActualDurationSent) > mAllowedActualDeviation;
 }
 
-void AidlPowerHalWrapper::sendActualWorkDuration(int64_t actualDurationNanos,
-                                                 nsecs_t timeStampNanos) {
+void AidlPowerHalWrapper::sendActualWorkDuration(int64_t actualDuration, nsecs_t timestamp) {
     ATRACE_CALL();
 
-    if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
+    if (actualDuration < 0 || !isPowerHintSessionRunning()) {
         ALOGV("Failed to send actual work duration, skipping");
         return;
     }
-    nsecs_t reportedDuration = actualDurationNanos;
+    const nsecs_t reportedDuration = actualDuration;
 
-    // normalize the sent values to a pre-set target
-    if (sNormalizeTarget) {
-        reportedDuration += mLastTargetDurationSent - mTargetDuration;
-    } else {
-        // when target duration change is within deviation and not updated, adjust the actual
-        // duration proportionally based on the difference, e.g. if new target is 5ms longer than
-        // last reported but actual duration is the same as last target, we want to report a smaller
-        // actual work duration now to indicate that we are overshooting
-        if (mLastTargetDurationSent != kDefaultTarget.count() && mTargetDuration != 0) {
-            reportedDuration =
-                    static_cast<int64_t>(static_cast<long double>(mLastTargetDurationSent) /
-                                         mTargetDuration * actualDurationNanos);
-            mActualDuration = reportedDuration;
-        }
-    }
     mActualDuration = reportedDuration;
     WorkDuration duration;
     duration.durationNanos = reportedDuration;
-    duration.timeStampNanos = timeStampNanos;
+    duration.timeStampNanos = timestamp;
     mPowerHintQueue.push_back(duration);
 
     if (sTraceHintSessionData) {
-        ATRACE_INT64("Measured duration", actualDurationNanos);
-        ATRACE_INT64("Target error term", mTargetDuration - actualDurationNanos);
+        ATRACE_INT64("Measured duration", actualDuration);
+        ATRACE_INT64("Target error term", actualDuration - mTargetDuration);
 
         ATRACE_INT64("Reported duration", reportedDuration);
         ATRACE_INT64("Reported target", mLastTargetDurationSent);
-        ATRACE_INT64("Reported target error term", mLastTargetDurationSent - reportedDuration);
+        ATRACE_INT64("Reported target error term", reportedDuration - mLastTargetDurationSent);
     }
 
     ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64
           " with error: %" PRId64,
-          reportedDuration, mLastTargetDurationSent, mLastTargetDurationSent - reportedDuration);
+          reportedDuration, mLastTargetDurationSent, reportedDuration - mLastTargetDurationSent);
 
     // This rate limiter queues similar duration reports to the powerhal into
     // batches to avoid excessive binder calls. The criteria to send a given batch
     // are outlined in shouldReportActualDurationsNow()
-    if (shouldReportActualDurationsNow()) {
+    if (shouldReportActualDurations()) {
         ALOGV("Sending hint update batch");
         mLastActualReportTimestamp = systemTime();
         auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
@@ -534,8 +813,8 @@
             mShouldReconnectHal = true;
         }
         mPowerHintQueue.clear();
-        // we save the non-normalized value here to detect % changes
-        mLastActualDurationSent = reportedDuration;
+        // We save the actual duration here for rate limiting
+        mLastActualDurationSent = actualDuration;
     }
 }
 
@@ -551,76 +830,73 @@
     return mTargetDuration;
 }
 
+void AidlPowerHalWrapper::setAllowedActualDeviation(nsecs_t allowedDeviation) {
+    mAllowedActualDeviation = allowedDeviation;
+}
+
 const bool AidlPowerHalWrapper::sTraceHintSessionData =
         base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
 
-const bool AidlPowerHalWrapper::sNormalizeTarget =
-        base::GetBoolProperty(std::string("debug.sf.normalize_hint_session_durations"), false);
-
 PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
-    static std::unique_ptr<HalWrapper> sHalWrapper = nullptr;
-    static bool sHasHal = true;
-
-    if (!sHasHal) {
+    if (!mHasHal) {
         return nullptr;
     }
 
-    // grab old hint session values before we destroy any existing wrapper
+    // Grab old hint session values before we destroy any existing wrapper
     std::vector<int32_t> oldPowerHintSessionThreadIds;
     std::optional<int64_t> oldTargetWorkDuration;
 
-    if (sHalWrapper != nullptr) {
-        oldPowerHintSessionThreadIds = sHalWrapper->getPowerHintSessionThreadIds();
-        oldTargetWorkDuration = sHalWrapper->getTargetWorkDuration();
+    if (mHalWrapper != nullptr) {
+        oldPowerHintSessionThreadIds = mHalWrapper->getPowerHintSessionThreadIds();
+        oldTargetWorkDuration = mHalWrapper->getTargetWorkDuration();
     }
 
     // If we used to have a HAL, but it stopped responding, attempt to reconnect
     if (mReconnectPowerHal) {
-        sHalWrapper = nullptr;
+        mHalWrapper = nullptr;
         mReconnectPowerHal = false;
     }
 
-    if (sHalWrapper != nullptr) {
-        auto wrapper = sHalWrapper.get();
-        // if the wrapper is fine, return it, but if it indicates a reconnect, remake it
+    if (mHalWrapper != nullptr) {
+        auto wrapper = mHalWrapper.get();
+        // If the wrapper is fine, return it, but if it indicates a reconnect, remake it
         if (!wrapper->shouldReconnectHAL()) {
             return wrapper;
         }
         ALOGD("Reconnecting Power HAL");
-        sHalWrapper = nullptr;
+        mHalWrapper = nullptr;
     }
 
-    // at this point, we know for sure there is no running session
+    // At this point, we know for sure there is no running session
     mPowerHintSessionRunning = false;
 
     // First attempt to connect to the AIDL Power HAL
-    sHalWrapper = AidlPowerHalWrapper::connect();
+    mHalWrapper = AidlPowerHalWrapper::connect();
 
     // If that didn't succeed, attempt to connect to the HIDL Power HAL
-    if (sHalWrapper == nullptr) {
-        sHalWrapper = HidlPowerHalWrapper::connect();
+    if (mHalWrapper == nullptr) {
+        mHalWrapper = HidlPowerHalWrapper::connect();
     } else {
         ALOGD("Successfully connecting AIDL Power HAL");
-        // if AIDL, pass on any existing hint session values
-        // thread ids always safe to set
-        sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
-        // only set duration and start if duration is defined
+        // If AIDL, pass on any existing hint session values
+        mHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
+        // Only set duration and start if duration is defined
         if (oldTargetWorkDuration.has_value()) {
-            sHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration);
-            // only start if possible to run and both threadids and duration are defined
+            mHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration);
+            // Only start if possible to run and both threadids and duration are defined
             if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) {
-                mPowerHintSessionRunning = sHalWrapper->startPowerHintSession();
+                mPowerHintSessionRunning = mHalWrapper->startPowerHintSession();
             }
         }
     }
 
     // If we make it to this point and still don't have a HAL, it's unlikely we
     // will, so stop trying
-    if (sHalWrapper == nullptr) {
-        sHasHal = false;
+    if (mHalWrapper == nullptr) {
+        mHasHal = false;
     }
 
-    return sHalWrapper.get();
+    return mHalWrapper.get();
 }
 
 } // namespace impl
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 7c10e19..6e25f78 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -18,11 +18,15 @@
 
 #include <atomic>
 #include <chrono>
+#include <unordered_map>
 #include <unordered_set>
 
+#include <ui/DisplayId.h>
+#include <ui/FenceTime.h>
 #include <utils/Mutex.h>
 
 #include <android/hardware/power/IPower.h>
+#include <compositionengine/impl/OutputCompositionState.h>
 #include <ui/DisplayIdentification.h>
 #include "../Scheduler/OneShotTimer.h"
 
@@ -44,13 +48,50 @@
     virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0;
     virtual bool isUsingExpensiveRendering() = 0;
     virtual void notifyDisplayUpdateImminent() = 0;
+    // Checks both if it supports and if it's enabled
     virtual bool usePowerHintSession() = 0;
     virtual bool supportsPowerHintSession() = 0;
     virtual bool isPowerHintSessionRunning() = 0;
-    virtual void setTargetWorkDuration(int64_t targetDurationNanos) = 0;
-    virtual void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) = 0;
+    // Sends a power hint that updates to the target work duration for the frame
+    virtual void setTargetWorkDuration(nsecs_t targetDuration) = 0;
+    // Sends a power hint for the actual known work duration at the end of the frame
+    virtual void sendActualWorkDuration() = 0;
+    // Sends a power hint for the upcoming frame predicted from previous frame timing
+    virtual void sendPredictedWorkDuration() = 0;
+    // Sets whether the power hint session is enabled
     virtual void enablePowerHint(bool enabled) = 0;
+    // Initializes the power hint session
     virtual bool startPowerHintSession(const std::vector<int32_t>& threadIds) = 0;
+    // Provides PowerAdvisor with a copy of the gpu fence so it can determine the gpu end time
+    virtual void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) = 0;
+    // Reports the start and end times of a hwc validate call this frame for a given display
+    virtual void setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime,
+                                      nsecs_t validateEndTime) = 0;
+    // Reports the start and end times of a hwc present call this frame for a given display
+    virtual void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
+                                     nsecs_t presentEndTime) = 0;
+    // Reports the expected time that the current frame will present to the display
+    virtual void setExpectedPresentTime(nsecs_t expectedPresentTime) = 0;
+    // Reports the most recent present fence time and end time once known
+    virtual void setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) = 0;
+    // Reports whether a display used client composition this frame
+    virtual void setRequiresClientComposition(DisplayId displayId,
+                                              bool requiresClientComposition) = 0;
+    // Reports whether a given display skipped validation this frame
+    virtual void setSkippedValidate(DisplayId displayId, bool skipped) = 0;
+    // Reports when a hwc present is delayed, and the time that it will resume
+    virtual void setHwcPresentDelayedTime(
+            DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) = 0;
+    // Reports the start delay for SurfaceFlinger this frame
+    virtual void setFrameDelay(nsecs_t frameDelayDuration) = 0;
+    // Reports the SurfaceFlinger commit start time this frame
+    virtual void setCommitStart(nsecs_t commitStartTime) = 0;
+    // Reports the SurfaceFlinger composite end time this frame
+    virtual void setCompositeEnd(nsecs_t compositeEndTime) = 0;
+    // Reports the list of the currently active displays
+    virtual void setDisplays(std::vector<DisplayId>& displayIds) = 0;
+    // Sets the target duration for the entire pipeline including the gpu
+    virtual void setTotalFrameTargetWorkDuration(nsecs_t targetDuration) = 0;
 };
 
 namespace impl {
@@ -70,12 +111,11 @@
         virtual void restartPowerHintSession() = 0;
         virtual void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) = 0;
         virtual bool startPowerHintSession() = 0;
-        virtual void setTargetWorkDuration(int64_t targetDurationNanos) = 0;
-        virtual void sendActualWorkDuration(int64_t actualDurationNanos,
-                                            nsecs_t timeStampNanos) = 0;
+        virtual void setTargetWorkDuration(nsecs_t targetDuration) = 0;
+        virtual void sendActualWorkDuration(nsecs_t actualDuration, nsecs_t timestamp) = 0;
         virtual bool shouldReconnectHAL() = 0;
         virtual std::vector<int32_t> getPowerHintSessionThreadIds() = 0;
-        virtual std::optional<int64_t> getTargetWorkDuration() = 0;
+        virtual std::optional<nsecs_t> getTargetWorkDuration() = 0;
     };
 
     PowerAdvisor(SurfaceFlinger& flinger);
@@ -89,26 +129,43 @@
     bool usePowerHintSession() override;
     bool supportsPowerHintSession() override;
     bool isPowerHintSessionRunning() override;
-    void setTargetWorkDuration(int64_t targetDurationNanos) override;
-    void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) override;
+    void setTargetWorkDuration(nsecs_t targetDuration) override;
+    void sendActualWorkDuration() override;
+    void sendPredictedWorkDuration() override;
     void enablePowerHint(bool enabled) override;
     bool startPowerHintSession(const std::vector<int32_t>& threadIds) override;
+    void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime);
+    void setHwcValidateTiming(DisplayId displayId, nsecs_t valiateStartTime,
+                              nsecs_t validateEndTime) override;
+    void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
+                             nsecs_t presentEndTime) override;
+    void setSkippedValidate(DisplayId displayId, bool skipped) override;
+    void setRequiresClientComposition(DisplayId displayId, bool requiresClientComposition) override;
+    void setExpectedPresentTime(nsecs_t expectedPresentTime) override;
+    void setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) override;
+    void setHwcPresentDelayedTime(
+            DisplayId displayId,
+            std::chrono::steady_clock::time_point earliestFrameStartTime) override;
+
+    void setFrameDelay(nsecs_t frameDelayDuration) override;
+    void setCommitStart(nsecs_t commitStartTime) override;
+    void setCompositeEnd(nsecs_t compositeEndTime) override;
+    void setDisplays(std::vector<DisplayId>& displayIds) override;
+    void setTotalFrameTargetWorkDuration(nsecs_t targetDuration) override;
 
 private:
+    friend class PowerAdvisorTest;
+
+    // Tracks if powerhal exists
+    bool mHasHal = true;
+    // Holds the hal wrapper for getPowerHal
+    std::unique_ptr<HalWrapper> mHalWrapper GUARDED_BY(mPowerHalMutex) = nullptr;
+
     HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex);
     bool mReconnectPowerHal GUARDED_BY(mPowerHalMutex) = false;
     std::mutex mPowerHalMutex;
 
     std::atomic_bool mBootFinished = false;
-    std::optional<bool> mPowerHintEnabled;
-    std::optional<bool> mSupportsPowerHint;
-    bool mPowerHintSessionRunning = false;
-
-    // An adjustable safety margin which moves the "target" earlier to allow flinger to
-    // go a bit over without dropping a frame, especially since we can't measure
-    // the exact time HWC finishes composition so "actual" durations are measured
-    // from the end of present() instead, which is a bit later.
-    static constexpr const std::chrono::nanoseconds kTargetSafetyMargin = 2ms;
 
     std::unordered_set<DisplayId> mExpensiveDisplays;
     bool mNotifiedExpensiveRendering = false;
@@ -117,6 +174,110 @@
     std::atomic_bool mSendUpdateImminent = true;
     std::atomic<nsecs_t> mLastScreenUpdatedTime = 0;
     std::optional<scheduler::OneShotTimer> mScreenUpdateTimer;
+
+    // Higher-level timing data used for estimation
+    struct DisplayTimeline {
+        // The start of hwc present, or the start of validate if it happened there instead
+        nsecs_t hwcPresentStartTime = -1;
+        // The end of hwc present or validate, whichever one actually presented
+        nsecs_t hwcPresentEndTime = -1;
+        // How long the actual hwc present was delayed after hwcPresentStartTime
+        nsecs_t hwcPresentDelayDuration = 0;
+        // When we think we started waiting for the present fence after calling into hwc present and
+        // after potentially waiting for the earliest present time
+        nsecs_t presentFenceWaitStartTime = -1;
+        // How long we ran after we finished waiting for the fence but before hwc present finished
+        nsecs_t postPresentFenceHwcPresentDuration = 0;
+        // Are we likely to have waited for the present fence during composition
+        bool probablyWaitsForPresentFence = false;
+        // Estimate one frame's timeline from that of a previous frame
+        DisplayTimeline estimateTimelineFromReference(nsecs_t fenceTime, nsecs_t displayStartTime);
+    };
+
+    struct GpuTimeline {
+        nsecs_t duration = 0;
+        nsecs_t startTime = -1;
+    };
+
+    // Power hint session data recorded from the pipeline
+    struct DisplayTimingData {
+        std::unique_ptr<FenceTime> gpuEndFenceTime;
+        std::optional<nsecs_t> gpuStartTime;
+        std::optional<nsecs_t> lastValidGpuEndTime;
+        std::optional<nsecs_t> lastValidGpuStartTime;
+        std::optional<nsecs_t> hwcPresentStartTime;
+        std::optional<nsecs_t> hwcPresentEndTime;
+        std::optional<nsecs_t> hwcValidateStartTime;
+        std::optional<nsecs_t> hwcValidateEndTime;
+        std::optional<nsecs_t> hwcPresentDelayedTime;
+        bool usedClientComposition = false;
+        bool skippedValidate = false;
+        // Calculate high-level timing milestones from more granular display timing data
+        DisplayTimeline calculateDisplayTimeline(nsecs_t fenceTime);
+        // Estimate the gpu duration for a given display from previous gpu timing data
+        std::optional<GpuTimeline> estimateGpuTiming(std::optional<nsecs_t> previousEnd);
+    };
+
+    template <class T, size_t N>
+    class RingBuffer {
+        std::array<T, N> elements = {};
+        size_t mIndex = 0;
+        size_t numElements = 0;
+
+    public:
+        void append(T item) {
+            mIndex = (mIndex + 1) % N;
+            numElements = std::min(N, numElements + 1);
+            elements[mIndex] = item;
+        }
+        bool isFull() const { return numElements == N; }
+        // Allows access like [0] == current, [-1] = previous, etc..
+        T& operator[](int offset) {
+            size_t positiveOffset =
+                    static_cast<size_t>((offset % static_cast<int>(N)) + static_cast<int>(N));
+            return elements[(mIndex + positiveOffset) % N];
+        }
+    };
+
+    // Filter and sort the display ids by a given property
+    std::vector<DisplayId> getOrderedDisplayIds(std::optional<nsecs_t> DisplayTimingData::*sortBy);
+    // Estimates a frame's total work duration including gpu time.
+    // Runs either at the beginning or end of a frame, using the most recent data available
+    std::optional<nsecs_t> estimateWorkDuration(bool earlyHint);
+    // There are two different targets and actual work durations we care about,
+    // this normalizes them together and takes the max of the two
+    nsecs_t combineTimingEstimates(nsecs_t totalDuration, nsecs_t flingerDuration);
+
+    std::unordered_map<DisplayId, DisplayTimingData> mDisplayTimingData;
+
+    // Current frame's delay
+    nsecs_t mFrameDelayDuration = 0;
+    // Last frame's post-composition duration
+    nsecs_t mLastPostcompDuration = 0;
+    // Buffer of recent commit start times
+    RingBuffer<nsecs_t, 2> mCommitStartTimes;
+    // Buffer of recent expected present times
+    RingBuffer<nsecs_t, 2> mExpectedPresentTimes;
+    // Most recent present fence time, set at the end of the frame once known
+    nsecs_t mLastPresentFenceTime = -1;
+    // Most recent present fence time, set at the end of the frame once known
+    nsecs_t mLastSfPresentEndTime = -1;
+    // Target for the entire pipeline including gpu
+    std::optional<nsecs_t> mTotalFrameTargetDuration;
+    // Updated list of display IDs
+    std::vector<DisplayId> mDisplayIds;
+
+    std::optional<bool> mPowerHintEnabled;
+    std::optional<bool> mSupportsPowerHint;
+    bool mPowerHintSessionRunning = false;
+
+    // An adjustable safety margin which pads the "actual" value sent to PowerHAL,
+    // encouraging more aggressive boosting to give SurfaceFlinger a larger margin for error
+    static constexpr const std::chrono::nanoseconds kTargetSafetyMargin = 1ms;
+
+    // How long we expect hwc to run after the present call until it waits for the fence
+    static constexpr const std::chrono::nanoseconds kFenceWaitStartDelayValidated = 150us;
+    static constexpr const std::chrono::nanoseconds kFenceWaitStartDelaySkippedValidate = 250us;
 };
 
 class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
@@ -133,50 +294,50 @@
     void restartPowerHintSession() override;
     void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override;
     bool startPowerHintSession() override;
-    void setTargetWorkDuration(int64_t targetDurationNanos) override;
-    void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override;
+    void setTargetWorkDuration(nsecs_t targetDuration) override;
+    void sendActualWorkDuration(nsecs_t actualDuration, nsecs_t timestamp) override;
     bool shouldReconnectHAL() override;
     std::vector<int32_t> getPowerHintSessionThreadIds() override;
-    std::optional<int64_t> getTargetWorkDuration() override;
+    std::optional<nsecs_t> getTargetWorkDuration() override;
 
 private:
+    friend class AidlPowerHalWrapperTest;
+
     bool checkPowerHintSessionSupported();
     void closePowerHintSession();
-    bool shouldReportActualDurationsNow();
-    bool shouldSetTargetDuration(int64_t targetDurationNanos);
+    bool shouldReportActualDurations();
+
+    // Used for testing
+    void setAllowedActualDeviation(nsecs_t);
 
     const sp<hardware::power::IPower> mPowerHal = nullptr;
     bool mHasExpensiveRendering = false;
     bool mHasDisplayUpdateImminent = false;
     // Used to indicate an error state and need for reconstruction
     bool mShouldReconnectHal = false;
-    // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
+
+    // Power hint session data
+
+    // Concurrent access for this is protected by mPowerHalMutex
     sp<hardware::power::IPowerHintSession> mPowerHintSession = nullptr;
     // Queue of actual durations saved to report
     std::vector<hardware::power::WorkDuration> mPowerHintQueue;
-    // The latest un-normalized values we have received for target and actual
-    int64_t mTargetDuration = kDefaultTarget.count();
-    std::optional<int64_t> mActualDuration;
+    // The latest values we have received for target and actual
+    nsecs_t mTargetDuration = kDefaultTarget.count();
+    std::optional<nsecs_t> mActualDuration;
     // The list of thread ids, stored so we can restart the session from this class if needed
     std::vector<int32_t> mPowerHintThreadIds;
-    bool mSupportsPowerHint;
+    bool mSupportsPowerHint = false;
     // Keep track of the last messages sent for rate limiter change detection
-    std::optional<int64_t> mLastActualDurationSent;
-    // timestamp of the last report we sent, used to avoid stale sessions
-    int64_t mLastActualReportTimestamp = 0;
-    int64_t mLastTargetDurationSent = kDefaultTarget.count();
-    // Whether to normalize all the actual values as error terms relative to a constant target
-    // This saves a binder call by not setting the target, and should not affect the pid values
-    static const bool sNormalizeTarget;
+    std::optional<nsecs_t> mLastActualDurationSent;
+    // Timestamp of the last report we sent, used to avoid stale sessions
+    nsecs_t mLastActualReportTimestamp = 0;
+    nsecs_t mLastTargetDurationSent = kDefaultTarget.count();
+    // Max amount the error term can vary without causing an actual value report
+    nsecs_t mAllowedActualDeviation = -1;
     // Whether we should emit ATRACE_INT data for hint sessions
     static const bool sTraceHintSessionData;
-
-    // Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
-    static constexpr double kAllowedActualDeviationPercent = 0.1;
-    // Max percent the target duration can vary without causing a report (eg: 0.1 = 10%)
-    static constexpr double kAllowedTargetDeviationPercent = 0.1;
-    // Target used for init and normalization, the actual value does not really matter
-    static constexpr const std::chrono::nanoseconds kDefaultTarget = 50ms;
+    static constexpr const std::chrono::nanoseconds kDefaultTarget = 16ms;
     // Amount of time after the last message was sent before the session goes stale
     // actually 100ms but we use 80 here to ideally avoid going stale
     static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 38662bd..0c4b012 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -81,6 +81,7 @@
 namespace android {
 namespace {
 constexpr int kDumpTableRowLength = 159;
+const ui::Transform kIdentityTransform;
 } // namespace
 
 using namespace ftl::flag_operators;
@@ -2164,7 +2165,8 @@
     if ((traceFlags & LayerTracing::TRACE_INPUT) && needsInputInfo()) {
         WindowInfo info;
         if (useDrawing) {
-            info = fillInputInfo(ui::Transform(), /* displayIsSecure */ true);
+            info = fillInputInfo(
+                    InputDisplayArgs{.transform = &kIdentityTransform, .isSecure = true});
         } else {
             info = state.inputInfo;
         }
@@ -2371,7 +2373,7 @@
     }
 }
 
-WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool displayIsSecure) {
+WindowInfo Layer::fillInputInfo(const InputDisplayArgs& displayArgs) {
     if (!hasInputInfo()) {
         mDrawingState.inputInfo.name = getName();
         mDrawingState.inputInfo.ownerUid = mOwnerUid;
@@ -2380,12 +2382,21 @@
         mDrawingState.inputInfo.displayId = getLayerStack().id;
     }
 
+    const ui::Transform& displayTransform =
+            displayArgs.transform != nullptr ? *displayArgs.transform : kIdentityTransform;
+
     WindowInfo info = mDrawingState.inputInfo;
     info.id = sequence;
     info.displayId = getLayerStack().id;
 
     fillInputFrameInfo(info, displayTransform);
 
+    if (displayArgs.transform == nullptr) {
+        // Do not let the window receive touches if it is not associated with a valid display
+        // transform. We still allow the window to receive keys and prevent ANRs.
+        info.inputConfig |= WindowInfo::InputConfig::NOT_TOUCHABLE;
+    }
+
     // For compatibility reasons we let layers which can receive input
     // receive input before they have actually submitted a buffer. Because
     // of this we use canReceiveInput instead of isVisible to check the
@@ -2403,7 +2414,7 @@
 
     // If the window will be blacked out on a display because the display does not have the secure
     // flag and the layer has the secure flag set, then drop input.
-    if (!displayIsSecure && isSecure()) {
+    if (!displayArgs.isSecure && isSecure()) {
         info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
     }
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 24abad9..c547da0 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -844,7 +844,11 @@
     bool getPremultipledAlpha() const;
     void setInputInfo(const gui::WindowInfo& info);
 
-    gui::WindowInfo fillInputInfo(const ui::Transform& displayTransform, bool displayIsSecure);
+    struct InputDisplayArgs {
+        const ui::Transform* transform = nullptr;
+        bool isSecure = false;
+    };
+    gui::WindowInfo fillInputInfo(const InputDisplayArgs& displayArgs);
 
     /**
      * Returns whether this layer has an explicitly set input-info.
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index d4435c2..a9180d4 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -16,9 +16,10 @@
 
 #include <algorithm>
 
-#include "RefreshRateOverlay.h"
+#include "BackgroundExecutor.h"
 #include "Client.h"
 #include "Layer.h"
+#include "RefreshRateOverlay.h"
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wconversion"
@@ -56,6 +57,14 @@
 
 } // namespace
 
+SurfaceControlHolder::~SurfaceControlHolder() {
+    // Hand the sp<SurfaceControl> to the helper thread to release the last
+    // reference. This makes sure that the SurfaceControl is destructed without
+    // SurfaceFlinger::mStateLock held.
+    BackgroundExecutor::getInstance().sendCallbacks(
+            {[sc = std::move(mSurfaceControl)]() mutable { sc.clear(); }});
+}
+
 void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor color,
                                                          SkCanvas& canvas) {
     const SkRect rect = [&]() {
@@ -210,21 +219,27 @@
     return buffers;
 }
 
+std::unique_ptr<SurfaceControlHolder> createSurfaceControlHolder() {
+    sp<SurfaceControl> surfaceControl =
+            SurfaceComposerClient::getDefault()
+                    ->createSurface(String8("RefreshRateOverlay"), kBufferWidth, kBufferHeight,
+                                    PIXEL_FORMAT_RGBA_8888,
+                                    ISurfaceComposerClient::eFXSurfaceBufferState);
+    return std::make_unique<SurfaceControlHolder>(std::move(surfaceControl));
+}
+
 RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, bool showSpinner)
       : mFpsRange(fpsRange),
         mShowSpinner(showSpinner),
-        mSurfaceControl(SurfaceComposerClient::getDefault()
-                                ->createSurface(String8("RefreshRateOverlay"), kBufferWidth,
-                                                kBufferHeight, PIXEL_FORMAT_RGBA_8888,
-                                                ISurfaceComposerClient::eFXSurfaceBufferState)) {
+        mSurfaceControl(createSurfaceControlHolder()) {
     if (!mSurfaceControl) {
         ALOGE("%s: Failed to create buffer state layer", __func__);
         return;
     }
 
-    createTransaction(mSurfaceControl)
-            .setLayer(mSurfaceControl, INT32_MAX - 2)
-            .setTrustedOverlay(mSurfaceControl, true)
+    createTransaction(mSurfaceControl->get())
+            .setLayer(mSurfaceControl->get(), INT32_MAX - 2)
+            .setTrustedOverlay(mSurfaceControl->get(), true)
             .apply();
 }
 
@@ -233,7 +248,7 @@
     if (!mSurfaceControl) return kNoBuffers;
 
     const auto transformHint =
-            static_cast<ui::Transform::RotationFlags>(mSurfaceControl->getTransformHint());
+            static_cast<ui::Transform::RotationFlags>(mSurfaceControl->get()->getTransformHint());
 
     // Tell SurfaceFlinger about the pre-rotation on the buffer.
     const auto transform = [&] {
@@ -247,7 +262,9 @@
         }
     }();
 
-    createTransaction(mSurfaceControl).setTransform(mSurfaceControl, transform).apply();
+    createTransaction(mSurfaceControl->get())
+            .setTransform(mSurfaceControl->get(), transform)
+            .apply();
 
     BufferCache::const_iterator it = mBufferCache.find({fps.getIntValue(), transformHint});
     if (it == mBufferCache.end()) {
@@ -289,21 +306,21 @@
     Rect frame((3 * width) >> 4, height >> 5);
     frame.offsetBy(width >> 5, height >> 4);
 
-    createTransaction(mSurfaceControl)
-            .setMatrix(mSurfaceControl, frame.getWidth() / static_cast<float>(kBufferWidth), 0, 0,
-                       frame.getHeight() / static_cast<float>(kBufferHeight))
-            .setPosition(mSurfaceControl, frame.left, frame.top)
+    createTransaction(mSurfaceControl->get())
+            .setMatrix(mSurfaceControl->get(), frame.getWidth() / static_cast<float>(kBufferWidth),
+                       0, 0, frame.getHeight() / static_cast<float>(kBufferHeight))
+            .setPosition(mSurfaceControl->get(), frame.left, frame.top)
             .apply();
 }
 
 void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
-    createTransaction(mSurfaceControl).setLayerStack(mSurfaceControl, stack).apply();
+    createTransaction(mSurfaceControl->get()).setLayerStack(mSurfaceControl->get(), stack).apply();
 }
 
 void RefreshRateOverlay::changeRefreshRate(Fps fps) {
     mCurrentFps = fps;
     const auto buffer = getOrCreateBuffers(fps)[mFrame];
-    createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply();
+    createTransaction(mSurfaceControl->get()).setBuffer(mSurfaceControl->get(), buffer).apply();
 }
 
 void RefreshRateOverlay::animate() {
@@ -312,7 +329,7 @@
     const auto& buffers = getOrCreateBuffers(*mCurrentFps);
     mFrame = (mFrame + 1) % buffers.size();
     const auto buffer = buffers[mFrame];
-    createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply();
+    createTransaction(mSurfaceControl->get()).setBuffer(mSurfaceControl->get(), buffer).apply();
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index a465a36..a2966e6 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -33,6 +33,20 @@
 
 class GraphicBuffer;
 class SurfaceControl;
+class SurfaceFlinger;
+
+// Helper class to delete the SurfaceControl on a helper thread as
+// SurfaceControl assumes its destruction happens without SurfaceFlinger::mStateLock held.
+class SurfaceControlHolder {
+public:
+    explicit SurfaceControlHolder(sp<SurfaceControl> sc) : mSurfaceControl(std::move(sc)){};
+    ~SurfaceControlHolder();
+
+    const sp<SurfaceControl>& get() const { return mSurfaceControl; }
+
+private:
+    sp<SurfaceControl> mSurfaceControl;
+};
 
 class RefreshRateOverlay {
 public:
@@ -75,7 +89,7 @@
     const FpsRange mFpsRange; // For color interpolation.
     const bool mShowSpinner;
 
-    const sp<SurfaceControl> mSurfaceControl;
+    const std::unique_ptr<SurfaceControlHolder> mSurfaceControl;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 747032b..4af1f5c 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -188,10 +188,10 @@
 
 VSyncSource::VSyncData DispSyncSource::getLatestVSyncData() const {
     std::lock_guard lock(mVsyncMutex);
-    nsecs_t expectedPresentTime = mVSyncTracker.nextAnticipatedVSyncTimeFrom(
+    nsecs_t expectedPresentationTime = mVSyncTracker.nextAnticipatedVSyncTimeFrom(
             systemTime() + mWorkDuration.get().count() + mReadyDuration.count());
-    nsecs_t deadline = expectedPresentTime - mWorkDuration.get().count() - mReadyDuration.count();
-    return {expectedPresentTime, deadline};
+    nsecs_t deadline = expectedPresentationTime - mReadyDuration.count();
+    return {expectedPresentationTime, deadline};
 }
 
 void DispSyncSource::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index ca83496..a48c921 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -40,22 +40,26 @@
 
 struct RefreshRateScore {
     DisplayModeIterator modeIt;
-    float score;
+    float overallScore;
+    struct {
+        float modeBelowThreshold;
+        float modeAboveThreshold;
+    } fixedRateBelowThresholdLayersScore;
 };
 
 template <typename Iterator>
 const DisplayModePtr& getMaxScoreRefreshRate(Iterator begin, Iterator end) {
     const auto it =
             std::max_element(begin, end, [](RefreshRateScore max, RefreshRateScore current) {
-                const auto& [modeIt, score] = current;
+                const auto& [modeIt, overallScore, _] = current;
 
                 std::string name = to_string(modeIt->second->getFps());
-                ALOGV("%s scores %.2f", name.c_str(), score);
+                ALOGV("%s scores %.2f", name.c_str(), overallScore);
 
-                ATRACE_INT(name.c_str(), static_cast<int>(std::round(score * 100)));
+                ATRACE_INT(name.c_str(), static_cast<int>(std::round(overallScore * 100)));
 
                 constexpr float kEpsilon = 0.0001f;
-                return score > max.score * (1 + kEpsilon);
+                return overallScore > max.overallScore * (1 + kEpsilon);
             });
 
     return it->modeIt->second;
@@ -151,31 +155,6 @@
     return {quotient, remainder};
 }
 
-bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer, Fps refreshRate) const {
-    using namespace fps_approx_ops;
-
-    switch (layer.vote) {
-        case LayerVoteType::ExplicitExactOrMultiple:
-        case LayerVoteType::Heuristic:
-            if (mConfig.frameRateMultipleThreshold != 0 &&
-                refreshRate >= Fps::fromValue(mConfig.frameRateMultipleThreshold) &&
-                layer.desiredRefreshRate < Fps::fromValue(mConfig.frameRateMultipleThreshold / 2)) {
-                // Don't vote high refresh rates past the threshold for layers with a low desired
-                // refresh rate. For example, desired 24 fps with 120 Hz threshold means no vote for
-                // 120 Hz, but desired 60 fps should have a vote.
-                return false;
-            }
-            break;
-        case LayerVoteType::ExplicitDefault:
-        case LayerVoteType::ExplicitExact:
-        case LayerVoteType::Max:
-        case LayerVoteType::Min:
-        case LayerVoteType::NoVote:
-            break;
-    }
-    return true;
-}
-
 float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(const LayerRequirement& layer,
                                                                     Fps refreshRate) const {
     constexpr float kScoreForFractionalPairs = .8f;
@@ -240,10 +219,6 @@
 
 float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate,
                                                     bool isSeamlessSwitch) const {
-    if (!isVoteAllowed(layer, refreshRate)) {
-        return 0;
-    }
-
     // Slightly prefer seamless switches.
     constexpr float kSeamedSwitchPenalty = 0.95f;
     const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
@@ -300,6 +275,7 @@
 auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers,
                                                   GlobalSignals signals) const
         -> std::pair<DisplayModePtr, GlobalSignals> {
+    using namespace fps_approx_ops;
     ATRACE_CALL();
     ALOGV("%s: %zu layers", __func__, layers.size());
 
@@ -409,7 +385,7 @@
 
         const auto weight = layer.weight;
 
-        for (auto& [modeIt, score] : scores) {
+        for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
             const auto& [id, mode] = *modeIt;
             const bool isSeamlessSwitch = mode->getGroup() == mActiveModeIt->second->getGroup();
 
@@ -451,18 +427,92 @@
                 continue;
             }
 
-            const auto layerScore =
+            const float layerScore =
                     calculateLayerScoreLocked(layer, mode->getFps(), isSeamlessSwitch);
-            ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
-                  to_string(mode->getFps()).c_str(), layerScore);
+            const float weightedLayerScore = weight * layerScore;
 
-            score += weight * layerScore;
+            // Layer with fixed source has a special consideration which depends on the
+            // mConfig.frameRateMultipleThreshold. We don't want these layers to score
+            // refresh rates above the threshold, but we also don't want to favor the lower
+            // ones by having a greater number of layers scoring them. Instead, we calculate
+            // the score independently for these layers and later decide which
+            // refresh rates to add it. For example, desired 24 fps with 120 Hz threshold should not
+            // score 120 Hz, but desired 60 fps should contribute to the score.
+            const bool fixedSourceLayer = [](LayerVoteType vote) {
+                switch (vote) {
+                    case LayerVoteType::ExplicitExactOrMultiple:
+                    case LayerVoteType::Heuristic:
+                        return true;
+                    case LayerVoteType::NoVote:
+                    case LayerVoteType::Min:
+                    case LayerVoteType::Max:
+                    case LayerVoteType::ExplicitDefault:
+                    case LayerVoteType::ExplicitExact:
+                        return false;
+                }
+            }(layer.vote);
+            const bool layerBelowThreshold = mConfig.frameRateMultipleThreshold != 0 &&
+                    layer.desiredRefreshRate <
+                            Fps::fromValue(mConfig.frameRateMultipleThreshold / 2);
+            if (fixedSourceLayer && layerBelowThreshold) {
+                const bool modeAboveThreshold =
+                        mode->getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold);
+                if (modeAboveThreshold) {
+                    ALOGV("%s gives %s fixed source (above threshold) score of %.4f",
+                          formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(),
+                          layerScore);
+                    fixedRateBelowThresholdLayersScore.modeAboveThreshold += weightedLayerScore;
+                } else {
+                    ALOGV("%s gives %s fixed source (below threshold) score of %.4f",
+                          formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(),
+                          layerScore);
+                    fixedRateBelowThresholdLayersScore.modeBelowThreshold += weightedLayerScore;
+                }
+            } else {
+                ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
+                      to_string(mode->getFps()).c_str(), layerScore);
+                overallScore += weightedLayerScore;
+            }
         }
     }
 
-    // Now that we scored all the refresh rates we need to pick the one that got the highest score.
-    // In case of a tie we will pick the higher refresh rate if any of the layers wanted Max,
-    // or the lower otherwise.
+    // We want to find the best refresh rate without the fixed source layers,
+    // so we could know whether we should add the modeAboveThreshold scores or not.
+    // If the best refresh rate is already above the threshold, it means that
+    // some non-fixed source layers already scored it, so we can just add the score
+    // for all fixed source layers, even the ones that are above the threshold.
+    const bool maxScoreAboveThreshold = [&] {
+        if (mConfig.frameRateMultipleThreshold == 0 || scores.empty()) {
+            return false;
+        }
+
+        const auto maxScoreIt =
+                std::max_element(scores.begin(), scores.end(),
+                                 [](RefreshRateScore max, RefreshRateScore current) {
+                                     const auto& [modeIt, overallScore, _] = current;
+                                     return overallScore > max.overallScore;
+                                 });
+        ALOGV("%s is the best refresh rate without fixed source layers. It is %s the threshold for "
+              "refresh rate multiples",
+              to_string(maxScoreIt->modeIt->second->getFps()).c_str(),
+              maxScoreAboveThreshold ? "above" : "below");
+        return maxScoreIt->modeIt->second->getFps() >=
+                Fps::fromValue(mConfig.frameRateMultipleThreshold);
+    }();
+
+    // Now we can add the fixed rate layers score
+    for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
+        overallScore += fixedRateBelowThresholdLayersScore.modeBelowThreshold;
+        if (maxScoreAboveThreshold) {
+            overallScore += fixedRateBelowThresholdLayersScore.modeAboveThreshold;
+        }
+        ALOGV("%s adjusted overallScore is %.4f", to_string(modeIt->second->getFps()).c_str(),
+              overallScore);
+    }
+
+    // Now that we scored all the refresh rates we need to pick the one that got the highest
+    // overallScore. In case of a tie we will pick the higher refresh rate if any of the layers
+    // wanted Max, or the lower otherwise.
     const DisplayModePtr& bestRefreshRate = maxVoteLayers > 0
             ? getMaxScoreRefreshRate(scores.rbegin(), scores.rend())
             : getMaxScoreRefreshRate(scores.begin(), scores.end());
@@ -471,7 +521,7 @@
         // If we never scored any layers, then choose the rate from the primary
         // range instead of picking a random score from the app range.
         if (std::all_of(scores.begin(), scores.end(),
-                        [](RefreshRateScore score) { return score.score == 0; })) {
+                        [](RefreshRateScore score) { return score.overallScore == 0; })) {
             const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup);
             ALOGV("layers not scored - choose %s", to_string(max->getFps()).c_str());
             return {max, kNoSignals};
@@ -575,7 +625,7 @@
             continue;
         }
 
-        for (auto& [_, score] : scores) {
+        for (auto& [_, score, _1] : scores) {
             score = 0;
         }
 
@@ -587,7 +637,7 @@
             LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault &&
                                 layer->vote != LayerVoteType::ExplicitExactOrMultiple &&
                                 layer->vote != LayerVoteType::ExplicitExact);
-            for (auto& [modeIt, score] : scores) {
+            for (auto& [modeIt, score, _] : scores) {
                 constexpr bool isSeamlessSwitch = true;
                 const auto layerScore = calculateLayerScoreLocked(*layer, modeIt->second->getFps(),
                                                                   isSeamlessSwitch);
@@ -605,7 +655,7 @@
 
         // If we never scored any layers, we don't have a preferred frame rate
         if (std::all_of(scores.begin(), scores.end(),
-                        [](RefreshRateScore score) { return score.score == 0; })) {
+                        [](RefreshRateScore score) { return score.overallScore == 0; })) {
             continue;
         }
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 05a8692..a79002e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -353,9 +353,6 @@
     const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
     bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
 
-    // Returns whether the layer is allowed to vote for the given refresh rate.
-    bool isVoteAllowed(const LayerRequirement&, Fps) const;
-
     // calculates a score for a layer. Used to determine the display refresh rate
     // and the frame rate override for certains applications.
     float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate,
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 37f0fec..727cb08 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -25,6 +25,7 @@
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
+#include <ftl/fake_guard.h>
 #include <gui/WindowInfo.h>
 #include <system/window.h>
 #include <ui/DisplayStatInfo.h>
@@ -94,9 +95,13 @@
 }
 
 void Scheduler::setRefreshRateConfigs(std::shared_ptr<RefreshRateConfigs> configs) {
+    // The current RefreshRateConfigs instance may outlive this call, so unbind its idle timer.
     {
-        // The current RefreshRateConfigs instance may outlive this call, so unbind its idle timer.
-        std::scoped_lock lock(mRefreshRateConfigsLock);
+        // mRefreshRateConfigsLock is not locked here to avoid the deadlock
+        // as the callback can attempt to acquire the lock before stopIdleTimer can finish
+        // the execution. It's safe to FakeGuard as main thread is the only thread that
+        // writes to the mRefreshRateConfigs.
+        ftl::FakeGuard guard(mRefreshRateConfigsLock);
         if (mRefreshRateConfigs) {
             mRefreshRateConfigs->stopIdleTimer();
             mRefreshRateConfigs->clearIdleTimerCallbacks();
@@ -554,11 +559,12 @@
     }
 }
 
-void Scheduler::setDisplayPowerState(bool normal) {
+void Scheduler::setDisplayPowerMode(hal::PowerMode powerMode) {
     {
         std::lock_guard<std::mutex> lock(mPolicyLock);
-        mPolicy.isDisplayPowerStateNormal = normal;
+        mPolicy.displayPowerMode = powerMode;
     }
+    mVsyncSchedule->getController().setDisplayPowerMode(powerMode);
 
     if (mDisplayPowerTimer) {
         mDisplayPowerTimer->reset();
@@ -706,7 +712,8 @@
     // If Display Power is not in normal operation we want to be in performance mode. When coming
     // back to normal mode, a grace period is given with DisplayPowerTimer.
     if (mDisplayPowerTimer &&
-        (!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) {
+        (mPolicy.displayPowerMode != hal::PowerMode::ON ||
+         mPolicy.displayPowerTimer == TimerState::Reset)) {
         constexpr GlobalSignals kNoSignals;
         return {configs->getMaxRefreshRateByPolicy(), kNoSignals};
     }
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 0c72124..a8043bf 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -186,7 +186,7 @@
     // Indicates that touch interaction is taking place.
     void onTouchHint();
 
-    void setDisplayPowerState(bool normal);
+    void setDisplayPowerMode(hal::PowerMode powerMode);
 
     VSyncDispatch& getVsyncDispatch() { return mVsyncSchedule->getDispatch(); }
 
@@ -325,7 +325,7 @@
         TimerState idleTimer = TimerState::Reset;
         TouchState touch = TouchState::Inactive;
         TimerState displayPowerTimer = TimerState::Expired;
-        bool isDisplayPowerStateNormal = true;
+        hal::PowerMode displayPowerMode = hal::PowerMode::ON;
 
         // Chosen display mode.
         DisplayModePtr mode;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 665a7ee..e23945d 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -147,6 +147,11 @@
         return false;
     }
 
+    if (mDisplayPowerMode == hal::PowerMode::DOZE ||
+        mDisplayPowerMode == hal::PowerMode::DOZE_SUSPEND) {
+        return true;
+    }
+
     if (!mLastHwVsync && !HwcVsyncPeriod) {
         return false;
     }
@@ -207,6 +212,11 @@
     return mMoreSamplesNeeded;
 }
 
+void VSyncReactor::setDisplayPowerMode(hal::PowerMode powerMode) {
+    std::scoped_lock lock(mMutex);
+    mDisplayPowerMode = powerMode;
+}
+
 void VSyncReactor::dump(std::string& result) const {
     std::lock_guard lock(mMutex);
     StringAppendF(&result, "VsyncReactor in use\n");
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 6a1950a..4501487 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -49,6 +49,8 @@
     bool addHwVsyncTimestamp(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
                              bool* periodFlushed) final;
 
+    void setDisplayPowerMode(hal::PowerMode powerMode) final;
+
     void dump(std::string& result) const final;
 
 private:
@@ -73,6 +75,8 @@
     std::optional<nsecs_t> mPeriodTransitioningTo GUARDED_BY(mMutex);
     std::optional<nsecs_t> mLastHwVsync GUARDED_BY(mMutex);
 
+    hal::PowerMode mDisplayPowerMode GUARDED_BY(mMutex) = hal::PowerMode::ON;
+
     const bool mSupportKernelIdleTimer = false;
 };
 
diff --git a/services/surfaceflinger/Scheduler/VsyncController.h b/services/surfaceflinger/Scheduler/VsyncController.h
index 59f6537..726a420 100644
--- a/services/surfaceflinger/Scheduler/VsyncController.h
+++ b/services/surfaceflinger/Scheduler/VsyncController.h
@@ -18,7 +18,10 @@
 
 #include <cstddef>
 #include <memory>
+#include <mutex>
 
+#include <DisplayHardware/HWComposer.h>
+#include <DisplayHardware/Hal.h>
 #include <ui/FenceTime.h>
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
@@ -70,6 +73,13 @@
      */
     virtual void setIgnorePresentFences(bool ignore) = 0;
 
+    /*
+     * Sets the primary display power mode to the controller.
+     *
+     * \param [in] powerMode
+     */
+    virtual void setDisplayPowerMode(hal::PowerMode powerMode) = 0;
+
     virtual void dump(std::string& result) const = 0;
 
 protected:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e9fbf6e..e228468 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -328,8 +328,9 @@
         mCompositionEngine(mFactory.createCompositionEngine()),
         mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
         mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
-        mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
         mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
+        mInternalDisplayDensity(
+                getDensityFromProperty("ro.sf.lcd_density", !mEmulatedDisplayDensity)),
         mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)),
         mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make(*this)) {
     ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
@@ -444,6 +445,11 @@
     }
 
     mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false);
+
+    // Power hint session mode, representing which hint(s) to send: early, late, or both)
+    mPowerHintSessionMode =
+            {.late = base::GetBoolProperty("debug.sf.send_late_power_session_hint"s, true),
+             .early = base::GetBoolProperty("debug.sf.send_early_power_session_hint"s, false)};
 }
 
 LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
@@ -1999,12 +2005,6 @@
 
 bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
         FTL_FAKE_GUARD(kMainThreadContext) {
-    // we set this once at the beginning of commit to ensure consistency throughout the whole frame
-    mPowerHintSessionData.sessionEnabled = mPowerAdvisor->usePowerHintSession();
-    if (mPowerHintSessionData.sessionEnabled) {
-        mPowerHintSessionData.commitStart = systemTime();
-    }
-
     // calculate the expected present time once and use the cached
     // value throughout this frame to make sure all layers are
     // seeing this same value.
@@ -2018,10 +2018,6 @@
     const nsecs_t lastScheduledPresentTime = mScheduledPresentTime;
     mScheduledPresentTime = expectedVsyncTime;
 
-    if (mPowerHintSessionData.sessionEnabled) {
-        mPowerAdvisor->setTargetWorkDuration(mExpectedPresentTime -
-                                             mPowerHintSessionData.commitStart);
-    }
     const auto vsyncIn = [&] {
         if (!ATRACE_ENABLED()) return 0.f;
         return (mExpectedPresentTime - systemTime()) / 1e6f;
@@ -2097,6 +2093,32 @@
         }
     }
 
+    // Save this once per commit + composite to ensure consistency
+    // TODO (b/240619471): consider removing active display check once AOD is fixed
+    const auto activeDisplay =
+            FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(mActiveDisplayToken));
+    mPowerHintSessionEnabled = mPowerAdvisor->usePowerHintSession() && activeDisplay &&
+            activeDisplay->getPowerMode() == hal::PowerMode::ON;
+    if (mPowerHintSessionEnabled) {
+        const auto& display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
+        // get stable vsync period from display mode
+        const nsecs_t vsyncPeriod = display->getActiveMode()->getVsyncPeriod();
+        mPowerAdvisor->setCommitStart(frameTime);
+        mPowerAdvisor->setExpectedPresentTime(mExpectedPresentTime);
+        const nsecs_t idealSfWorkDuration =
+                mVsyncModulator->getVsyncConfig().sfWorkDuration.count();
+        // Frame delay is how long we should have minus how long we actually have
+        mPowerAdvisor->setFrameDelay(idealSfWorkDuration - (mExpectedPresentTime - frameTime));
+        mPowerAdvisor->setTotalFrameTargetWorkDuration(idealSfWorkDuration);
+        mPowerAdvisor->setTargetWorkDuration(vsyncPeriod);
+
+        // Send early hint here to make sure there's not another frame pending
+        if (mPowerHintSessionMode.early) {
+            // Send a rough prediction for this frame based on last frame's timing info
+            mPowerAdvisor->sendPredictedWorkDuration();
+        }
+    }
+
     if (mTracingEnabledChanged) {
         mLayerTracingEnabled = mLayerTracing.isEnabled();
         mTracingEnabledChanged = false;
@@ -2173,16 +2195,15 @@
         FTL_FAKE_GUARD(kMainThreadContext) {
     ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId);
 
-    if (mPowerHintSessionData.sessionEnabled) {
-        mPowerHintSessionData.compositeStart = systemTime();
-    }
-
     compositionengine::CompositionRefreshArgs refreshArgs;
     const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays);
     refreshArgs.outputs.reserve(displays.size());
+    std::vector<DisplayId> displayIds;
     for (const auto& [_, display] : displays) {
         refreshArgs.outputs.push_back(display->getCompositionDisplay());
+        displayIds.push_back(display->getId());
     }
+    mPowerAdvisor->setDisplays(displayIds);
     mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
         if (auto layerFE = layer->getCompositionEngineLayerFE())
             refreshArgs.layers.push_back(layerFE);
@@ -2230,12 +2251,17 @@
 
     mCompositionEngine->present(refreshArgs);
 
-    if (mPowerHintSessionData.sessionEnabled) {
-        mPowerHintSessionData.presentEnd = systemTime();
-    }
-
     mTimeStats->recordFrameDuration(frameTime, systemTime());
 
+    // Send a power hint hint after presentation is finished
+    if (mPowerHintSessionEnabled) {
+        mPowerAdvisor->setSfPresentTiming(mPreviousPresentFences[0].fenceTime->getSignalTime(),
+                                          systemTime());
+        if (mPowerHintSessionMode.late) {
+            mPowerAdvisor->sendActualWorkDuration();
+        }
+    }
+
     if (mScheduler->onPostComposition(presentTime)) {
         scheduleComposite(FrameHint::kNone);
     }
@@ -2280,11 +2306,8 @@
         scheduleCommit(FrameHint::kNone);
     }
 
-    // calculate total render time for performance hinting if adpf cpu hint is enabled,
-    if (mPowerHintSessionData.sessionEnabled) {
-        const nsecs_t flingerDuration =
-                (mPowerHintSessionData.presentEnd - mPowerHintSessionData.commitStart);
-        mPowerAdvisor->sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd);
+    if (mPowerHintSessionEnabled) {
+        mPowerAdvisor->setCompositeEnd(systemTime());
     }
 }
 
@@ -2878,7 +2901,8 @@
     ALOGV("Display Orientation: %s", toCString(creationArgs.physicalOrientation));
 
     // virtual displays are always considered enabled
-    creationArgs.initialPowerMode = state.isVirtual() ? hal::PowerMode::ON : hal::PowerMode::OFF;
+    creationArgs.initialPowerMode =
+            state.isVirtual() ? std::make_optional(hal::PowerMode::ON) : std::nullopt;
 
     sp<DisplayDevice> display = getFactory().createDisplayDevice(creationArgs);
 
@@ -3321,11 +3345,11 @@
     mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
         if (!layer->needsInputInfo()) return;
 
-        // Do not create WindowInfos for windows on displays that cannot receive input.
-        if (const auto opt = displayInputInfos.get(layer->getLayerStack())) {
-            const auto& info = opt->get();
-            outWindowInfos.push_back(layer->fillInputInfo(info.transform, info.isSecure));
-        }
+        const auto opt = displayInputInfos.get(layer->getLayerStack(),
+                                               [](const auto& info) -> Layer::InputDisplayArgs {
+                                                   return {&info.transform, info.isSecure};
+                                               });
+        outWindowInfos.push_back(layer->fillInputInfo(opt.value_or(Layer::InputDisplayArgs{})));
     });
 
     sNumWindowInfos = outWindowInfos.size();
@@ -4859,8 +4883,8 @@
     const auto displayId = display->getPhysicalId();
     ALOGD("Setting power mode %d on display %s", mode, to_string(displayId).c_str());
 
-    const hal::PowerMode currentMode = display->getPowerMode();
-    if (mode == currentMode) {
+    std::optional<hal::PowerMode> currentMode = display->getPowerMode();
+    if (currentMode.has_value() && mode == *currentMode) {
         return;
     }
 
@@ -4876,7 +4900,7 @@
         mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode));
     }
     const auto refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
-    if (currentMode == hal::PowerMode::OFF) {
+    if (*currentMode == hal::PowerMode::OFF) {
         // Turn on the display
         if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) {
             onActiveDisplayChangedLocked(display);
@@ -4907,7 +4931,7 @@
         if (SurfaceFlinger::setSchedAttr(false) != NO_ERROR) {
             ALOGW("Couldn't set uclamp.min on display off: %s\n", strerror(errno));
         }
-        if (isDisplayActiveLocked(display) && currentMode != hal::PowerMode::DOZE_SUSPEND) {
+        if (isDisplayActiveLocked(display) && *currentMode != hal::PowerMode::DOZE_SUSPEND) {
             mScheduler->disableHardwareVsync(true);
             mScheduler->onScreenReleased(mAppConnectionHandle);
         }
@@ -4921,7 +4945,7 @@
     } else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) {
         // Update display while dozing
         getHwComposer().setPowerMode(displayId, mode);
-        if (isDisplayActiveLocked(display) && currentMode == hal::PowerMode::DOZE_SUSPEND) {
+        if (isDisplayActiveLocked(display) && *currentMode == hal::PowerMode::DOZE_SUSPEND) {
             mScheduler->onScreenAcquired(mAppConnectionHandle);
             mScheduler->resyncToHardwareVsync(true, refreshRate);
         }
@@ -4940,7 +4964,7 @@
     if (isDisplayActiveLocked(display)) {
         mTimeStats->setPowerMode(mode);
         mRefreshRateStats->setPowerMode(mode);
-        mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON);
+        mScheduler->setDisplayPowerMode(mode);
     }
 
     ALOGD("Finished setting power mode %d on display %s", mode, to_string(displayId).c_str());
@@ -4993,6 +5017,25 @@
 
         const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
 
+        // Traversal of drawing state must happen on the main thread.
+        // Otherwise, SortedVector may have shared ownership during concurrent
+        // traversals, which can result in use-after-frees.
+        std::string compositionLayers;
+        mScheduler
+                ->schedule([&] {
+                    StringAppendF(&compositionLayers, "Composition layers\n");
+                    mDrawingState.traverseInZOrder([&](Layer* layer) {
+                        auto* compositionState = layer->getCompositionState();
+                        if (!compositionState || !compositionState->isVisible) return;
+
+                        android::base::StringAppendF(&compositionLayers, "* Layer %p (%s)\n", layer,
+                                                     layer->getDebugName() ? layer->getDebugName()
+                                                                           : "<unknown>");
+                        compositionState->dump(compositionLayers);
+                    });
+                })
+                .get();
+
         bool dumpLayers = true;
         {
             TimedLock lock(mStateLock, s2ns(1), __func__);
@@ -5005,7 +5048,7 @@
                 (it->second)(args, asProto, result);
                 dumpLayers = false;
             } else if (!asProto) {
-                dumpAllLocked(args, result);
+                dumpAllLocked(args, compositionLayers, result);
             }
         }
 
@@ -5304,7 +5347,8 @@
     result.append(future.get());
 }
 
-void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
+void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& compositionLayers,
+                                   std::string& result) const {
     const bool colorize = !args.empty() && args[0] == String16("--color");
     Colorizer colorizer(colorize);
 
@@ -5355,18 +5399,7 @@
     StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers.load());
     colorizer.reset(result);
 
-    {
-        StringAppendF(&result, "Composition layers\n");
-        mDrawingState.traverseInZOrder([&](Layer* layer) {
-            auto* compositionState = layer->getCompositionState();
-            if (!compositionState || !compositionState->isVisible) return;
-
-            android::base::StringAppendF(&result, "* Layer %p (%s)\n", layer,
-                                         layer->getDebugName() ? layer->getDebugName()
-                                                               : "<unknown>");
-            compositionState->dump(result);
-        });
-    }
+    result.append(compositionLayers);
 
     colorizer.bold(result);
     StringAppendF(&result, "Displays (%zu entries)\n", mDisplays.size());
@@ -6631,8 +6664,13 @@
                                              1 /* layerCount */, usage, "screenshot");
 
     const status_t bufferStatus = buffer->initCheck();
-    LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d",
-                        bufferStatus);
+    if (bufferStatus != OK) {
+        // Animations may end up being really janky, but don't crash here.
+        // Otherwise an irreponsible process may cause an SF crash by allocating
+        // too much.
+        ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus);
+        return ftl::yield<FenceResult>(base::unexpected(bufferStatus)).share();
+    }
     const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared<
             renderengine::impl::ExternalTexture>(buffer, getRenderEngine(),
                                                  renderengine::impl::ExternalTexture::Usage::
@@ -6906,9 +6944,7 @@
         return NO_ERROR;
     }
 
-    status_t setPolicyResult = overridePolicy
-            ? display->refreshRateConfigs().setOverridePolicy(policy)
-            : display->refreshRateConfigs().setDisplayManagerPolicy(*policy);
+    const status_t setPolicyResult = display->setRefreshRatePolicy(policy, overridePolicy);
     if (setPolicyResult < 0) {
         return BAD_VALUE;
     }
@@ -7564,7 +7600,7 @@
     IPCThreadState* ipc = IPCThreadState::self();
     const int pid = ipc->getCallingPid();
     const int uid = ipc->getCallingUid();
-    if ((uid != AID_GRAPHICS) &&
+    if ((uid != AID_GRAPHICS) && (uid != AID_SYSTEM) &&
         !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) {
         ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid);
         return PERMISSION_DENIED;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 46f0e6b..02846fe 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1085,7 +1085,8 @@
     /*
      * Debugging & dumpsys
      */
-    void dumpAllLocked(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock);
+    void dumpAllLocked(const DumpArgs& args, const std::string& compositionLayers,
+                       std::string& result) const REQUIRES(mStateLock);
 
     void appendSfConfigString(std::string& result) const;
     void listLayersLocked(std::string& result) const;
@@ -1374,8 +1375,8 @@
     sp<TunnelModeEnabledReporter> mTunnelModeEnabledReporter;
     ui::DisplayPrimaries mInternalDisplayPrimaries;
 
-    const float mInternalDisplayDensity;
     const float mEmulatedDisplayDensity;
+    const float mInternalDisplayDensity;
 
     // Should only be accessed by the main thread.
     sp<os::IInputFlinger> mInputFlinger;
@@ -1436,12 +1437,12 @@
         return mScheduler->getLayerFramerate(now, id);
     }
 
+    bool mPowerHintSessionEnabled;
+
     struct {
-        bool sessionEnabled = false;
-        nsecs_t commitStart;
-        nsecs_t compositeStart;
-        nsecs_t presentEnd;
-    } mPowerHintSessionData GUARDED_BY(kMainThreadContext);
+        bool late = false;
+        bool early = false;
+    } mPowerHintSessionMode;
 
     nsecs_t mAnimationTransactionTimeout = s2ns(5);
 
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index ceddf27..507601b 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -63,7 +63,7 @@
         "android.hardware.graphics.composer@2.1",
     ],
     shared_libs: [
-        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.graphics.common-V4-ndk",
         "android.hardware.graphics.common@1.2",
         "libandroid",
         "libbase",
diff --git a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
index 9ab35d7..53de4a6 100644
--- a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
+++ b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
@@ -52,6 +52,8 @@
     void verifyAndClearExpectations();
     void sendActualWorkDurationGroup(std::vector<WorkDuration> durations,
                                      std::chrono::nanoseconds sleepBeforeLastSend);
+    std::chrono::nanoseconds mAllowedDeviation;
+    std::chrono::nanoseconds mStaleTimeout;
 };
 
 void AidlPowerHalWrapperTest::SetUp() {
@@ -59,6 +61,9 @@
     mMockSession = new NiceMock<MockIPowerHintSession>();
     ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)).WillByDefault(Return(Status::ok()));
     mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal);
+    mWrapper->setAllowedActualDeviation(std::chrono::nanoseconds{10ms}.count());
+    mAllowedDeviation = std::chrono::nanoseconds{mWrapper->mAllowedActualDeviation};
+    mStaleTimeout = AidlPowerHalWrapper::kStaleTimeout;
 }
 
 void AidlPowerHalWrapperTest::verifyAndClearExpectations() {
@@ -76,6 +81,7 @@
         mWrapper->sendActualWorkDuration(duration.durationNanos, duration.timeStampNanos);
     }
 }
+
 WorkDuration toWorkDuration(std::chrono::nanoseconds durationNanos, int64_t timeStampNanos) {
     WorkDuration duration;
     duration.durationNanos = durationNanos.count();
@@ -83,6 +89,10 @@
     return duration;
 }
 
+WorkDuration toWorkDuration(std::pair<std::chrono::nanoseconds, nsecs_t> timePair) {
+    return toWorkDuration(timePair.first, timePair.second);
+}
+
 std::string printWorkDurations(const ::std::vector<WorkDuration>& durations) {
     std::ostringstream os;
     for (auto duration : durations) {
@@ -112,7 +122,7 @@
     EXPECT_FALSE(mWrapper->startPowerHintSession());
 }
 
-TEST_F(AidlPowerHalWrapperTest, restartNewPoserHintSessionWithNewThreadIds) {
+TEST_F(AidlPowerHalWrapperTest, restartNewPowerHintSessionWithNewThreadIds) {
     ASSERT_TRUE(mWrapper->supportsPowerHintSession());
 
     std::vector<int32_t> threadIds = {1, 2};
@@ -149,12 +159,8 @@
 
     std::chrono::nanoseconds base = 100ms;
     // test cases with target work duration and whether it should update hint against baseline 100ms
-    const std::vector<std::pair<std::chrono::nanoseconds, bool>> testCases = {{0ms, false},
-                                                                              {-1ms, false},
-                                                                              {200ms, true},
-                                                                              {2ms, true},
-                                                                              {91ms, false},
-                                                                              {109ms, false}};
+    const std::vector<std::pair<std::chrono::nanoseconds, bool>> testCases =
+            {{0ms, true}, {-1ms, true}, {200ms, true}, {2ms, true}, {100ms, false}, {109ms, true}};
 
     for (const auto& test : testCases) {
         // reset to 100ms baseline
@@ -200,21 +206,21 @@
     // 100ms
     const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
             testCases = {{{{-1ms, 100}}, false},
-                         {{{91ms, 100}}, false},
-                         {{{109ms, 100}}, false},
+                         {{{100ms - (mAllowedDeviation / 2), 100}}, false},
+                         {{{100ms + (mAllowedDeviation / 2), 100}}, false},
+                         {{{100ms + (mAllowedDeviation + 1ms), 100}}, true},
+                         {{{100ms - (mAllowedDeviation + 1ms), 100}}, true},
                          {{{100ms, 100}, {200ms, 200}}, true},
                          {{{100ms, 500}, {100ms, 600}, {3ms, 600}}, true}};
 
     for (const auto& test : testCases) {
         // reset actual duration
-        sendActualWorkDurationGroup({base}, 80ms);
+        sendActualWorkDurationGroup({base}, mStaleTimeout);
 
         auto raw = test.first;
         std::vector<WorkDuration> durations(raw.size());
         std::transform(raw.begin(), raw.end(), durations.begin(),
-                       [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
-                           return toWorkDuration(d.first, d.second);
-                       });
+                       [](auto d) { return toWorkDuration(d); });
         EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
                 .Times(test.second ? 1 : 0);
         sendActualWorkDurationGroup(durations, 0ms);
@@ -222,40 +228,6 @@
     }
 }
 
-TEST_F(AidlPowerHalWrapperTest, sendAdjustedActualWorkDuration) {
-    ASSERT_TRUE(mWrapper->supportsPowerHintSession());
-
-    std::vector<int32_t> threadIds = {1, 2};
-    mWrapper->setPowerHintSessionThreadIds(threadIds);
-    EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
-            .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
-    ASSERT_TRUE(mWrapper->startPowerHintSession());
-    verifyAndClearExpectations();
-
-    std::chrono::nanoseconds lastTarget = 100ms;
-    EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(lastTarget.count())).Times(1);
-    mWrapper->setTargetWorkDuration(lastTarget.count());
-    std::chrono::nanoseconds newTarget = 105ms;
-    mWrapper->setTargetWorkDuration(newTarget.count());
-    EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(newTarget.count())).Times(0);
-    std::chrono::nanoseconds actual = 21ms;
-    // 100 / 105 * 21ms = 20ms
-    std::chrono::nanoseconds expectedActualSent = 20ms;
-    std::vector<WorkDuration> expectedDurations = {toWorkDuration(expectedActualSent, 1)};
-
-    EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_))
-            .WillOnce(DoAll(
-                    [expectedDurations](const ::std::vector<WorkDuration>& durationsSent) {
-                        EXPECT_EQ(expectedDurations, durationsSent)
-                                << base::StringPrintf("actual sent: %s vs expected: %s",
-                                                      printWorkDurations(durationsSent).c_str(),
-                                                      printWorkDurations(expectedDurations)
-                                                              .c_str());
-                    },
-                    Return(Status::ok())));
-    mWrapper->sendActualWorkDuration(actual.count(), 1);
-}
-
 TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_exceedsStaleTime) {
     ASSERT_TRUE(mWrapper->supportsPowerHintSession());
 
@@ -269,22 +241,23 @@
     auto base = toWorkDuration(100ms, 0);
     // test cases with actual work durations and whether it should update hint against baseline
     // 100ms
-    const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
-            testCases = {{{{91ms, 100}}, true}, {{{109ms, 100}}, true}};
+    const std::vector<std::tuple<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>,
+                                 std::chrono::nanoseconds, bool>>
+            testCases = {{{{100ms, 100}}, mStaleTimeout, true},
+                         {{{100ms + (mAllowedDeviation / 2), 100}}, mStaleTimeout, true},
+                         {{{100ms, 100}}, mStaleTimeout / 2, false}};
 
     for (const auto& test : testCases) {
         // reset actual duration
-        sendActualWorkDurationGroup({base}, 80ms);
+        sendActualWorkDurationGroup({base}, mStaleTimeout);
 
-        auto raw = test.first;
+        auto raw = std::get<0>(test);
         std::vector<WorkDuration> durations(raw.size());
         std::transform(raw.begin(), raw.end(), durations.begin(),
-                       [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
-                           return toWorkDuration(d.first, d.second);
-                       });
+                       [](auto d) { return toWorkDuration(d); });
         EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
-                .Times(test.second ? 1 : 0);
-        sendActualWorkDurationGroup(durations, 80ms);
+                .Times(std::get<2>(test) ? 1 : 0);
+        sendActualWorkDurationGroup(durations, std::get<1>(test));
         verifyAndClearExpectations();
     }
 }
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 7823363..339d746 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -24,6 +24,7 @@
 filegroup {
     name: "libsurfaceflinger_mock_sources",
     srcs: [
+        "mock/DisplayHardware/MockAidlPowerHalWrapper.cpp",
         "mock/DisplayHardware/MockComposer.cpp",
         "mock/DisplayHardware/MockHWC2.cpp",
         "mock/DisplayHardware/MockIPower.cpp",
@@ -95,6 +96,7 @@
         "LayerTest.cpp",
         "LayerTestUtils.cpp",
         "MessageQueueTest.cpp",
+        "PowerAdvisorTest.cpp",
         "SurfaceFlinger_CreateDisplayTest.cpp",
         "SurfaceFlinger_DestroyDisplayTest.cpp",
         "SurfaceFlinger_DisplayModeSwitching.cpp",
@@ -136,7 +138,7 @@
     static_libs: [
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
-        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.graphics.common-V4-ndk",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index ec27eda..67ace1a 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -292,9 +292,10 @@
 
 TEST_F(DispSyncSourceTest, getLatestVsyncData) {
     const nsecs_t now = systemTime();
-    const nsecs_t vsyncInternalDuration = mWorkDuration.count() + mReadyDuration.count();
+    const nsecs_t expectedPresentationTime =
+            now + mWorkDuration.count() + mReadyDuration.count() + 1;
     EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_))
-            .WillOnce(Return(now + vsyncInternalDuration + 1));
+            .WillOnce(Return(expectedPresentationTime));
     {
         InSequence seq;
         EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
@@ -306,10 +307,8 @@
     EXPECT_TRUE(mDispSyncSource);
 
     const auto vsyncData = mDispSyncSource->getLatestVSyncData();
-    ASSERT_GT(vsyncData.deadlineTimestamp, now);
-    ASSERT_GT(vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp);
-    EXPECT_EQ(vsyncData.deadlineTimestamp,
-              vsyncData.expectedPresentationTime - vsyncInternalDuration);
+    ASSERT_EQ(vsyncData.expectedPresentationTime, expectedPresentationTime);
+    EXPECT_EQ(vsyncData.deadlineTimestamp, expectedPresentationTime - mReadyDuration.count());
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
new file mode 100644
index 0000000..8711a42
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 LOG_TAG
+#define LOG_TAG "PowerAdvisorTest"
+
+#include <DisplayHardware/PowerAdvisor.h>
+#include <compositionengine/Display.h>
+#include <ftl/fake_guard.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <ui/DisplayId.h>
+#include <chrono>
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockAidlPowerHalWrapper.h"
+
+using namespace android;
+using namespace android::Hwc2::mock;
+using namespace android::hardware::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+namespace android::Hwc2::impl {
+
+class PowerAdvisorTest : public testing::Test {
+public:
+    void SetUp() override;
+    void startPowerHintSession();
+    void fakeBasicFrameTiming(nsecs_t startTime, nsecs_t vsyncPeriod);
+    void setExpectedTiming(nsecs_t startTime, nsecs_t vsyncPeriod);
+    nsecs_t getFenceWaitDelayDuration(bool skipValidate);
+
+protected:
+    TestableSurfaceFlinger mFlinger;
+    std::unique_ptr<PowerAdvisor> mPowerAdvisor;
+    NiceMock<MockAidlPowerHalWrapper>* mMockAidlWrapper;
+    nsecs_t kErrorMargin = std::chrono::nanoseconds(1ms).count();
+};
+
+void PowerAdvisorTest::SetUp() FTL_FAKE_GUARD(mPowerAdvisor->mPowerHalMutex) {
+    std::unique_ptr<MockAidlPowerHalWrapper> mockAidlWrapper =
+            std::make_unique<NiceMock<MockAidlPowerHalWrapper>>();
+    mPowerAdvisor = std::make_unique<PowerAdvisor>(*mFlinger.flinger());
+    ON_CALL(*mockAidlWrapper.get(), supportsPowerHintSession()).WillByDefault(Return(true));
+    ON_CALL(*mockAidlWrapper.get(), startPowerHintSession()).WillByDefault(Return(true));
+    mPowerAdvisor->mHalWrapper = std::move(mockAidlWrapper);
+    mMockAidlWrapper =
+            reinterpret_cast<NiceMock<MockAidlPowerHalWrapper>*>(mPowerAdvisor->mHalWrapper.get());
+}
+
+void PowerAdvisorTest::startPowerHintSession() {
+    const std::vector<int32_t> threadIds = {1, 2, 3};
+    mPowerAdvisor->enablePowerHint(true);
+    mPowerAdvisor->startPowerHintSession(threadIds);
+}
+
+void PowerAdvisorTest::setExpectedTiming(nsecs_t totalFrameTarget, nsecs_t expectedPresentTime) {
+    mPowerAdvisor->setTotalFrameTargetWorkDuration(totalFrameTarget);
+    mPowerAdvisor->setExpectedPresentTime(expectedPresentTime);
+}
+
+void PowerAdvisorTest::fakeBasicFrameTiming(nsecs_t startTime, nsecs_t vsyncPeriod) {
+    mPowerAdvisor->setCommitStart(startTime);
+    mPowerAdvisor->setFrameDelay(0);
+    mPowerAdvisor->setTargetWorkDuration(vsyncPeriod);
+}
+
+nsecs_t PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) {
+    return (skipValidate ? PowerAdvisor::kFenceWaitStartDelaySkippedValidate
+                         : PowerAdvisor::kFenceWaitStartDelayValidated)
+            .count();
+}
+
+namespace {
+
+TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) {
+    mPowerAdvisor->onBootFinished();
+    startPowerHintSession();
+
+    std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
+
+    // 60hz
+    const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60;
+    const nsecs_t presentDuration = std::chrono::nanoseconds(5ms).count();
+    const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count();
+
+    nsecs_t startTime = 100;
+
+    // advisor only starts on frame 2 so do an initial no-op frame
+    fakeBasicFrameTiming(startTime, vsyncPeriod);
+    setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
+    mPowerAdvisor->setDisplays(displayIds);
+    mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
+    mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
+
+    // increment the frame
+    startTime += vsyncPeriod;
+
+    const nsecs_t expectedDuration = kErrorMargin + presentDuration + postCompDuration;
+    EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1);
+
+    fakeBasicFrameTiming(startTime, vsyncPeriod);
+    setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
+    mPowerAdvisor->setDisplays(displayIds);
+    mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000);
+    mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 2500000);
+    mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
+    mPowerAdvisor->sendActualWorkDuration();
+}
+
+TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) {
+    mPowerAdvisor->onBootFinished();
+    startPowerHintSession();
+
+    std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
+
+    // 60hz
+    const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60;
+    const nsecs_t presentDuration = std::chrono::nanoseconds(5ms).count();
+    const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count();
+    const nsecs_t hwcBlockedDuration = std::chrono::nanoseconds(500us).count();
+
+    nsecs_t startTime = 100;
+
+    // advisor only starts on frame 2 so do an initial no-op frame
+    fakeBasicFrameTiming(startTime, vsyncPeriod);
+    setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
+    mPowerAdvisor->setDisplays(displayIds);
+    mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
+    mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
+
+    // increment the frame
+    startTime += vsyncPeriod;
+
+    const nsecs_t expectedDuration = kErrorMargin + presentDuration +
+            getFenceWaitDelayDuration(false) - hwcBlockedDuration + postCompDuration;
+    EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1);
+
+    fakeBasicFrameTiming(startTime, vsyncPeriod);
+    setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
+    mPowerAdvisor->setDisplays(displayIds);
+    mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000);
+    mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 3000000);
+    // now report the fence as having fired during the display HWC time
+    mPowerAdvisor->setSfPresentTiming(startTime + 2000000 + hwcBlockedDuration,
+                                      startTime + presentDuration);
+    mPowerAdvisor->sendActualWorkDuration();
+}
+
+TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) {
+    mPowerAdvisor->onBootFinished();
+    startPowerHintSession();
+
+    std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u), GpuVirtualDisplayId(0),
+                                      GpuVirtualDisplayId(1)};
+
+    // 60hz
+    const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60;
+    // make present duration much later than the hwc display by itself will account for
+    const nsecs_t presentDuration = std::chrono::nanoseconds(10ms).count();
+    const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count();
+
+    nsecs_t startTime = 100;
+
+    // advisor only starts on frame 2 so do an initial no-op frame
+    fakeBasicFrameTiming(startTime, vsyncPeriod);
+    setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
+    mPowerAdvisor->setDisplays(displayIds);
+    mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
+    mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
+
+    // increment the frame
+    startTime += vsyncPeriod;
+
+    const nsecs_t expectedDuration = kErrorMargin + presentDuration + postCompDuration;
+    EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1);
+
+    fakeBasicFrameTiming(startTime, vsyncPeriod);
+    setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
+    mPowerAdvisor->setDisplays(displayIds);
+
+    // don't report timing for the gpu displays since they don't use hwc
+    mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000);
+    mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 2500000);
+    mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
+    mPowerAdvisor->sendActualWorkDuration();
+}
+
+} // namespace
+} // namespace android::Hwc2::impl
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index fcde532..188fd58 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -564,9 +564,10 @@
     TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60,
                                        {.frameRateMultipleThreshold = 120});
 
-    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}, {.weight = 1.f}};
     auto& lr1 = layers[0];
     auto& lr2 = layers[1];
+    auto& lr3 = layers[2];
 
     lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitDefault;
@@ -639,6 +640,48 @@
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.name = "90Hz ExplicitExactOrMultiple";
     EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
+
+    lr1.desiredRefreshRate = 24_Hz;
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.name = "24Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::Max;
+    lr2.name = "Max";
+    EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+    lr1.desiredRefreshRate = 24_Hz;
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.name = "24Hz ExplicitExactOrMultiple";
+    lr2.desiredRefreshRate = 120_Hz;
+    lr2.vote = LayerVoteType::ExplicitDefault;
+    lr2.name = "120Hz ExplicitDefault";
+    EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+    lr1.desiredRefreshRate = 24_Hz;
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.name = "24Hz ExplicitExactOrMultiple";
+    lr2.desiredRefreshRate = 120_Hz;
+    lr2.vote = LayerVoteType::ExplicitExact;
+    lr2.name = "120Hz ExplicitExact";
+    EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+    lr1.desiredRefreshRate = 10_Hz;
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.name = "30Hz ExplicitExactOrMultiple";
+    lr2.desiredRefreshRate = 120_Hz;
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.name = "120Hz ExplicitExact";
+    EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+    lr1.desiredRefreshRate = 30_Hz;
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.name = "30Hz ExplicitExactOrMultiple";
+    lr2.desiredRefreshRate = 30_Hz;
+    lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr2.name = "30Hz ExplicitExactOrMultiple";
+    lr3.vote = LayerVoteType::Heuristic;
+    lr3.desiredRefreshRate = 120_Hz;
+    lr3.name = "120Hz Heuristic";
+    EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) {
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index aab2795..93c809e 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -159,8 +159,8 @@
     mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
     ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
 
-    constexpr bool kPowerStateNormal = true;
-    mScheduler->setDisplayPowerState(kPowerStateNormal);
+    constexpr hal::PowerMode kPowerModeOn = hal::PowerMode::ON;
+    mScheduler->setDisplayPowerMode(kPowerModeOn);
 
     constexpr uint32_t kDisplayArea = 999'999;
     mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
@@ -226,8 +226,8 @@
 
     mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
 
-    constexpr bool kPowerStateNormal = true;
-    mScheduler->setDisplayPowerState(kPowerStateNormal);
+    constexpr hal::PowerMode kPowerModeOn = hal::PowerMode::ON;
+    mScheduler->setDisplayPowerMode(kPowerModeOn);
 
     constexpr uint32_t kDisplayArea = 999'999;
     mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
index 8de9e4b..2c9888d 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
@@ -74,6 +74,7 @@
     mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
     mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
     mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+    mFlinger.setPowerHintSessionMode(true, true);
     mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor));
     static constexpr bool kIsPrimary = true;
     FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, hal::DisplayType::PHYSICAL, kIsPrimary)
@@ -96,6 +97,7 @@
                     .setNativeWindow(mNativeWindow)
                     .setPowerMode(hal::PowerMode::ON)
                     .inject();
+    mFlinger.mutableActiveDisplayToken() = mDisplay->getDisplayToken();
 }
 
 void SurfaceFlingerPowerHintTest::setupScheduler() {
@@ -142,10 +144,30 @@
                 std::this_thread::sleep_for(mockHwcRunTime);
                 return hardware::graphics::composer::V2_1::Error::NONE;
             });
-    EXPECT_CALL(*mPowerAdvisor,
-                sendActualWorkDuration(Gt(mockHwcRunTime.count()),
-                                       Gt(now + mockHwcRunTime.count())))
+    EXPECT_CALL(*mPowerAdvisor, sendActualWorkDuration()).Times(1);
+    static constexpr bool kVsyncId = 123; // arbitrary
+    mFlinger.commitAndComposite(now, kVsyncId, now + mockVsyncPeriod.count());
+}
+
+TEST_F(SurfaceFlingerPowerHintTest, inactiveOnDisplayDoze) {
+    ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true));
+
+    mDisplay->setPowerMode(hal::PowerMode::DOZE);
+
+    const std::chrono::nanoseconds mockVsyncPeriod = 15ms;
+    EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(_)).Times(0);
+
+    const nsecs_t now = systemTime();
+    const std::chrono::nanoseconds mockHwcRunTime = 20ms;
+    EXPECT_CALL(*mDisplaySurface,
+                prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc))
             .Times(1);
+    EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _))
+            .WillOnce([mockHwcRunTime] {
+                std::this_thread::sleep_for(mockHwcRunTime);
+                return hardware::graphics::composer::V2_1::Error::NONE;
+            });
+    EXPECT_CALL(*mPowerAdvisor, sendActualWorkDuration()).Times(0);
     static constexpr bool kVsyncId = 123; // arbitrary
     mFlinger.commitAndComposite(now, kVsyncId, now + mockVsyncPeriod.count());
 }
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index f1a69fb..283f9ca 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -330,6 +330,10 @@
         layer->mDrawingParent = drawingParent;
     }
 
+    void setPowerHintSessionMode(bool early, bool late) {
+        mFlinger->mPowerHintSessionMode = {.late = late, .early = early};
+    }
+
     /* ------------------------------------------------------------------------
      * Forwarding for functions being tested
      */
@@ -741,6 +745,7 @@
                 mHwcDisplayId(hwcDisplayId) {
             mCreationArgs.connectionType = connectionType;
             mCreationArgs.isPrimary = isPrimary;
+            mCreationArgs.initialPowerMode = hal::PowerMode::ON;
         }
 
         sp<IBinder> token() const { return mDisplayToken; }
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 4eb9055..30a3f9a 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -349,6 +349,23 @@
     }
 }
 
+TEST_F(VSyncReactorTest, addHwVsyncTimestampDozePreempt) {
+    bool periodFlushed = false;
+    nsecs_t const newPeriod = 4000;
+
+    mReactor.startPeriodTransition(newPeriod);
+
+    auto time = 0;
+    // If the power mode is not DOZE or DOZE_SUSPEND, it is still collecting timestamps.
+    EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+
+    // Set power mode to DOZE to trigger period flushing.
+    mReactor.setDisplayPowerMode(hal::PowerMode::DOZE);
+    EXPECT_FALSE(mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed));
+    EXPECT_TRUE(periodFlushed);
+}
+
 TEST_F(VSyncReactorTest, addPresentFenceWhileAwaitingPeriodConfirmationRequestsHwVsync) {
     auto time = 0;
     bool periodFlushed = false;
diff --git a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.cpp
similarity index 65%
copy from libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
copy to services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.cpp
index fc2542b..5049b1d 100644
--- a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.cpp
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
-parcelable GenericDataParcelable {
-    int data;
-    float majorVersion;
-    float minorVersion;
-    IBinder binder;
-    ParcelFileDescriptor fileDescriptor;
-    int[] array;
-}
\ No newline at end of file
+#include "MockAidlPowerHalWrapper.h"
+#include "MockIPower.h"
+
+namespace android::Hwc2::mock {
+
+MockAidlPowerHalWrapper::MockAidlPowerHalWrapper()
+      : AidlPowerHalWrapper(sp<testing::NiceMock<MockIPower>>::make()){};
+MockAidlPowerHalWrapper::~MockAidlPowerHalWrapper() = default;
+
+} // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h
new file mode 100644
index 0000000..657ced3
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "DisplayHardware/PowerAdvisor.h"
+
+namespace android {
+namespace hardware {
+namespace power {
+class IPower;
+}
+} // namespace hardware
+} // namespace android
+
+namespace android::Hwc2::mock {
+
+class MockAidlPowerHalWrapper : public Hwc2::impl::AidlPowerHalWrapper {
+public:
+    MockAidlPowerHalWrapper();
+    ~MockAidlPowerHalWrapper() override;
+    MOCK_METHOD(bool, setExpensiveRendering, (bool enabled), (override));
+    MOCK_METHOD(bool, notifyDisplayUpdateImminent, (), (override));
+    MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
+    MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
+    MOCK_METHOD(void, restartPowerHintSession, (), (override));
+    MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds),
+                (override));
+    MOCK_METHOD(bool, startPowerHintSession, (), (override));
+    MOCK_METHOD(void, setTargetWorkDuration, (nsecs_t targetDuration), (override));
+    MOCK_METHOD(void, sendActualWorkDuration, (nsecs_t actualDuration, nsecs_t timestamp),
+                (override));
+    MOCK_METHOD(bool, shouldReconnectHAL, (), (override));
+};
+
+} // namespace android::Hwc2::mock
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index c598cbc..aede250 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -36,11 +36,33 @@
     MOCK_METHOD(bool, usePowerHintSession, (), (override));
     MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
     MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
-    MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override));
-    MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp),
-                (override));
+    MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDuration), (override));
+    MOCK_METHOD(void, sendActualWorkDuration, (), (override));
+    MOCK_METHOD(void, sendPredictedWorkDuration, (), (override));
     MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
     MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override));
+    MOCK_METHOD(void, setGpuFenceTime,
+                (DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override));
+    MOCK_METHOD(void, setHwcValidateTiming,
+                (DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime),
+                (override));
+    MOCK_METHOD(void, setHwcPresentTiming,
+                (DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime),
+                (override));
+    MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override));
+    MOCK_METHOD(void, setRequiresClientComposition,
+                (DisplayId displayId, bool requiresClientComposition), (override));
+    MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override));
+    MOCK_METHOD(void, setSfPresentTiming, (nsecs_t presentFenceTime, nsecs_t presentEndTime),
+                (override));
+    MOCK_METHOD(void, setHwcPresentDelayedTime,
+                (DisplayId displayId,
+                 std::chrono::steady_clock::time_point earliestFrameStartTime));
+    MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override));
+    MOCK_METHOD(void, setCommitStart, (nsecs_t commitStartTime), (override));
+    MOCK_METHOD(void, setCompositeEnd, (nsecs_t compositeEndtime), (override));
+    MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override));
+    MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (int64_t targetDuration), (override));
 };
 
 } // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h
index 314f681..4ef91da 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h
@@ -31,6 +31,7 @@
     MOCK_METHOD3(addHwVsyncTimestamp, bool(nsecs_t, std::optional<nsecs_t>, bool*));
     MOCK_METHOD1(startPeriodTransition, void(nsecs_t));
     MOCK_METHOD1(setIgnorePresentFences, void(bool));
+    MOCK_METHOD(void, setDisplayPowerMode, (hal::PowerMode), (override));
 
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
deleted file mode 100644
index 80e9a3c..0000000
--- a/services/vr/hardware_composer/Android.bp
+++ /dev/null
@@ -1,134 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_native_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_native_license"],
-}
-
-cc_library_shared {
-    name: "libvr_hwc-hal",
-
-    system_ext_specific: true,
-
-    srcs: [
-        "impl/vr_hwc.cpp",
-        "impl/vr_composer_client.cpp",
-    ],
-
-    static_libs: [
-        "libbroadcastring",
-        "libdisplay",
-    ],
-
-    shared_libs: [
-        "android.frameworks.vr.composer@2.0",
-        "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.composer@2.2",
-        "android.hardware.graphics.composer@2.3",
-        "android.hardware.graphics.composer@2.1-resources",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
-        "libbase",
-        "libbufferhubqueue",
-        "libbinder",
-        "libcutils",
-        "libfmq",
-        "libhardware",
-        "libhidlbase",
-        "liblog",
-        "libsync",
-        "libui",
-        "libutils",
-        "libpdx_default_transport",
-    ],
-
-    header_libs: [
-        "android.hardware.graphics.composer@2.1-command-buffer",
-        "android.hardware.graphics.composer@2.3-hal",
-    ],
-
-    export_header_lib_headers: [
-        "android.hardware.graphics.composer@2.3-hal",
-    ],
-
-    export_static_lib_headers: [
-        "libdisplay",
-    ],
-
-    export_shared_lib_headers: [
-        "android.frameworks.vr.composer@2.0",
-        "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.composer@2.2",
-        "android.hardware.graphics.composer@2.3",
-    ],
-
-    export_include_dirs: ["."],
-
-    cflags: [
-        "-DLOG_TAG=\"vr_hwc\"",
-        "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
-        "-Wall",
-        "-Werror",
-        "-Wno-error=unused-private-field",
-        // Warnings in vr_hwc.cpp to be fixed after sync of goog/master.
-        "-Wno-sign-compare",
-        "-Wno-unused-parameter",
-    ],
-
-}
-
-cc_library_static {
-    name: "libvr_hwc-impl",
-    srcs: [
-        "vr_composer.cpp",
-    ],
-    static_libs: [
-        "libvr_hwc-binder",
-    ],
-    shared_libs: [
-        "libbase",
-        "libbinder",
-        "liblog",
-        "libui",
-        "libutils",
-        "libvr_hwc-hal",
-    ],
-    export_shared_lib_headers: [
-        "libvr_hwc-hal",
-    ],
-    cflags: [
-        "-DLOG_TAG=\"vr_hwc\"",
-        "-Wall",
-        "-Werror",
-    ],
-}
-
-cc_test {
-    name: "vr_hwc_test",
-    gtest: true,
-    srcs: ["tests/vr_composer_test.cpp"],
-    static_libs: [
-        "libgtest",
-        "libvr_hwc-impl",
-        // NOTE: This needs to be included after the *-impl lib otherwise the
-        // symbols in the *-binder library get optimized out.
-        "libvr_hwc-binder",
-    ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-        // warnings in vr_composer_test.cpp to be fixed after merge of goog/master
-        "-Wno-sign-compare",
-        "-Wno-unused-parameter",
-    ],
-    shared_libs: [
-        "libbase",
-        "libbinder",
-        "liblog",
-        "libui",
-        "libutils",
-    ],
-}
diff --git a/services/vr/hardware_composer/aidl/Android.bp b/services/vr/hardware_composer/aidl/Android.bp
deleted file mode 100644
index fa71ed7..0000000
--- a/services/vr/hardware_composer/aidl/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_native_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_native_license"],
-}
-
-cc_library_static {
-    name: "libvr_hwc-binder",
-    srcs: [
-        "android/dvr/IVrComposer.aidl",
-        "android/dvr/IVrComposerCallback.aidl",
-        "android/dvr/parcelable_composer_frame.cpp",
-        "android/dvr/parcelable_composer_layer.cpp",
-        "android/dvr/parcelable_unique_fd.cpp",
-    ],
-    aidl: {
-        local_include_dirs: ["."],
-        export_aidl_headers: true,
-    },
-    export_include_dirs: ["."],
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-
-    shared_libs: [
-        "libbinder",
-        "libui",
-        "libutils",
-        "libvr_hwc-hal",
-    ],
-}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
deleted file mode 100644
index be1ec5b..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-package android.dvr;
-
-import android.dvr.IVrComposerCallback;
-
-/**
- * Service interface exposed by VR HWC exposed to system apps which allows one
- * system app to connect to get SurfaceFlinger's outputs (all displays). This
- * is active when SurfaceFlinger is in VR mode, where all 2D output is
- * redirected to VR HWC.
- *
- * @hide */
-interface IVrComposer
-{
-  const String SERVICE_NAME = "vr_hwc";
-
-  /**
-   * Registers a callback used to receive frame notifications.
-   */
-  void registerObserver(in IVrComposerCallback callback);
-
-  /**
-   * Clears a previously registered frame notification callback.
-   */
-  void clearObserver();
-}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl
deleted file mode 100644
index aa70de1..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-package android.dvr;
-
-import android.dvr.ParcelableComposerFrame;
-import android.dvr.ParcelableUniqueFd;
-
-/**
- * A system app will implement and register this callback with VRComposer
- * to receive the layers SurfaceFlinger presented when in VR mode.
- *
- * @hide */
-interface IVrComposerCallback {
-  /**
-   * Called by the VR HWC service when a new frame is ready to be presented.
-   *
-   * @param frame The new frame VR HWC wants to present.
-   * @return A fence FD used to signal when the previous frame is no longer
-   * used by the client. This may be an invalid fence (-1) if the client is not
-   * using the previous frame, in which case the previous frame may be re-used
-   * at any point in time.
-   */
-  ParcelableUniqueFd onNewFrame(in ParcelableComposerFrame frame);
-}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl
deleted file mode 100644
index 84abc19..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl
+++ /dev/null
@@ -1,3 +0,0 @@
-package android.dvr;
-
-parcelable ParcelableComposerFrame cpp_header "android/dvr/parcelable_composer_frame.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl
deleted file mode 100644
index a200345..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl
+++ /dev/null
@@ -1,3 +0,0 @@
-package android.dvr;
-
-parcelable ParcelableComposerLayer cpp_header "android/dvr/parcelable_composer_layer.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl
deleted file mode 100644
index eee9d13..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl
+++ /dev/null
@@ -1,3 +0,0 @@
-package android.dvr;
-
-parcelable ParcelableUniqueFd cpp_header "android/dvr/parcelable_unique_fd.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
deleted file mode 100644
index db7d5dc..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-#include "aidl/android/dvr/parcelable_composer_frame.h"
-
-#include <binder/Parcel.h>
-
-#include "aidl/android/dvr/parcelable_composer_layer.h"
-
-namespace android {
-namespace dvr {
-
-ParcelableComposerFrame::ParcelableComposerFrame() {}
-
-ParcelableComposerFrame::ParcelableComposerFrame(
-    const ComposerView::Frame& frame)
-    : frame_(frame) {}
-
-ParcelableComposerFrame::~ParcelableComposerFrame() {}
-
-status_t ParcelableComposerFrame::writeToParcel(Parcel* parcel) const {
-  status_t ret = parcel->writeUint64(frame_.display_id);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeInt32(frame_.display_width);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeInt32(frame_.display_height);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeBool(frame_.removed);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeUint32(static_cast<uint32_t>(frame_.active_config));
-  if (ret != OK) return ret;
-
-  ret = parcel->writeUint32(static_cast<uint32_t>(frame_.color_mode));
-  if (ret != OK) return ret;
-
-  ret = parcel->writeUint32(static_cast<uint32_t>(frame_.power_mode));
-  if (ret != OK) return ret;
-
-  ret = parcel->writeUint32(static_cast<uint32_t>(frame_.vsync_enabled));
-  if (ret != OK) return ret;
-
-  ret = parcel->writeInt32(frame_.color_transform_hint);
-  if (ret != OK) return ret;
-
-  for(size_t i = 0; i < 16; i++) {
-    ret = parcel->writeFloat(frame_.color_transform[i]);
-    if (ret != OK) return ret;
-  }
-
-  std::vector<ParcelableComposerLayer> layers;
-  for (size_t i = 0; i < frame_.layers.size(); ++i)
-    layers.push_back(ParcelableComposerLayer(frame_.layers[i]));
-
-  ret = parcel->writeParcelableVector(layers);
-
-  return ret;
-}
-
-status_t ParcelableComposerFrame::readFromParcel(const Parcel* parcel) {
-  status_t ret = parcel->readUint64(&frame_.display_id);
-  if (ret != OK) return ret;
-
-  ret = parcel->readInt32(&frame_.display_width);
-  if (ret != OK) return ret;
-
-  ret = parcel->readInt32(&frame_.display_height);
-  if (ret != OK) return ret;
-
-  ret = parcel->readBool(&frame_.removed);
-  if (ret != OK) return ret;
-
-  uint32_t value;
-  ret = parcel->readUint32(&value);
-  if (ret != OK) return ret;
-  frame_.active_config = static_cast<Config>(value);
-
-  ret = parcel->readUint32(&value);
-  if (ret != OK) return ret;
-  frame_.color_mode = static_cast<ColorMode>(value);
-
-  ret = parcel->readUint32(&value);
-  if (ret != OK) return ret;
-  frame_.power_mode = static_cast<IComposerClient::PowerMode>(value);
-
-  ret = parcel->readUint32(&value);
-  if (ret != OK) return ret;
-  frame_.vsync_enabled = static_cast<IComposerClient::Vsync>(value);
-
-  ret = parcel->readInt32(&frame_.color_transform_hint);
-  if (ret != OK) return ret;
-
-  for(size_t i = 0; i < 16; i++) {
-    ret = parcel->readFloat(&frame_.color_transform[i]);
-    if (ret != OK) return ret;
-  }
-
-  std::vector<ParcelableComposerLayer> layers;
-  ret = parcel->readParcelableVector(&layers);
-  if (ret != OK) return ret;
-
-  frame_.layers.clear();
-  for (size_t i = 0; i < layers.size(); ++i)
-    frame_.layers.push_back(layers[i].layer());
-
-  return ret;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h
deleted file mode 100644
index a82df7f..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
-#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
-
-#include <binder/Parcelable.h>
-#include <impl/vr_hwc.h>
-
-namespace android {
-namespace dvr {
-
-class ParcelableComposerFrame : public Parcelable {
- public:
-  ParcelableComposerFrame();
-  explicit ParcelableComposerFrame(const ComposerView::Frame& frame);
-  ~ParcelableComposerFrame() override;
-
-  ComposerView::Frame frame() const { return frame_; }
-
-  status_t writeToParcel(Parcel* parcel) const override;
-  status_t readFromParcel(const Parcel* parcel) override;
-
- private:
-  ComposerView::Frame frame_;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
deleted file mode 100644
index c3621eb..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
+++ /dev/null
@@ -1,240 +0,0 @@
-#include "aidl/android/dvr/parcelable_composer_layer.h"
-
-#include <binder/Parcel.h>
-#include <ui/Fence.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/GraphicBufferMapper.h>
-
-namespace android {
-namespace dvr {
-
-ParcelableComposerLayer::ParcelableComposerLayer() {}
-
-ParcelableComposerLayer::ParcelableComposerLayer(
-    const ComposerView::ComposerLayer& layer) : layer_(layer) {}
-
-ParcelableComposerLayer::~ParcelableComposerLayer() {}
-
-status_t ParcelableComposerLayer::writeToParcel(Parcel* parcel) const {
-  status_t ret = parcel->writeUint64(layer_.id);
-  if (ret != OK) return ret;
-
-  ret = parcel->write(*layer_.buffer);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeBool(layer_.fence->isValid());
-  if (ret != OK) return ret;
-
-  if (layer_.fence->isValid()) {
-    ret = parcel->writeFileDescriptor(layer_.fence->dup(), true);
-    if (ret != OK) return ret;
-  }
-
-  ret = parcel->writeInt32(layer_.display_frame.left);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeInt32(layer_.display_frame.top);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeInt32(layer_.display_frame.right);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeInt32(layer_.display_frame.bottom);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeFloat(layer_.crop.left);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeFloat(layer_.crop.top);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeFloat(layer_.crop.right);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeFloat(layer_.crop.bottom);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeInt32(static_cast<int32_t>(layer_.blend_mode));
-  if (ret != OK) return ret;
-
-  ret = parcel->writeFloat(layer_.alpha);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeUint32(layer_.type);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeUint32(layer_.app_id);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeUint32(layer_.z_order);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeInt32(layer_.cursor_x);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeInt32(layer_.cursor_y);
-  if (ret != OK) return ret;
-
-  uint32_t color = layer_.color.r |
-      (static_cast<uint32_t>(layer_.color.g) << 8) |
-      (static_cast<uint32_t>(layer_.color.b) << 16) |
-      (static_cast<uint32_t>(layer_.color.a) << 24);
-  ret = parcel->writeUint32(color);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeInt32(layer_.dataspace);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeInt32(layer_.transform);
-  if (ret != OK) return ret;
-
-  ret = parcel->writeUint32(static_cast<uint32_t>(layer_.visible_regions.size()));
-  if (ret != OK) return ret;
-
-  for (auto& rect: layer_.visible_regions) {
-    ret = parcel->writeInt32(rect.left);
-    ret = parcel->writeInt32(rect.top);
-    ret = parcel->writeInt32(rect.right);
-    ret = parcel->writeInt32(rect.bottom);
-    if (ret != OK) return ret;
-  }
-
-  ret = parcel->writeUint32(static_cast<uint32_t>(layer_.damaged_regions.size()));
-  if (ret != OK) return ret;
-
-  for (auto& rect: layer_.damaged_regions) {
-    ret = parcel->writeInt32(rect.left);
-    ret = parcel->writeInt32(rect.top);
-    ret = parcel->writeInt32(rect.right);
-    ret = parcel->writeInt32(rect.bottom);
-    if (ret != OK) return ret;
-  }
-
-  return OK;
-}
-
-status_t ParcelableComposerLayer::readFromParcel(const Parcel* parcel) {
-  status_t ret = parcel->readUint64(&layer_.id);
-  if (ret != OK) return ret;
-
-  layer_.buffer = new GraphicBuffer();
-  ret = parcel->read(*layer_.buffer);
-  if (ret != OK) {
-    layer_.buffer.clear();
-    return ret;
-  }
-
-  bool has_fence = 0;
-  ret = parcel->readBool(&has_fence);
-  if (ret != OK) return ret;
-
-  if (has_fence)
-    layer_.fence = new Fence(dup(parcel->readFileDescriptor()));
-  else
-    layer_.fence = new Fence();
-
-  ret = parcel->readInt32(&layer_.display_frame.left);
-  if (ret != OK) return ret;
-
-  ret = parcel->readInt32(&layer_.display_frame.top);
-  if (ret != OK) return ret;
-
-  ret = parcel->readInt32(&layer_.display_frame.right);
-  if (ret != OK) return ret;
-
-  ret = parcel->readInt32(&layer_.display_frame.bottom);
-  if (ret != OK) return ret;
-
-  ret = parcel->readFloat(&layer_.crop.left);
-  if (ret != OK) return ret;
-
-  ret = parcel->readFloat(&layer_.crop.top);
-  if (ret != OK) return ret;
-
-  ret = parcel->readFloat(&layer_.crop.right);
-  if (ret != OK) return ret;
-
-  ret = parcel->readFloat(&layer_.crop.bottom);
-  if (ret != OK) return ret;
-
-  ret = parcel->readInt32(reinterpret_cast<int32_t*>(&layer_.blend_mode));
-  if (ret != OK) return ret;
-
-  ret = parcel->readFloat(&layer_.alpha);
-  if (ret != OK) return ret;
-
-  ret = parcel->readUint32(&layer_.type);
-  if (ret != OK) return ret;
-
-  ret = parcel->readUint32(&layer_.app_id);
-  if (ret != OK) return ret;
-
-  ret = parcel->readUint32(&layer_.z_order);
-  if (ret != OK) return ret;
-
-  ret = parcel->readInt32(&layer_.cursor_x);
-  if (ret != OK) return ret;
-
-  ret = parcel->readInt32(&layer_.cursor_y);
-  if (ret != OK) return ret;
-
-  uint32_t color;
-  ret = parcel->readUint32(&color);
-  if (ret != OK) return ret;
-  layer_.color.r = color & 0xFF;
-  layer_.color.g = (color >> 8) & 0xFF;
-  layer_.color.b = (color >> 16) & 0xFF;
-  layer_.color.a = (color >> 24) & 0xFF;
-
-  ret = parcel->readInt32(&layer_.dataspace);
-  if (ret != OK) return ret;
-
-  ret = parcel->readInt32(&layer_.transform);
-  if (ret != OK) return ret;
-
-  uint32_t size;
-  ret = parcel->readUint32(&size);
-  if (ret != OK) return ret;
-
-  for(size_t i = 0; i < size; i++) {
-    hwc_rect_t rect;
-    ret = parcel->readInt32(&rect.left);
-    if (ret != OK) return ret;
-
-    ret = parcel->readInt32(&rect.top);
-    if (ret != OK) return ret;
-
-    ret = parcel->readInt32(&rect.right);
-    if (ret != OK) return ret;
-
-    ret = parcel->readInt32(&rect.bottom);
-    if (ret != OK) return ret;
-
-    layer_.visible_regions.push_back(rect);
-  }
-
-  ret = parcel->readUint32(&size);
-  if (ret != OK) return ret;
-
-  for(size_t i = 0; i < size; i++) {
-    hwc_rect_t rect;
-    ret = parcel->readInt32(&rect.left);
-    if (ret != OK) return ret;
-
-    ret = parcel->readInt32(&rect.top);
-    if (ret != OK) return ret;
-
-    ret = parcel->readInt32(&rect.right);
-    if (ret != OK) return ret;
-
-    ret = parcel->readInt32(&rect.bottom);
-    if (ret != OK) return ret;
-
-    layer_.damaged_regions.push_back(rect);
-  }
-
-  return OK;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h
deleted file mode 100644
index 6d2ac09..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
-#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
-
-#include <binder/Parcelable.h>
-#include <impl/vr_hwc.h>
-
-#include <memory>
-
-namespace android {
-namespace dvr {
-
-class ParcelableComposerLayer : public Parcelable {
- public:
-  ParcelableComposerLayer();
-  explicit ParcelableComposerLayer(const ComposerView::ComposerLayer& layer);
-  ~ParcelableComposerLayer() override;
-
-  ComposerView::ComposerLayer layer() const { return layer_; }
-
-  status_t writeToParcel(Parcel* parcel) const override;
-  status_t readFromParcel(const Parcel* parcel) override;
-
- private:
-  ComposerView::ComposerLayer layer_;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp
deleted file mode 100644
index 9486f3c..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "android/dvr/parcelable_unique_fd.h"
-
-#include <binder/Parcel.h>
-
-namespace android {
-namespace dvr {
-
-ParcelableUniqueFd::ParcelableUniqueFd() {}
-
-ParcelableUniqueFd::ParcelableUniqueFd(const base::unique_fd& fence)
-    : fence_(dup(fence.get())) {}
-
-ParcelableUniqueFd::~ParcelableUniqueFd() {}
-
-status_t ParcelableUniqueFd::writeToParcel(Parcel* parcel) const {
-  status_t ret = parcel->writeBool(fence_.get() >= 0);
-  if (ret != OK) return ret;
-
-  if (fence_.get() >= 0)
-    ret = parcel->writeUniqueFileDescriptor(fence_);
-
-  return ret;
-}
-
-status_t ParcelableUniqueFd::readFromParcel(const Parcel* parcel) {
-  bool has_fence = 0;
-  status_t ret = parcel->readBool(&has_fence);
-  if (ret != OK) return ret;
-
-  if (has_fence)
-    ret = parcel->readUniqueFileDescriptor(&fence_);
-
-  return ret;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h
deleted file mode 100644
index c4216f6..0000000
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
-#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
-
-#include <android-base/unique_fd.h>
-#include <binder/Parcelable.h>
-
-namespace android {
-namespace dvr {
-
-// Provide a wrapper to serialized base::unique_fd. The wrapper also handles the
-// case where the FD is invalid (-1), unlike FileDescriptor which expects a
-// valid FD.
-class ParcelableUniqueFd : public Parcelable {
- public:
-  ParcelableUniqueFd();
-  explicit ParcelableUniqueFd(const base::unique_fd& fence);
-  ~ParcelableUniqueFd() override;
-
-  void set_fence(const base::unique_fd& fence) {
-    fence_.reset(dup(fence.get()));
-  }
-  base::unique_fd fence() const { return base::unique_fd(dup(fence_.get())); }
-
-  status_t writeToParcel(Parcel* parcel) const override;
-  status_t readFromParcel(const Parcel* parcel) override;
-
- private:
-  base::unique_fd fence_;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
deleted file mode 100644
index dd1603d..0000000
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
-#include <hardware/gralloc.h>
-#include <hardware/gralloc1.h>
-#include <log/log.h>
-
-#include <memory>
-
-#include "impl/vr_hwc.h"
-#include "impl/vr_composer_client.h"
-
-namespace android {
-namespace dvr {
-
-using android::frameworks::vr::composer::V2_0::IVrComposerClient;
-
-VrComposerClient::VrComposerClient(dvr::VrHwc& hal)
-    : ComposerClient(&hal), mVrHal(hal) {
-  if (!init()) {
-      LOG_ALWAYS_FATAL("failed to initialize VrComposerClient");
-  }
-}
-
-VrComposerClient::~VrComposerClient() {}
-
-std::unique_ptr<ComposerCommandEngine>
-VrComposerClient::createCommandEngine() {
-  return std::make_unique<VrCommandEngine>(*this);
-}
-
-VrComposerClient::VrCommandEngine::VrCommandEngine(VrComposerClient& client)
-    : ComposerCommandEngine(client.mHal, client.mResources.get()),
-      mVrHal(client.mVrHal) {}
-
-VrComposerClient::VrCommandEngine::~VrCommandEngine() {}
-
-bool VrComposerClient::VrCommandEngine::executeCommand(
-    hardware::graphics::composer::V2_1::IComposerClient::Command command,
-    uint16_t length) {
-  IVrComposerClient::VrCommand vrCommand =
-      static_cast<IVrComposerClient::VrCommand>(command);
-  switch (vrCommand) {
-    case IVrComposerClient::VrCommand::SET_LAYER_INFO:
-      return executeSetLayerInfo(length);
-    case IVrComposerClient::VrCommand::SET_CLIENT_TARGET_METADATA:
-      return executeSetClientTargetMetadata(length);
-    case IVrComposerClient::VrCommand::SET_LAYER_BUFFER_METADATA:
-      return executeSetLayerBufferMetadata(length);
-    default:
-      return ComposerCommandEngine::executeCommand(command, length);
-  }
-}
-
-bool VrComposerClient::VrCommandEngine::executeSetLayerInfo(uint16_t length) {
-  if (length != 2) {
-    return false;
-  }
-
-  auto err = mVrHal.setLayerInfo(mCurrentDisplay, mCurrentLayer, read(), read());
-  if (err != Error::NONE) {
-    mWriter->setError(getCommandLoc(), err);
-  }
-
-  return true;
-}
-
-bool VrComposerClient::VrCommandEngine::executeSetClientTargetMetadata(
-    uint16_t length) {
-  if (length != 7)
-    return false;
-
-  auto err = mVrHal.setClientTargetMetadata(mCurrentDisplay, readBufferMetadata());
-  if (err != Error::NONE)
-    mWriter->setError(getCommandLoc(), err);
-
-  return true;
-}
-
-bool VrComposerClient::VrCommandEngine::executeSetLayerBufferMetadata(
-    uint16_t length) {
-  if (length != 7)
-    return false;
-
-  auto err = mVrHal.setLayerBufferMetadata(mCurrentDisplay, mCurrentLayer,
-                                           readBufferMetadata());
-  if (err != Error::NONE)
-    mWriter->setError(getCommandLoc(), err);
-
-  return true;
-}
-
-IVrComposerClient::BufferMetadata
-VrComposerClient::VrCommandEngine::readBufferMetadata() {
-  IVrComposerClient::BufferMetadata metadata = {
-      .width = read(),
-      .height = read(),
-      .stride = read(),
-      .layerCount = read(),
-      .format =
-          static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(
-              readSigned()),
-      .usage = read64(),
-  };
-  return metadata;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
deleted file mode 100644
index 1b2b5f4..0000000
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 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 ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H
-#define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H
-
-#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
-#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
-#include <composer-hal/2.1/ComposerClient.h>
-#include <composer-hal/2.1/ComposerCommandEngine.h>
-#include <composer-hal/2.2/ComposerClient.h>
-#include <composer-hal/2.3/ComposerClient.h>
-
-namespace android {
-namespace dvr {
-
-class VrHwc;
-
-using hardware::graphics::composer::V2_1::hal::ComposerCommandEngine;
-using hardware::graphics::composer::V2_3::hal::ComposerHal;
-using hardware::graphics::composer::V2_3::hal::detail::ComposerClientImpl;
-
-using ComposerClient = ComposerClientImpl<IVrComposerClient, ComposerHal>;
-
-class VrComposerClient : public ComposerClient {
- public:
-  explicit VrComposerClient(android::dvr::VrHwc& hal);
-  virtual ~VrComposerClient();
-
- private:
-  class VrCommandEngine : public ComposerCommandEngine {
-   public:
-    explicit VrCommandEngine(VrComposerClient& client);
-    ~VrCommandEngine() override;
-
-    bool executeCommand(
-        hardware::graphics::composer::V2_1::IComposerClient::Command command,
-        uint16_t length) override;
-
-   private:
-    bool executeSetLayerInfo(uint16_t length);
-    bool executeSetClientTargetMetadata(uint16_t length);
-    bool executeSetLayerBufferMetadata(uint16_t length);
-
-    IVrComposerClient::BufferMetadata readBufferMetadata();
-
-    android::dvr::VrHwc& mVrHal;
-
-    VrCommandEngine(const VrCommandEngine&) = delete;
-    void operator=(const VrCommandEngine&) = delete;
-  };
-
-  VrComposerClient(const VrComposerClient&) = delete;
-  void operator=(const VrComposerClient&) = delete;
-
-  std::unique_ptr<ComposerCommandEngine> createCommandEngine() override;
-  dvr::VrHwc& mVrHal;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif  // ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
deleted file mode 100644
index e530b16..0000000
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ /dev/null
@@ -1,1178 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "impl/vr_hwc.h"
-
-#include "android-base/stringprintf.h"
-#include <binder/IServiceManager.h>
-#include <cutils/properties.h>
-#include <private/dvr/display_client.h>
-#include <ui/Fence.h>
-#include <utils/Trace.h>
-
-#include <mutex>
-
-#include "vr_composer_client.h"
-
-using namespace android::hardware::graphics::common::V1_0;
-using namespace android::hardware::graphics::composer::V2_3;
-
-using android::base::StringPrintf;
-using android::hardware::hidl_handle;
-using android::hardware::hidl_string;
-using android::hardware::hidl_vec;
-using android::hardware::Return;
-using android::hardware::Void;
-
-namespace types = android::hardware::graphics::common;
-
-namespace android {
-namespace dvr {
-namespace {
-
-const Display kDefaultDisplayId = 1;
-const Config kDefaultConfigId = 1;
-
-sp<GraphicBuffer> CreateGraphicBuffer(
-    const native_handle_t* handle,
-    const IVrComposerClient::BufferMetadata& metadata) {
-   sp<GraphicBuffer> buffer = new GraphicBuffer(
-      handle, GraphicBuffer::CLONE_HANDLE, metadata.width, metadata.height,
-      static_cast<int32_t>(metadata.format), metadata.layerCount,
-      metadata.usage, metadata.stride);
-   if (buffer->initCheck() != OK) {
-     ALOGE("Failed to create graphic buffer");
-     return nullptr;
-   }
-
-   return buffer;
-}
-
-void GetPrimaryDisplaySize(int32_t* width, int32_t* height) {
-  *width = 1080;
-  *height = 1920;
-
-  int error = 0;
-  auto display_client = display::DisplayClient::Create(&error);
-  if (!display_client) {
-    ALOGE("Could not connect to display service : %s(%d)", strerror(error),
-          error);
-    return;
-  }
-
-  auto status = display_client->GetDisplayMetrics();
-  if (!status) {
-    ALOGE("Could not get display metrics from display service : %s(%d)",
-          status.GetErrorMessage().c_str(), status.error());
-    return;
-  }
-
-  *width = status.get().display_width;
-  *height = status.get().display_height;
-}
-
-}  // namespace
-
-HwcDisplay::HwcDisplay(int32_t width, int32_t height)
-    : width_(width), height_(height) {}
-
-HwcDisplay::~HwcDisplay() {}
-
-bool HwcDisplay::SetClientTarget(const native_handle_t* handle,
-                                 base::unique_fd fence) {
-  if (handle)
-    buffer_ = CreateGraphicBuffer(handle, buffer_metadata_);
-
-  fence_ = new Fence(fence.release());
-  return true;
-}
-
-void HwcDisplay::SetClientTargetMetadata(
-    const IVrComposerClient::BufferMetadata& metadata) {
-  buffer_metadata_ = metadata;
-}
-
-HwcLayer* HwcDisplay::CreateLayer() {
-  uint64_t layer_id = layer_ids_++;
-  layers_.push_back(HwcLayer(layer_id));
-  return &layers_.back();
-}
-
-HwcLayer* HwcDisplay::GetLayer(Layer id) {
-  for (size_t i = 0; i < layers_.size(); ++i)
-    if (layers_[i].info.id == id)
-      return &layers_[i];
-
-  return nullptr;
-}
-
-bool HwcDisplay::DestroyLayer(Layer id) {
-  for (auto it = layers_.begin(); it != layers_.end(); ++it) {
-    if (it->info.id == id) {
-      layers_.erase(it);
-      return true;
-    }
-  }
-
-  return false;
-}
-
-void HwcDisplay::GetChangedCompositionTypes(
-    std::vector<Layer>* layer_ids,
-    std::vector<IComposerClient::Composition>* types) {
-  std::sort(layers_.begin(), layers_.end(),
-            [](const auto& lhs, const auto& rhs) {
-              return lhs.info.z_order < rhs.info.z_order;
-            });
-
-  const size_t no_layer = std::numeric_limits<size_t>::max();
-  size_t first_client_layer = no_layer, last_client_layer = no_layer;
-  for (size_t i = 0; i < layers_.size(); ++i) {
-    switch (layers_[i].composition_type) {
-      case IComposerClient::Composition::SOLID_COLOR:
-      case IComposerClient::Composition::CURSOR:
-      case IComposerClient::Composition::SIDEBAND:
-        if (first_client_layer == no_layer)
-          first_client_layer = i;
-
-        last_client_layer = i;
-        break;
-      default:
-        break;
-    }
-  }
-
-  for (size_t i = 0; i < layers_.size(); ++i) {
-    if (i >= first_client_layer && i <= last_client_layer) {
-      if (layers_[i].composition_type != IComposerClient::Composition::CLIENT) {
-        layer_ids->push_back(layers_[i].info.id);
-        types->push_back(IComposerClient::Composition::CLIENT);
-        layers_[i].composition_type = IComposerClient::Composition::CLIENT;
-      }
-
-      continue;
-    }
-
-    if (layers_[i].composition_type != IComposerClient::Composition::DEVICE) {
-      layer_ids->push_back(layers_[i].info.id);
-      types->push_back(IComposerClient::Composition::DEVICE);
-      layers_[i].composition_type = IComposerClient::Composition::DEVICE;
-    }
-  }
-}
-
-Error HwcDisplay::GetFrame(
-    std::vector<ComposerView::ComposerLayer>* out_frames) {
-  bool queued_client_target = false;
-  std::vector<ComposerView::ComposerLayer> frame;
-  for (const auto& layer : layers_) {
-    if (layer.composition_type == IComposerClient::Composition::CLIENT) {
-      if (queued_client_target)
-        continue;
-
-      if (!buffer_.get()) {
-        ALOGE("Client composition requested but no client target buffer");
-        return Error::BAD_LAYER;
-      }
-
-      ComposerView::ComposerLayer client_target_layer = {
-          .buffer = buffer_,
-          .fence = fence_.get() ? fence_ : new Fence(-1),
-          .display_frame = {0, 0, static_cast<int32_t>(buffer_->getWidth()),
-            static_cast<int32_t>(buffer_->getHeight())},
-          .crop = {0.0f, 0.0f, static_cast<float>(buffer_->getWidth()),
-            static_cast<float>(buffer_->getHeight())},
-          .blend_mode = IComposerClient::BlendMode::NONE,
-      };
-
-      frame.push_back(client_target_layer);
-      queued_client_target = true;
-    } else {
-      if (!layer.info.buffer.get() || !layer.info.fence.get()) {
-        ALOGV("Layer requested without valid buffer");
-        continue;
-      }
-
-      frame.push_back(layer.info);
-    }
-  }
-
-  out_frames->swap(frame);
-  return Error::NONE;
-}
-
-std::vector<Layer> HwcDisplay::UpdateLastFrameAndGetLastFrameLayers() {
-  std::vector<Layer> last_frame_layers;
-  last_frame_layers.swap(last_frame_layers_ids_);
-
-  for (const auto& layer : layers_)
-    last_frame_layers_ids_.push_back(layer.info.id);
-
-  return last_frame_layers;
-}
-
-void HwcDisplay::SetColorTransform(const float* matrix, int32_t hint) {
-  color_transform_hint_ = hint;
-  if (matrix)
-    memcpy(color_transform_, matrix, sizeof(color_transform_));
-}
-
-void HwcDisplay::dumpDebugInfo(std::string* result) const {
-  if (!result) {
-    return;
-  }
-  *result += StringPrintf("HwcDisplay: width: %d, height: %d, layers size: %zu, colormode: %d\
-      , config: %d\n", width_, height_, layers_.size(), color_mode_, active_config_);
-  *result += StringPrintf("HwcDisplay buffer metadata: width: %d, height: %d, stride: %d,\
-      layerCount: %d, pixelFormat: %d\n", buffer_metadata_.width, buffer_metadata_.height,
-      buffer_metadata_.stride, buffer_metadata_.layerCount, buffer_metadata_.format);
-  for (const auto& layer : layers_) {
-    layer.dumpDebugInfo(result);
-  }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// VrHwcClient
-
-VrHwc::VrHwc() {
-  vsync_callback_ = new VsyncCallback;
-}
-
-VrHwc::~VrHwc() {
-  vsync_callback_->SetEventCallback(nullptr);
-}
-
-bool VrHwc::hasCapability(hwc2_capability_t /* capability */) { return false; }
-
-void VrHwc::registerEventCallback(EventCallback* callback) {
-  std::unique_lock<std::mutex> lock(mutex_);
-  event_callback_ = callback;
-  int32_t width, height;
-  GetPrimaryDisplaySize(&width, &height);
-  // Create the primary display late to avoid initialization issues between
-  // VR HWC and SurfaceFlinger.
-  displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
-
-  // Surface flinger will make calls back into vr_hwc when it receives the
-  // onHotplug() call, so it's important to release mutex_ here.
-  lock.unlock();
-  event_callback_->onHotplug(kDefaultDisplayId,
-                             hardware::graphics::composer::V2_1::
-                                 IComposerCallback::Connection::CONNECTED);
-  lock.lock();
-  UpdateVsyncCallbackEnabledLocked();
-}
-
-void VrHwc::unregisterEventCallback() {
-  std::lock_guard<std::mutex> guard(mutex_);
-  event_callback_ = nullptr;
-  UpdateVsyncCallbackEnabledLocked();
-}
-
-uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; }
-
-Error VrHwc::destroyVirtualDisplay(Display display) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  if (display == kDefaultDisplayId || displays_.erase(display) == 0)
-    return Error::BAD_DISPLAY;
-  ComposerView::Frame frame;
-  frame.display_id = display;
-  frame.removed = true;
-  if (observer_)
-    observer_->OnNewFrame(frame);
-  return Error::NONE;
-}
-
-Error VrHwc::createLayer(Display display, Layer* outLayer) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* layer = display_ptr->CreateLayer();
-  *outLayer = layer->info.id;
-  return Error::NONE;
-}
-
-Error VrHwc::destroyLayer(Display display, Layer layer) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr) {
-    return Error::BAD_DISPLAY;
-  }
-
-  return display_ptr->DestroyLayer(layer) ? Error::NONE : Error::BAD_LAYER;
-}
-
-Error VrHwc::getActiveConfig(Display display, Config* outConfig) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  if (!FindDisplay(display))
-    return Error::BAD_DISPLAY;
-  *outConfig = kDefaultConfigId;
-  return Error::NONE;
-}
-
-Error VrHwc::getDisplayAttribute(Display display, Config config,
-                                 IComposerClient::Attribute attribute,
-                                 int32_t* outValue) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr) {
-    return Error::BAD_DISPLAY;
-  }
-  if (config != kDefaultConfigId) {
-    return Error::BAD_CONFIG;
-  }
-
-  switch (attribute) {
-    case IComposerClient::Attribute::WIDTH:
-      *outValue = display_ptr->width();
-      break;
-    case IComposerClient::Attribute::HEIGHT:
-      *outValue = display_ptr->height();
-      break;
-    case IComposerClient::Attribute::VSYNC_PERIOD:
-      {
-        int error = 0;
-        auto display_client = display::DisplayClient::Create(&error);
-        if (!display_client) {
-          ALOGE("Could not connect to display service : %s(%d)",
-                strerror(error), error);
-          // Return a default value of 30 fps
-          *outValue = 1000 * 1000 * 1000 / 30;
-        } else {
-          auto metrics = display_client->GetDisplayMetrics();
-          *outValue = metrics.get().vsync_period_ns;
-        }
-      }
-      break;
-    case IComposerClient::Attribute::DPI_X:
-    case IComposerClient::Attribute::DPI_Y:
-      {
-        constexpr int32_t kDefaultDPI = 300;
-        int32_t dpi = property_get_int32("ro.vr.hwc.dpi", kDefaultDPI);
-        if (dpi <= 0) {
-          dpi = kDefaultDPI;
-        }
-        *outValue = 1000 * dpi;
-      }
-      break;
-    default:
-      return Error::BAD_PARAMETER;
-  }
-
-  return Error::NONE;
-}
-
-Error VrHwc::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  if (!FindDisplay(display))
-    return Error::BAD_DISPLAY;
-  std::vector<Config> configs(1, kDefaultConfigId);
-  *outConfigs = hidl_vec<Config>(configs);
-  return Error::NONE;
-}
-
-Error VrHwc::getDisplayName(Display /* display */, hidl_string* outName) {
-  *outName = hidl_string();
-  return Error::NONE;
-}
-
-Error VrHwc::getDisplayType(Display display,
-                            IComposerClient::DisplayType* outType) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr) {
-    *outType = IComposerClient::DisplayType::INVALID;
-    return Error::BAD_DISPLAY;
-  }
-
-  if (display == kDefaultDisplayId)
-    *outType = IComposerClient::DisplayType::PHYSICAL;
-  else
-    *outType = IComposerClient::DisplayType::VIRTUAL;
-
-  return Error::NONE;
-}
-
-Error VrHwc::getDozeSupport(Display display, bool* outSupport) {
-  *outSupport = false;
-  std::lock_guard<std::mutex> guard(mutex_);
-  if (!FindDisplay(display))
-    return Error::BAD_DISPLAY;
-  return Error::NONE;
-}
-
-Error VrHwc::setActiveConfig(Display display, Config config) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-  if (config != kDefaultConfigId)
-    return Error::BAD_CONFIG;
-
-  display_ptr->set_active_config(config);
-  return Error::NONE;
-}
-
-Error VrHwc::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  if (enabled != IComposerClient::Vsync::ENABLE &&
-      enabled != IComposerClient::Vsync::DISABLE) {
-    return Error::BAD_PARAMETER;
-  }
-
-  Error set_vsync_result = Error::NONE;
-  if (display == kDefaultDisplayId) {
-    sp<IVsyncService> vsync_service = interface_cast<IVsyncService>(
-        defaultServiceManager()->getService(
-            String16(IVsyncService::GetServiceName())));
-    if (vsync_service == nullptr) {
-      ALOGE("Failed to get vsync service");
-      return Error::NO_RESOURCES;
-    }
-
-    if (enabled == IComposerClient::Vsync::ENABLE) {
-      ALOGI("Enable vsync");
-      display_ptr->set_vsync_enabled(true);
-      status_t result = vsync_service->registerCallback(vsync_callback_);
-      if (result != OK) {
-        ALOGE("%s service registerCallback() failed: %s (%d)",
-            IVsyncService::GetServiceName(), strerror(-result), result);
-        set_vsync_result = Error::NO_RESOURCES;
-      }
-    } else if (enabled == IComposerClient::Vsync::DISABLE) {
-      ALOGI("Disable vsync");
-      display_ptr->set_vsync_enabled(false);
-      status_t result = vsync_service->unregisterCallback(vsync_callback_);
-      if (result != OK) {
-        ALOGE("%s service unregisterCallback() failed: %s (%d)",
-            IVsyncService::GetServiceName(), strerror(-result), result);
-        set_vsync_result = Error::NO_RESOURCES;
-      }
-    }
-
-    UpdateVsyncCallbackEnabledLocked();
-  }
-
-  return set_vsync_result;
-}
-
-Error VrHwc::setColorTransform(Display display, const float* matrix,
-                               int32_t hint) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  display_ptr->SetColorTransform(matrix, hint);
-  return Error::NONE;
-}
-
-Error VrHwc::setClientTarget(Display display, buffer_handle_t target,
-                             int32_t acquireFence, int32_t /* dataspace */,
-                             const std::vector<hwc_rect_t>& /* damage */) {
-  base::unique_fd fence(acquireFence);
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  if (target == nullptr)
-    return Error::NONE;
-
-  if (!display_ptr->SetClientTarget(target, std::move(fence)))
-    return Error::BAD_PARAMETER;
-
-  return Error::NONE;
-}
-
-Error VrHwc::setOutputBuffer(Display display, buffer_handle_t /* buffer */,
-                             int32_t releaseFence) {
-  base::unique_fd fence(releaseFence);
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  // TODO(dnicoara): Is it necessary to do anything here?
-  return Error::NONE;
-}
-
-Error VrHwc::validateDisplay(
-    Display display, std::vector<Layer>* outChangedLayers,
-    std::vector<IComposerClient::Composition>* outCompositionTypes,
-    uint32_t* /* outDisplayRequestMask */,
-    std::vector<Layer>* /* outRequestedLayers */,
-    std::vector<uint32_t>* /* outRequestMasks */) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  display_ptr->GetChangedCompositionTypes(outChangedLayers,
-                                          outCompositionTypes);
-  return Error::NONE;
-}
-
-Error VrHwc::acceptDisplayChanges(Display /* display */) { return Error::NONE; }
-
-Error VrHwc::presentDisplay(Display display, int32_t* outPresentFence,
-                            std::vector<Layer>* outLayers,
-                            std::vector<int32_t>* outReleaseFences) {
-  *outPresentFence = -1;
-  outLayers->clear();
-  outReleaseFences->clear();
-
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  ComposerView::Frame frame;
-  std::vector<Layer> last_frame_layers;
-  Error status = display_ptr->GetFrame(&frame.layers);
-  frame.display_id = display;
-  frame.display_width = display_ptr->width();
-  frame.display_height = display_ptr->height();
-  frame.active_config = display_ptr->active_config();
-  frame.power_mode = display_ptr->power_mode();
-  frame.vsync_enabled = display_ptr->vsync_enabled() ?
-      IComposerClient::Vsync::ENABLE : IComposerClient::Vsync::DISABLE;
-  frame.color_transform_hint = display_ptr->color_transform_hint();
-  frame.color_mode = display_ptr->color_mode();
-  memcpy(frame.color_transform, display_ptr->color_transform(),
-         sizeof(frame.color_transform));
-  if (status != Error::NONE)
-    return status;
-
-  last_frame_layers = display_ptr->UpdateLastFrameAndGetLastFrameLayers();
-
-  base::unique_fd fence;
-  if (observer_)
-    fence = observer_->OnNewFrame(frame);
-
-  if (fence.get() < 0)
-    return Error::NONE;
-
-  *outPresentFence = dup(fence.get());
-  outLayers->swap(last_frame_layers);
-  for (size_t i = 0; i < outLayers->size(); ++i)
-    outReleaseFences->push_back(dup(fence.get()));
-
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerCursorPosition(Display display, Layer layer, int32_t x,
-                                    int32_t y) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->info.cursor_x = x;
-  hwc_layer->info.cursor_y = y;
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerBuffer(Display display, Layer layer,
-                            buffer_handle_t buffer, int32_t acquireFence) {
-  base::unique_fd fence(acquireFence);
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->info.buffer = CreateGraphicBuffer(
-      buffer, hwc_layer->buffer_metadata);
-  hwc_layer->info.fence = new Fence(fence.release());
-
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerSurfaceDamage(Display display, Layer layer,
-                                   const std::vector<hwc_rect_t>& damage) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->info.damaged_regions = damage;
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerBlendMode(Display display, Layer layer, int32_t mode) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->info.blend_mode =
-      static_cast<ComposerView::ComposerLayer::BlendMode>(mode);
-
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerColor(Display display, Layer layer,
-                           IComposerClient::Color color) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->info.color = color;
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerCompositionType(Display display, Layer layer,
-                                     int32_t type) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->composition_type = static_cast<HwcLayer::Composition>(type);
-
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerDataspace(Display display, Layer layer,
-                               int32_t dataspace) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->info.dataspace = dataspace;
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerDisplayFrame(Display display, Layer layer,
-                                  const hwc_rect_t& frame) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->info.display_frame =
-      {frame.left, frame.top, frame.right, frame.bottom};
-
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerPlaneAlpha(Display display, Layer layer, float alpha) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->info.alpha = alpha;
-
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerSidebandStream(Display display, Layer /* layer */,
-                                    buffer_handle_t /* stream */) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  if (!FindDisplay(display))
-    return Error::BAD_DISPLAY;
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerSourceCrop(Display display, Layer layer,
-                                const hwc_frect_t& crop) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->info.crop = {crop.left, crop.top, crop.right, crop.bottom};
-
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerTransform(Display display, Layer layer,
-                               int32_t transform) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->info.transform = transform;
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerVisibleRegion(Display display, Layer layer,
-                                   const std::vector<hwc_rect_t>& visible) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->info.visible_regions = visible;
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerZOrder(Display display, Layer layer, uint32_t z) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->info.z_order = z;
-
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerInfo(Display display, Layer layer, uint32_t type,
-                          uint32_t appId) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->info.type = type;
-  hwc_layer->info.app_id = appId;
-
-  return Error::NONE;
-}
-
-Error VrHwc::setClientTargetMetadata(
-    Display display, const IVrComposerClient::BufferMetadata& metadata) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  display_ptr->SetClientTargetMetadata(metadata);
-
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerBufferMetadata(
-    Display display, Layer layer,
-    const IVrComposerClient::BufferMetadata& metadata) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
-  if (!hwc_layer)
-    return Error::BAD_LAYER;
-
-  hwc_layer->buffer_metadata = metadata;
-
-  return Error::NONE;
-}
-
-Return<void> VrHwc::getCapabilities(getCapabilities_cb hidl_cb) {
-  hidl_cb(hidl_vec<Capability>());
-  return Void();
-}
-
-Return<void> VrHwc::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
-  std::string result;
-
-  {
-    std::lock_guard<std::mutex> guard(mutex_);
-    result = "\nVrHwc states:\n";
-    for (const auto& pair : displays_) {
-      result += StringPrintf("Display id: %lu\n", (unsigned long)pair.first);
-      pair.second->dumpDebugInfo(&result);
-    }
-    result += "\n";
-  }
-
-  hidl_cb(hidl_string(result));
-  return Void();
-}
-
-Return<void> VrHwc::createClient(createClient_cb hidl_cb) {
-  std::lock_guard<std::mutex> guard(mutex_);
-
-  Error status = Error::NONE;
-  sp<VrComposerClient> client;
-  if (!client_.promote().get()) {
-    client = new VrComposerClient(*this);
-  } else {
-    ALOGE("Already have a client");
-    status = Error::NO_RESOURCES;
-  }
-
-  client_ = client;
-  hidl_cb(status, client);
-  return Void();
-}
-
-Return<void> VrHwc::createClient_2_3(IComposer::createClient_2_3_cb hidl_cb) {
-  std::lock_guard<std::mutex> guard(mutex_);
-
-  Error status = Error::NONE;
-  sp<VrComposerClient> client;
-  if (!client_.promote().get()) {
-    client = new VrComposerClient(*this);
-  } else {
-    ALOGE("Already have a client");
-    status = Error::NO_RESOURCES;
-  }
-
-  client_ = client;
-  hidl_cb(status, client);
-  return Void();
-}
-
-void VrHwc::ForceDisplaysRefresh() {
-  std::lock_guard<std::mutex> guard(mutex_);
-  if (event_callback_ != nullptr) {
-    for (const auto& pair : displays_)
-      event_callback_->onRefresh(pair.first);
-  }
-}
-
-void VrHwc::RegisterObserver(Observer* observer) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  if (observer_)
-    ALOGE("Overwriting observer");
-  else
-    observer_ = observer;
-}
-
-void VrHwc::UnregisterObserver(Observer* observer) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  if (observer != observer_)
-    ALOGE("Trying to unregister unknown observer");
-  else
-    observer_ = nullptr;
-}
-
-HwcDisplay* VrHwc::FindDisplay(Display display) {
-  auto iter = displays_.find(display);
-  return iter == displays_.end() ? nullptr : iter->second.get();
-}
-
-void VrHwc::UpdateVsyncCallbackEnabledLocked() {
-  auto primary_display = FindDisplay(kDefaultDisplayId);
-  LOG_ALWAYS_FATAL_IF(event_callback_ != nullptr && primary_display == nullptr,
-      "Should have created the primary display by now");
-  bool send_vsync =
-      event_callback_ != nullptr && primary_display->vsync_enabled();
-  vsync_callback_->SetEventCallback(send_vsync ? event_callback_ : nullptr);
-}
-
-Return<void> VrHwc::debug(const hidl_handle& fd,
-                          const hidl_vec<hidl_string>& args) {
-  std::string result;
-
-  {
-    std::lock_guard<std::mutex> guard(mutex_);
-    for (const auto& pair : displays_) {
-      result += StringPrintf("Display id: %d\n", static_cast<int>(pair.first));
-      pair.second->dumpDebugInfo(&result);
-    }
-    result += "\n";
-  }
-
-  FILE* out = fdopen(dup(fd->data[0]), "w");
-  fprintf(out, "%s", result.c_str());
-  fclose(out);
-
-  return Void();
-}
-
-void HwcLayer::dumpDebugInfo(std::string* result) const {
-  if (!result) {
-    return;
-  }
-  *result += StringPrintf("Layer: composition_type: %d, type: %d, app_id: %d, z_order: %d,\
-      cursor_x: %d, cursor_y: %d, color(rgba): (%d,%d,%d,%d), dataspace: %d, transform: %d,\
-      display_frame(LTRB): (%d,%d,%d,%d), crop(LTRB): (%.1f,%.1f,%.1f,%.1f), blend_mode: %d\n",
-      composition_type, info.type, info.app_id, info.z_order, info.cursor_x, info.cursor_y,
-      info.color.r, info.color.g, info.color.b, info.color.a, info.dataspace, info.transform,
-      info.display_frame.left, info.display_frame.top, info.display_frame.right,
-      info.display_frame.bottom, info.crop.left, info.crop.top, info.crop.right,
-      info.crop.bottom, info.blend_mode);
-  *result += StringPrintf("Layer buffer metadata: width: %d, height: %d, stride: %d, layerCount: %d\
-      , pixelFormat: %d\n", buffer_metadata.width, buffer_metadata.height, buffer_metadata.stride,
-      buffer_metadata.layerCount, buffer_metadata.format);
-}
-
-status_t VrHwc::VsyncCallback::onVsync(int64_t vsync_timestamp) {
-  ATRACE_NAME("vr_hwc onVsync");
-  std::lock_guard<std::mutex> guard(mutex_);
-  if (callback_ != nullptr)
-    callback_->onVsync(kDefaultDisplayId, vsync_timestamp);
-  return OK;
-}
-
-void VrHwc::VsyncCallback::SetEventCallback(EventCallback* callback) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  callback_ = callback;
-}
-
-// composer::V2_2::ComposerHal
-Error VrHwc::setReadbackBuffer(Display display,
-                               const native_handle_t* bufferHandle,
-                               android::base::unique_fd fenceFd) {
-  return Error::NONE;
-}
-
-Error VrHwc::getReadbackBufferFence(Display display,
-                                    android::base::unique_fd* outFenceFd) {
-  return Error::NONE;
-}
-
-Error VrHwc::createVirtualDisplay_2_2(uint32_t width, uint32_t height,
-                                      types::V1_1::PixelFormat* format,
-                                      Display* outDisplay) {
-  *format = types::V1_1::PixelFormat::RGBA_8888;
-  *outDisplay = display_count_;
-  displays_[display_count_].reset(new HwcDisplay(width, height));
-  display_count_++;
-  return Error::NONE;
-}
-
-Error VrHwc::setPowerMode_2_2(Display display,
-                              IComposerClient::PowerMode mode) {
-  bool dozeSupported = false;
-
-  Error dozeSupportError = getDozeSupport(display, &dozeSupported);
-
-  if (dozeSupportError != Error::NONE)
-    return dozeSupportError;
-
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  if (mode < IComposerClient::PowerMode::OFF ||
-      mode > IComposerClient::PowerMode::DOZE_SUSPEND) {
-    return Error::BAD_PARAMETER;
-  }
-
-  if (!dozeSupported && (mode == IComposerClient::PowerMode::DOZE ||
-                         mode == IComposerClient::PowerMode::DOZE_SUSPEND)) {
-    return Error::UNSUPPORTED;
-  }
-
-  display_ptr->set_power_mode(mode);
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerFloatColor(Display display, Layer layer,
-                                IComposerClient::FloatColor color) {
-  return Error::NONE;
-}
-
-Error VrHwc::getRenderIntents(Display display, types::V1_1::ColorMode mode,
-                              std::vector<RenderIntent>* outIntents) {
-  return Error::NONE;
-}
-
-std::array<float, 16> VrHwc::getDataspaceSaturationMatrix(
-    types::V1_1::Dataspace dataspace) {
-  return {};
-}
-
-// composer::V2_3::ComposerHal
-Error VrHwc::getHdrCapabilities_2_3(Display /*display*/,
-                                    hidl_vec<Hdr>* /*outTypes*/,
-                                    float* outMaxLuminance,
-                                    float* outMaxAverageLuminance,
-                                    float* outMinLuminance) {
-  *outMaxLuminance = 0;
-  *outMaxAverageLuminance = 0;
-  *outMinLuminance = 0;
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerPerFrameMetadata_2_3(
-    Display display, Layer layer,
-    const std::vector<IComposerClient::PerFrameMetadata>& metadata) {
-  return Error::NONE;
-}
-
-Error VrHwc::getPerFrameMetadataKeys_2_3(
-    Display display,
-    std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) {
-  return Error::NONE;
-}
-
-Error VrHwc::setColorMode_2_3(Display display, ColorMode mode,
-                              RenderIntent intent) {
-  std::lock_guard<std::mutex> guard(mutex_);
-  auto display_ptr = FindDisplay(display);
-  if (!display_ptr)
-    return Error::BAD_DISPLAY;
-
-  if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3)
-    return Error::BAD_PARAMETER;
-
-  display_ptr->set_color_mode(mode);
-  return Error::NONE;
-}
-
-Error VrHwc::getRenderIntents_2_3(Display display, ColorMode mode,
-                                  std::vector<RenderIntent>* outIntents) {
-  return Error::NONE;
-}
-
-Error VrHwc::getColorModes_2_3(Display display, hidl_vec<ColorMode>* outModes) {
-  return Error::NONE;
-}
-
-Error VrHwc::getClientTargetSupport_2_3(Display display, uint32_t width,
-                                        uint32_t height, PixelFormat format,
-                                        Dataspace dataspace) {
-  return Error::NONE;
-}
-
-Error VrHwc::getReadbackBufferAttributes_2_3(Display display,
-                                             PixelFormat* outFormat,
-                                             Dataspace* outDataspace) {
-  return Error::NONE;
-}
-
-Error VrHwc::getDisplayIdentificationData(Display display, uint8_t* outPort,
-                                          std::vector<uint8_t>* outData) {
-  int error = 0;
-  auto display_client = display::DisplayClient::Create(&error);
-  if (!display_client) {
-    ALOGE("Could not connect to display service : %s(%d)", strerror(error),
-          error);
-    return Error::BAD_CONFIG;
-  }
-  auto edid_data = display_client->GetConfigurationData(
-      display::ConfigFileType::kDeviceEdid);
-  auto display_identification_port =
-      display_client->GetDisplayIdentificationPort();
-  *outPort = display_identification_port.get();
-
-  std::copy(edid_data.get().begin(), edid_data.get().end(),
-            std::back_inserter(*outData));
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerColorTransform(Display display, Layer layer,
-                                    const float* matrix) {
-  return Error::NONE;
-}
-
-Error VrHwc::getDisplayedContentSamplingAttributes(
-    Display display, PixelFormat& format, Dataspace& dataspace,
-    hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) {
-  return Error::NONE;
-}
-
-Error VrHwc::setDisplayedContentSamplingEnabled(
-    Display display, IComposerClient::DisplayedContentSampling enable,
-    hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
-    uint64_t maxFrames) {
-  return Error::NONE;
-}
-
-Error VrHwc::getDisplayedContentSample(Display display, uint64_t maxFrames,
-                                       uint64_t timestamp, uint64_t& frameCount,
-                                       hidl_vec<uint64_t>& sampleComponent0,
-                                       hidl_vec<uint64_t>& sampleComponent1,
-                                       hidl_vec<uint64_t>& sampleComponent2,
-                                       hidl_vec<uint64_t>& sampleComponent3) {
-  return Error::NONE;
-}
-
-Error VrHwc::getDisplayCapabilities(
-    Display display,
-    std::vector<IComposerClient::DisplayCapability>* outCapabilities) {
-  return Error::NONE;
-}
-
-Error VrHwc::setLayerPerFrameMetadataBlobs(
-    Display display, Layer layer,
-    std::vector<IComposerClient::PerFrameMetadataBlob>& blobs) {
-  return Error::NONE;
-}
-
-Error VrHwc::getDisplayBrightnessSupport(Display display, bool* outSupport) {
-  return Error::NONE;
-}
-
-Error VrHwc::setDisplayBrightness(Display display, float brightness) {
-  return Error::NONE;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
deleted file mode 100644
index 3e3a630..0000000
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_HWC_H
-#define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_HWC_H
-
-#include <android-base/unique_fd.h>
-#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
-#include <android/hardware/graphics/composer/2.3/IComposer.h>
-#include <composer-hal/2.3/ComposerHal.h>
-#include <private/dvr/vsync_service.h>
-#include <ui/Fence.h>
-#include <ui/GraphicBuffer.h>
-#include <utils/StrongPointer.h>
-
-#include <mutex>
-#include <unordered_map>
-
-using namespace android::frameworks::vr::composer::V2_0;
-using namespace android::hardware::graphics::common::V1_0;
-using namespace android::hardware::graphics::composer::V2_3;
-
-using android::hardware::hidl_bitfield;
-using android::hardware::hidl_handle;
-using android::hardware::hidl_string;
-using android::hardware::hidl_vec;
-using android::hardware::Return;
-using android::hardware::Void;
-using android::hardware::graphics::composer::V2_1::Config;
-using android::hardware::graphics::composer::V2_1::Display;
-using android::hardware::graphics::composer::V2_1::Error;
-using android::hardware::graphics::composer::V2_1::Layer;
-using android::hardware::graphics::composer::V2_3::IComposerClient;
-
-namespace android {
-
-class Fence;
-
-namespace dvr {
-
-class VrComposerClient;
-
-using android::hardware::graphics::composer::V2_3::hal::ComposerHal;
-
-namespace types = android::hardware::graphics::common;
-
-using types::V1_1::RenderIntent;
-using types::V1_2::ColorMode;
-using types::V1_2::Dataspace;
-using types::V1_2::Hdr;
-using types::V1_2::PixelFormat;
-
-class ComposerView {
- public:
-  struct ComposerLayer {
-    using Recti = hardware::graphics::composer::V2_3::IComposerClient::Rect;
-    using Rectf = hardware::graphics::composer::V2_3::IComposerClient::FRect;
-    using BlendMode =
-        hardware::graphics::composer::V2_3::IComposerClient::BlendMode;
-
-    Layer id;
-    sp<GraphicBuffer> buffer;
-    sp<Fence> fence;
-    Recti display_frame;
-    Rectf crop;
-    BlendMode blend_mode;
-    float alpha;
-    uint32_t type;
-    uint32_t app_id;
-    uint32_t z_order;
-    int32_t cursor_x;
-    int32_t cursor_y;
-    IComposerClient::Color color;
-    int32_t dataspace;
-    int32_t transform;
-    std::vector<hwc_rect_t> visible_regions;
-    std::vector<hwc_rect_t> damaged_regions;
-  };
-
-  struct Frame {
-    Display display_id;
-    // This is set to true to notify the upper layer that the display is
-    // being removed, or left false in the case of a normal frame. The upper
-    // layer tracks display IDs and will handle new ones showing up.
-    bool removed = false;
-    int32_t display_width;
-    int32_t display_height;
-    Config active_config;
-    ColorMode color_mode;
-    IComposerClient::PowerMode power_mode;
-    IComposerClient::Vsync vsync_enabled;
-    float color_transform[16];
-    int32_t color_transform_hint;
-    std::vector<ComposerLayer> layers;
-  };
-
-  class Observer {
-   public:
-    virtual ~Observer() {}
-
-    // Returns a list of layers that need to be shown together. Layers are
-    // returned in z-order, with the lowest layer first.
-    virtual base::unique_fd OnNewFrame(const Frame& frame) = 0;
-  };
-
-  virtual ~ComposerView() {}
-
-  virtual void ForceDisplaysRefresh() = 0;
-  virtual void RegisterObserver(Observer* observer) = 0;
-  virtual void UnregisterObserver(Observer* observer) = 0;
-};
-
-struct HwcLayer {
-  using Composition =
-      hardware::graphics::composer::V2_3::IComposerClient::Composition;
-
-  explicit HwcLayer(Layer new_id) { info.id = new_id; }
-
-  void dumpDebugInfo(std::string* result) const;
-
-  Composition composition_type;
-  ComposerView::ComposerLayer info;
-  IVrComposerClient::BufferMetadata buffer_metadata;
-};
-
-class HwcDisplay {
- public:
-  HwcDisplay(int32_t width, int32_t height);
-  ~HwcDisplay();
-
-  int32_t width() const { return width_; }
-  int32_t height() const { return height_; }
-
-  HwcLayer* CreateLayer();
-  bool DestroyLayer(Layer id);
-  HwcLayer* GetLayer(Layer id);
-
-  bool SetClientTarget(const native_handle_t* handle, base::unique_fd fence);
-  void SetClientTargetMetadata(
-      const IVrComposerClient::BufferMetadata& metadata);
-
-  void GetChangedCompositionTypes(
-      std::vector<Layer>* layer_ids,
-      std::vector<IComposerClient::Composition>* composition);
-
-  Error GetFrame(std::vector<ComposerView::ComposerLayer>* out_frame);
-
-  std::vector<Layer> UpdateLastFrameAndGetLastFrameLayers();
-
-  Config active_config() const { return active_config_; }
-  void set_active_config(Config config) { active_config_ = config; }
-
-  ColorMode color_mode() const { return color_mode_; }
-  void set_color_mode(ColorMode mode) { color_mode_ = mode; }
-
-  IComposerClient::PowerMode power_mode() const { return power_mode_; }
-  void set_power_mode(IComposerClient::PowerMode mode) { power_mode_ = mode; }
-
-  bool vsync_enabled() const { return vsync_enabled_; }
-  void set_vsync_enabled(bool vsync) {vsync_enabled_ = vsync;}
-
-  const float* color_transform() const { return color_transform_; }
-  int32_t color_transform_hint() const { return color_transform_hint_; }
-  void SetColorTransform(const float* matrix, int32_t hint);
-
-  void dumpDebugInfo(std::string* result) const;
-
- private:
-  // The client target buffer and the associated fence.
-  sp<GraphicBuffer> buffer_;
-  IVrComposerClient::BufferMetadata buffer_metadata_;
-  sp<Fence> fence_;
-
-  // List of currently active layers.
-  std::vector<HwcLayer> layers_;
-
-  std::vector<Layer> last_frame_layers_ids_;
-
-  // Layer ID generator.
-  uint64_t layer_ids_ = 1;
-
-  int32_t width_;
-  int32_t height_;
-
-  Config active_config_;
-  ColorMode color_mode_;
-  IComposerClient::PowerMode power_mode_;
-  bool vsync_enabled_ = false;
-  float color_transform_[16];
-  int32_t color_transform_hint_;
-
-  HwcDisplay(const HwcDisplay&) = delete;
-  void operator=(const HwcDisplay&) = delete;
-};
-
-class VrHwc : public IComposer, public ComposerHal, public ComposerView {
- public:
-  VrHwc();
-  ~VrHwc() override;
-
-  Error setLayerInfo(Display display, Layer layer, uint32_t type,
-                     uint32_t appId);
-  Error setClientTargetMetadata(
-      Display display, const IVrComposerClient::BufferMetadata& metadata);
-  Error setLayerBufferMetadata(
-      Display display, Layer layer,
-      const IVrComposerClient::BufferMetadata& metadata);
-
-  // composer::V2_1::ComposerHal
-  bool hasCapability(hwc2_capability_t capability) override;
-
-  std::string dumpDebugInfo() override { return {}; }
-
-  void registerEventCallback(ComposerHal::EventCallback* callback) override;
-  void unregisterEventCallback() override;
-
-  uint32_t getMaxVirtualDisplayCount() override;
-  Error destroyVirtualDisplay(Display display) override;
-
-  Error createLayer(Display display, Layer* outLayer) override;
-  Error destroyLayer(Display display, Layer layer) override;
-
-  Error getActiveConfig(Display display, Config* outConfig) override;
-  Error getDisplayAttribute(Display display, Config config,
-                            IComposerClient::Attribute attribute,
-                            int32_t* outValue) override;
-  Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override;
-  Error getDisplayName(Display display, hidl_string* outName) override;
-  Error getDisplayType(Display display,
-                       IComposerClient::DisplayType* outType) override;
-  Error getDozeSupport(Display display, bool* outSupport) override;
-
-  Error setActiveConfig(Display display, Config config) override;
-  Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
-
-  Error setColorTransform(Display display, const float* matrix,
-                          int32_t hint) override;
-  Error setClientTarget(Display display, buffer_handle_t target,
-                        int32_t acquireFence, int32_t dataspace,
-                        const std::vector<hwc_rect_t>& damage) override;
-  Error setOutputBuffer(Display display, buffer_handle_t buffer,
-                        int32_t releaseFence) override;
-  Error validateDisplay(
-      Display display, std::vector<Layer>* outChangedLayers,
-      std::vector<IComposerClient::Composition>* outCompositionTypes,
-      uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
-      std::vector<uint32_t>* outRequestMasks) override;
-  Error acceptDisplayChanges(Display display) override;
-  Error presentDisplay(Display display, int32_t* outPresentFence,
-                       std::vector<Layer>* outLayers,
-                       std::vector<int32_t>* outReleaseFences) override;
-
-  Error setLayerCursorPosition(Display display, Layer layer, int32_t x,
-                               int32_t y) override;
-  Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
-                       int32_t acquireFence) override;
-  Error setLayerSurfaceDamage(Display display, Layer layer,
-                              const std::vector<hwc_rect_t>& damage) override;
-  Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override;
-  Error setLayerColor(Display display, Layer layer,
-                      IComposerClient::Color color) override;
-  Error setLayerCompositionType(Display display, Layer layer,
-                                int32_t type) override;
-  Error setLayerDataspace(Display display, Layer layer,
-                          int32_t dataspace) override;
-  Error setLayerDisplayFrame(Display display, Layer layer,
-                             const hwc_rect_t& frame) override;
-  Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
-  Error setLayerSidebandStream(Display display, Layer layer,
-                               buffer_handle_t stream) override;
-  Error setLayerSourceCrop(Display display, Layer layer,
-                           const hwc_frect_t& crop) override;
-  Error setLayerTransform(Display display, Layer layer,
-                          int32_t transform) override;
-  Error setLayerVisibleRegion(Display display, Layer layer,
-                              const std::vector<hwc_rect_t>& visible) override;
-  Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
-
-  // composer::V2_2::ComposerHal
-  Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle,
-                          android::base::unique_fd fenceFd) override;
-  Error getReadbackBufferFence(Display display,
-                               android::base::unique_fd* outFenceFd) override;
-  Error createVirtualDisplay_2_2(uint32_t width, uint32_t height,
-                                 types::V1_1::PixelFormat* format,
-                                 Display* outDisplay) override;
-  Error setPowerMode_2_2(Display display,
-                         IComposerClient::PowerMode mode) override;
-  Error setLayerFloatColor(Display display, Layer layer,
-                           IComposerClient::FloatColor color) override;
-  Error getRenderIntents(Display display, types::V1_1::ColorMode mode,
-                         std::vector<RenderIntent>* outIntents) override;
-  std::array<float, 16> getDataspaceSaturationMatrix(
-      types::V1_1::Dataspace dataspace) override;
-
-  // composer::V2_3::ComposerHal
-  Error getHdrCapabilities_2_3(Display display, hidl_vec<Hdr>* outTypes,
-                               float* outMaxLuminance,
-                               float* outMaxAverageLuminance,
-                               float* outMinLuminance) override;
-  Error setLayerPerFrameMetadata_2_3(
-      Display display, Layer layer,
-      const std::vector<IComposerClient::PerFrameMetadata>& metadata) override;
-  Error getPerFrameMetadataKeys_2_3(
-      Display display,
-      std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) override;
-  Error setColorMode_2_3(Display display, ColorMode mode,
-                         RenderIntent intent) override;
-  Error getRenderIntents_2_3(Display display, ColorMode mode,
-                             std::vector<RenderIntent>* outIntents) override;
-  Error getColorModes_2_3(Display display,
-                          hidl_vec<ColorMode>* outModes) override;
-  Error getClientTargetSupport_2_3(Display display, uint32_t width,
-                                   uint32_t height, PixelFormat format,
-                                   Dataspace dataspace) override;
-  Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat,
-                                        Dataspace* outDataspace) override;
-  Error getDisplayIdentificationData(Display display, uint8_t* outPort,
-                                     std::vector<uint8_t>* outData) override;
-  Error setLayerColorTransform(Display display, Layer layer,
-                               const float* matrix) override;
-  Error getDisplayedContentSamplingAttributes(
-      Display display, PixelFormat& format, Dataspace& dataspace,
-      hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask)
-      override;
-  Error setDisplayedContentSamplingEnabled(
-      Display display, IComposerClient::DisplayedContentSampling enable,
-      hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
-      uint64_t maxFrames) override;
-  Error getDisplayedContentSample(
-      Display display, uint64_t maxFrames, uint64_t timestamp,
-      uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0,
-      hidl_vec<uint64_t>& sampleComponent1,
-      hidl_vec<uint64_t>& sampleComponent2,
-      hidl_vec<uint64_t>& sampleComponent3) override;
-  Error getDisplayCapabilities(Display display,
-                               std::vector<IComposerClient::DisplayCapability>*
-                                   outCapabilities) override;
-  Error setLayerPerFrameMetadataBlobs(
-      Display display, Layer layer,
-      std::vector<IComposerClient::PerFrameMetadataBlob>& blobs) override;
-  Error getDisplayBrightnessSupport(Display display, bool* outSupport) override;
-  Error setDisplayBrightness(Display display, float brightness) override;
-
-  // IComposer:
-  Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
-  Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
-  Return<void> createClient(createClient_cb hidl_cb) override;
-  Return<void> createClient_2_3(
-      IComposer::createClient_2_3_cb hidl_cb) override;
-
-  // ComposerView:
-  void ForceDisplaysRefresh() override;
-  void RegisterObserver(Observer* observer) override;
-  void UnregisterObserver(Observer* observer) override;
-
-  Return<void> debug(const hidl_handle& fd,
-                     const hidl_vec<hidl_string>& args) override;
-
- private:
-  class VsyncCallback : public BnVsyncCallback {
-   public:
-    status_t onVsync(int64_t vsync_timestamp) override;
-    void SetEventCallback(EventCallback* callback);
-   private:
-    std::mutex mutex_;
-    EventCallback* callback_;
-  };
-
-  HwcDisplay* FindDisplay(Display display);
-
-  // Re-evaluate whether or not we should start making onVsync() callbacks to
-  // the client. We need enableCallback(true) to have been called, and
-  // setVsyncEnabled() to have been called for the primary display. The caller
-  // must have mutex_ locked already.
-  void UpdateVsyncCallbackEnabledLocked();
-
-  wp<VrComposerClient> client_;
-
-  // Guard access to internal state from binder threads.
-  std::mutex mutex_;
-
-  std::unordered_map<Display, std::unique_ptr<HwcDisplay>> displays_;
-  Display display_count_ = 2;
-
-  EventCallback* event_callback_ = nullptr;
-  Observer* observer_ = nullptr;
-
-  sp<VsyncCallback> vsync_callback_;
-
-  VrHwc(const VrHwc&) = delete;
-  void operator=(const VrHwc&) = delete;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_HWC_H
diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp
deleted file mode 100644
index 2e70928..0000000
--- a/services/vr/hardware_composer/tests/vr_composer_test.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-#include <android/dvr/BnVrComposerCallback.h>
-#include <binder/IServiceManager.h>
-#include <gtest/gtest.h>
-#include <sys/eventfd.h>
-#include <vr_composer.h>
-
-namespace android {
-namespace dvr {
-namespace {
-
-const char kVrDisplayName[] = "VrDisplay_Test";
-
-class TestComposerView : public ComposerView {
- public:
-  TestComposerView() {}
-  ~TestComposerView() override = default;
-
-  size_t display_refresh_count() const { return display_refresh_count_; }
-
-  void ForceDisplaysRefresh() override { display_refresh_count_++; }
-  void RegisterObserver(Observer* observer) override {}
-  void UnregisterObserver(Observer* observer) override {}
-
-  TestComposerView(const TestComposerView&) = delete;
-  void operator=(const TestComposerView&) = delete;
-
- private:
-  size_t display_refresh_count_ = 0;
-};
-
-class TestComposerCallback : public BnVrComposerCallback {
- public:
-  TestComposerCallback() {}
-  ~TestComposerCallback() override = default;
-
-  ComposerView::Frame last_frame() const { return last_frame_; }
-
-  binder::Status onNewFrame(
-      const ParcelableComposerFrame& frame,
-      ParcelableUniqueFd* /* fence */) override {
-    last_frame_ = frame.frame();
-    return binder::Status::ok();
-  }
-
- private:
-  ComposerView::Frame last_frame_;
-
-  TestComposerCallback(const TestComposerCallback&) = delete;
-  void operator=(const TestComposerCallback&) = delete;
-};
-
-class TestComposerCallbackWithFence : public TestComposerCallback {
- public:
-  ~TestComposerCallbackWithFence() override = default;
-
-  binder::Status onNewFrame(
-      const ParcelableComposerFrame& frame,
-      ParcelableUniqueFd* fence) override {
-    binder::Status status = TestComposerCallback::onNewFrame(frame, fence);
-
-    base::unique_fd fd(eventfd(0, 0));
-    EXPECT_LE(0, fd.get());
-    fence->set_fence(fd);
-
-    return status;
-  }
-};
-
-sp<GraphicBuffer> CreateBuffer() {
-  return new GraphicBuffer(600, 400, PIXEL_FORMAT_RGBA_8888,
-                           GraphicBuffer::USAGE_HW_TEXTURE);
-}
-
-}  // namespace
-
-class VrComposerTest : public testing::Test {
- public:
-  VrComposerTest() : composer_(new VrComposer(&composer_view_)) {}
-  ~VrComposerTest() override = default;
-
-  sp<IVrComposer> GetComposerProxy() const {
-    sp<IServiceManager> sm(defaultServiceManager());
-    return interface_cast<IVrComposer>(sm->getService(String16(kVrDisplayName)));
-  }
-
-  void SetUp() override {
-    sp<IServiceManager> sm(defaultServiceManager());
-    EXPECT_EQ(OK,
-              sm->addService(String16(kVrDisplayName), composer_, false));
-  }
-
- protected:
-  TestComposerView composer_view_;
-  sp<VrComposer> composer_;
-
-  VrComposerTest(const VrComposerTest&) = delete;
-  void operator=(const VrComposerTest&) = delete;
-};
-
-TEST_F(VrComposerTest, TestWithoutObserver) {
-  sp<IVrComposer> composer = GetComposerProxy();
-  ComposerView::Frame frame;
-
-  base::unique_fd fence = composer_->OnNewFrame(frame);
-  ASSERT_EQ(-1, fence.get());
-}
-
-TEST_F(VrComposerTest, TestWithObserver) {
-  sp<IVrComposer> composer = GetComposerProxy();
-  sp<TestComposerCallback> callback = new TestComposerCallback();
-  ASSERT_EQ(0, composer_view_.display_refresh_count());
-  ASSERT_TRUE(composer->registerObserver(callback).isOk());
-  ASSERT_EQ(1, composer_view_.display_refresh_count());
-
-  ComposerView::Frame frame;
-  base::unique_fd fence = composer_->OnNewFrame(frame);
-  ASSERT_EQ(-1, fence.get());
-}
-
-TEST_F(VrComposerTest, TestWithOneLayer) {
-  sp<IVrComposer> composer = GetComposerProxy();
-  sp<TestComposerCallback> callback = new TestComposerCallbackWithFence();
-  ASSERT_TRUE(composer->registerObserver(callback).isOk());
-
-  ComposerView::Frame frame;
-  frame.display_id = 1;
-  frame.removed = false;
-  frame.display_width = 600;
-  frame.display_height = 400;
-  frame.layers.push_back(ComposerView::ComposerLayer{
-    .id = 1,
-    .buffer = CreateBuffer(),
-    .fence = new Fence(eventfd(0, 0)),
-    .display_frame = {0, 0, 600, 400},
-    .crop = {0.0f, 0.0f, 600.0f, 400.0f},
-    .blend_mode = IComposerClient::BlendMode::NONE,
-    .alpha = 1.0f,
-    .type = 1,
-    .app_id = 1,
-  });
-  base::unique_fd fence = composer_->OnNewFrame(frame);
-  ASSERT_LE(0, fence.get());
-
-  ComposerView::Frame received_frame = callback->last_frame();
-  ASSERT_EQ(frame.display_id, received_frame.display_id);
-  ASSERT_EQ(frame.display_width, received_frame.display_width);
-  ASSERT_EQ(frame.display_height, received_frame.display_height);
-  ASSERT_EQ(frame.removed, received_frame.removed);
-  ASSERT_EQ(1u, received_frame.layers.size());
-  ASSERT_EQ(frame.layers[0].id, received_frame.layers[0].id);
-  ASSERT_NE(nullptr, received_frame.layers[0].buffer.get());
-  ASSERT_TRUE(received_frame.layers[0].fence->isValid());
-  ASSERT_EQ(frame.layers[0].display_frame.left,
-            received_frame.layers[0].display_frame.left);
-  ASSERT_EQ(frame.layers[0].display_frame.top,
-            received_frame.layers[0].display_frame.top);
-  ASSERT_EQ(frame.layers[0].display_frame.right,
-            received_frame.layers[0].display_frame.right);
-  ASSERT_EQ(frame.layers[0].display_frame.bottom,
-            received_frame.layers[0].display_frame.bottom);
-  ASSERT_EQ(frame.layers[0].crop.left, received_frame.layers[0].crop.left);
-  ASSERT_EQ(frame.layers[0].crop.top, received_frame.layers[0].crop.top);
-  ASSERT_EQ(frame.layers[0].crop.right, received_frame.layers[0].crop.right);
-  ASSERT_EQ(frame.layers[0].crop.bottom, received_frame.layers[0].crop.bottom);
-  ASSERT_EQ(frame.layers[0].blend_mode, received_frame.layers[0].blend_mode);
-  ASSERT_EQ(frame.layers[0].alpha, received_frame.layers[0].alpha);
-  ASSERT_EQ(frame.layers[0].type, received_frame.layers[0].type);
-  ASSERT_EQ(frame.layers[0].app_id, received_frame.layers[0].app_id);
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp
deleted file mode 100644
index d93f370..0000000
--- a/services/vr/hardware_composer/vr_composer.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-#include "vr_composer.h"
-
-#include <binder/IPCThreadState.h>
-#include <binder/PermissionCache.h>
-
-namespace android {
-namespace dvr {
-namespace {
-
-bool CheckPermission() {
-  const android::IPCThreadState* ipc = android::IPCThreadState::self();
-  const pid_t pid = ipc->getCallingPid();
-  const uid_t uid = ipc->getCallingUid();
-  const bool permission = PermissionCache::checkPermission(
-      String16("android.permission.RESTRICTED_VR_ACCESS"), pid, uid);
-  if (!permission)
-    ALOGE("permission denied to pid=%d uid=%u", pid, uid);
-
-  return permission;
-}
-
-}  // namespace
-
-VrComposer::VrComposer(ComposerView* composer_view)
-  : composer_view_(composer_view) {
-  composer_view_->RegisterObserver(this);
-}
-
-VrComposer::~VrComposer() {
-  composer_view_->UnregisterObserver(this);
-}
-
-binder::Status VrComposer::registerObserver(
-    const sp<IVrComposerCallback>& callback) {
-  {
-    std::lock_guard<std::mutex> guard(mutex_);
-
-    if (!CheckPermission())
-      return binder::Status::fromStatusT(PERMISSION_DENIED);
-
-    if (callback_.get()) {
-      ALOGE("Failed to register callback, already registered");
-      return binder::Status::fromStatusT(ALREADY_EXISTS);
-    }
-
-    callback_ = callback;
-    IInterface::asBinder(callback_)->linkToDeath(this);
-  }
-
-  // Don't take the lock to force display refresh otherwise it could end in a
-  // deadlock since HWC calls this with new frames and it has a lock of its own
-  // to serialize access to the display information.
-  composer_view_->ForceDisplaysRefresh();
-  return binder::Status::ok();
-}
-
-binder::Status VrComposer::clearObserver() {
-  std::lock_guard<std::mutex> guard(mutex_);
-  callback_ = nullptr;
-  return binder::Status::ok();
-}
-
-base::unique_fd VrComposer::OnNewFrame(const ComposerView::Frame& frame) {
-  std::lock_guard<std::mutex> guard(mutex_);
-
-  if (!callback_.get())
-    return base::unique_fd();
-
-  ParcelableComposerFrame parcelable_frame(frame);
-  ParcelableUniqueFd fence;
-  binder::Status ret = callback_->onNewFrame(parcelable_frame, &fence);
-  if (!ret.isOk())
-    ALOGE("Failed to send new frame: %s", ret.toString8().string());
-
-  return fence.fence();
-}
-
-void VrComposer::binderDied(const wp<IBinder>& /* who */) {
-  std::lock_guard<std::mutex> guard(mutex_);
-
-  callback_ = nullptr;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h
deleted file mode 100644
index 1273352..0000000
--- a/services/vr/hardware_composer/vr_composer.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
-#define ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
-
-#include <android/dvr/BnVrComposer.h>
-#include <impl/vr_hwc.h>
-
-namespace android {
-namespace dvr {
-
-class VrComposerCallback;
-
-// Implementation of the IVrComposer service used to notify VR Window Manager
-// when SurfaceFlinger presents 2D UI changes.
-//
-// VR HWC updates the presented frame via the ComposerView::Observer interface.
-// On notification |callback_| is called to update VR Window Manager.
-// NOTE: If VR Window Manager isn't connected, the notification is a no-op.
-class VrComposer
-    : public BnVrComposer,
-      public ComposerView::Observer,
-      public IBinder::DeathRecipient {
- public:
-  explicit VrComposer(ComposerView* composer_view);
-  ~VrComposer() override;
-
-  // BnVrComposer:
-  binder::Status registerObserver(
-      const sp<IVrComposerCallback>& callback) override;
-
-  binder::Status clearObserver() override;
-
-  // ComposerView::Observer:
-  base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
-
- private:
-  // IBinder::DeathRecipient:
-  void binderDied(const wp<IBinder>& who) override;
-
-  std::mutex mutex_;
-
-  sp<IVrComposerCallback> callback_;
-
-  ComposerView* composer_view_;  // Not owned.
-
-  VrComposer(const VrComposer&) = delete;
-  void operator=(const VrComposer&) = delete;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  //  ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h
index ba98696..40cf9fb 100644
--- a/vulkan/include/vulkan/vk_android_native_buffer.h
+++ b/vulkan/include/vulkan/vk_android_native_buffer.h
@@ -49,7 +49,13 @@
  * in VkBindImageMemorySwapchainInfoKHR will be additionally chained to the
  * pNext chain of VkBindImageMemoryInfo and passed down to the driver.
  */
-#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 8
+/*
+ * NOTE ON VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 9
+ *
+ * This version of the extension is largely designed to clean up the mix of
+ * GrallocUsage and GrallocUsage2
+ */
+#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 9
 #define VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME "VK_ANDROID_native_buffer"
 
 #define VK_ANDROID_NATIVE_BUFFER_ENUM(type, id) \
@@ -61,6 +67,8 @@
     VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 1)
 #define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID \
     VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 2)
+#define VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID \
+    VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 3)
 
 /* clang-format off */
 typedef enum VkSwapchainImageUsageFlagBitsANDROID {
@@ -90,6 +98,7 @@
  * format: gralloc format requested when the buffer was allocated
  * usage: gralloc usage requested when the buffer was allocated
  * usage2: gralloc usage requested when the buffer was allocated
+ * usage3: gralloc usage requested when the buffer was allocated
  */
 typedef struct {
     VkStructureType                   sType;
@@ -98,7 +107,8 @@
     int                               stride;
     int                               format;
     int                               usage; /* DEPRECATED in SPEC_VERSION 6 */
-    VkNativeBufferUsage2ANDROID       usage2; /* ADDED in SPEC_VERSION 6 */
+    VkNativeBufferUsage2ANDROID       usage2; /* DEPRECATED in SPEC_VERSION 9 */
+    uint64_t                          usage3; /* ADDED in SPEC_VERSION 9 */
 } VkNativeBufferANDROID;
 
 /*
@@ -127,6 +137,21 @@
     VkBool32                          sharedImage;
 } VkPhysicalDevicePresentationPropertiesANDROID;
 
+/*
+ * struct VkGrallocUsageInfoANDROID
+ *
+ * sType: VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID
+ * pNext: NULL or a pointer to a structure extending this structure
+ * format: value specifying the format the image will be created with
+ * imageUsage: bitmask of VkImageUsageFlagBits describing intended usage
+ */
+typedef struct {
+    VkStructureType                   sType;
+    const void*                       pNext;
+    VkFormat                          format;
+    VkImageUsageFlags                 imageUsage;
+} VkGrallocUsageInfoANDROID;
+
 /* DEPRECATED in SPEC_VERSION 6 */
 typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsageANDROID)(
     VkDevice                          device,
@@ -134,7 +159,7 @@
     VkImageUsageFlags                 imageUsage,
     int*                              grallocUsage);
 
-/* ADDED in SPEC_VERSION 6 */
+/* DEPRECATED in SPEC_VERSION 9 */
 typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsage2ANDROID)(
     VkDevice                          device,
     VkFormat                          format,
@@ -143,6 +168,12 @@
     uint64_t*                         grallocConsumerUsage,
     uint64_t*                         grallocProducerUsage);
 
+/* ADDED in SPEC_VERSION 9 */
+typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsage3ANDROID)(
+    VkDevice                          device,
+    const VkGrallocUsageInfoANDROID*  grallocUsageInfo,
+    uint64_t*                         grallocUsage);
+
 typedef VkResult (VKAPI_PTR *PFN_vkAcquireImageANDROID)(
     VkDevice                          device,
     VkImage                           image,
@@ -167,7 +198,7 @@
     int*                              grallocUsage
 );
 
-/* ADDED in SPEC_VERSION 6 */
+/* DEPRECATED in SPEC_VERSION 9 */
 VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsage2ANDROID(
     VkDevice                          device,
     VkFormat                          format,
@@ -177,6 +208,13 @@
     uint64_t*                         grallocProducerUsage
 );
 
+/* ADDED in SPEC_VERSION 9 */
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsage3ANDROID(
+    VkDevice                          device,
+    const VkGrallocUsageInfoANDROID*  grallocUsageInfo,
+    uint64_t*                         grallocUsage
+);
+
 VKAPI_ATTR VkResult VKAPI_CALL vkAcquireImageANDROID(
     VkDevice                          device,
     VkImage                           image,
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index df70bf4..a9706bc 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -682,6 +682,7 @@
         "vkGetPhysicalDeviceMemoryProperties2",
         "vkGetPhysicalDeviceMemoryProperties2KHR",
         "vkGetPhysicalDeviceMultisamplePropertiesEXT",
+        "vkGetPhysicalDeviceOpticalFlowImageFormatsNV",
         "vkGetPhysicalDevicePresentRectanglesKHR",
         "vkGetPhysicalDeviceProperties",
         "vkGetPhysicalDeviceProperties2",
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 7664518..a99355f 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -1027,6 +1027,51 @@
     }
 }
 
+VkResult GetAndroidNativeBufferSpecVersion9Support(
+    VkPhysicalDevice physicalDevice,
+    bool& support) {
+    support = false;
+
+    const InstanceData& data = GetData(physicalDevice);
+
+    // Call to get propertyCount
+    uint32_t propertyCount = 0;
+    ATRACE_BEGIN("driver.EnumerateDeviceExtensionProperties");
+    VkResult result = data.driver.EnumerateDeviceExtensionProperties(
+        physicalDevice, nullptr, &propertyCount, nullptr);
+    ATRACE_END();
+
+    if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
+        return result;
+    }
+
+    // Call to enumerate properties
+    std::vector<VkExtensionProperties> properties(propertyCount);
+    ATRACE_BEGIN("driver.EnumerateDeviceExtensionProperties");
+    result = data.driver.EnumerateDeviceExtensionProperties(
+        physicalDevice, nullptr, &propertyCount, properties.data());
+    ATRACE_END();
+
+    if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
+        return result;
+    }
+
+    for (uint32_t i = 0; i < propertyCount; i++) {
+        auto& prop = properties[i];
+
+        if (strcmp(prop.extensionName,
+                   VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) != 0)
+            continue;
+
+        if (prop.specVersion >= 9) {
+            support = true;
+            return result;
+        }
+    }
+
+    return result;
+}
+
 VkResult EnumerateDeviceExtensionProperties(
     VkPhysicalDevice physicalDevice,
     const char* pLayerName,
@@ -1061,6 +1106,49 @@
                 VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION});
     }
 
+    // Conditionally add VK_EXT_IMAGE_COMPRESSION_CONTROL* if feature and ANB
+    // support is provided by the driver
+    VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT
+        swapchainCompFeats = {};
+    swapchainCompFeats.sType =
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT;
+    swapchainCompFeats.pNext = nullptr;
+    swapchainCompFeats.imageCompressionControlSwapchain = false;
+    VkPhysicalDeviceImageCompressionControlFeaturesEXT imageCompFeats = {};
+    imageCompFeats.sType =
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT;
+    imageCompFeats.pNext = &swapchainCompFeats;
+    imageCompFeats.imageCompressionControl = false;
+
+    VkPhysicalDeviceFeatures2 feats2 = {};
+    feats2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+    feats2.pNext = &imageCompFeats;
+
+    const auto& driver = GetData(physicalDevice).driver;
+    if (driver.GetPhysicalDeviceFeatures2 ||
+        driver.GetPhysicalDeviceFeatures2KHR) {
+        GetPhysicalDeviceFeatures2(physicalDevice, &feats2);
+    }
+
+    bool anb9 = false;
+    VkResult result =
+        GetAndroidNativeBufferSpecVersion9Support(physicalDevice, anb9);
+
+    if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
+        return result;
+    }
+
+    if (anb9 && imageCompFeats.imageCompressionControl) {
+        loader_extensions.push_back(
+            {VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME,
+             VK_EXT_IMAGE_COMPRESSION_CONTROL_SPEC_VERSION});
+    }
+    if (anb9 && swapchainCompFeats.imageCompressionControlSwapchain) {
+        loader_extensions.push_back(
+            {VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME,
+             VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION});
+    }
+
     // enumerate our extensions first
     if (!pLayerName && pProperties) {
         uint32_t count = std::min(
@@ -1078,7 +1166,7 @@
     }
 
     ATRACE_BEGIN("driver.EnumerateDeviceExtensionProperties");
-    VkResult result = data.driver.EnumerateDeviceExtensionProperties(
+    result = data.driver.EnumerateDeviceExtensionProperties(
         physicalDevice, pLayerName, pPropertyCount, pProperties);
     ATRACE_END();
 
@@ -1254,15 +1342,18 @@
         return VK_ERROR_INCOMPATIBLE_DRIVER;
     }
 
-    // sanity check ANDROID_native_buffer implementation, whose set of
+    // Confirming ANDROID_native_buffer implementation, whose set of
     // entrypoints varies according to the spec version.
     if ((wrapper.GetHalExtensions()[ProcHook::ANDROID_native_buffer]) &&
         !data->driver.GetSwapchainGrallocUsageANDROID &&
-        !data->driver.GetSwapchainGrallocUsage2ANDROID) {
-        ALOGE("Driver's implementation of ANDROID_native_buffer is broken;"
-              " must expose at least one of "
-              "vkGetSwapchainGrallocUsageANDROID or "
-              "vkGetSwapchainGrallocUsage2ANDROID");
+        !data->driver.GetSwapchainGrallocUsage2ANDROID &&
+        !data->driver.GetSwapchainGrallocUsage3ANDROID) {
+        ALOGE(
+            "Driver's implementation of ANDROID_native_buffer is broken;"
+            " must expose at least one of "
+            "vkGetSwapchainGrallocUsageANDROID or "
+            "vkGetSwapchainGrallocUsage2ANDROID or "
+            "vkGetSwapchainGrallocUsage3ANDROID");
 
         data->driver.DestroyDevice(dev, pAllocator);
         FreeDeviceData(data, data_allocator);
@@ -1441,10 +1532,89 @@
 
     if (driver.GetPhysicalDeviceFeatures2) {
         driver.GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
+    } else {
+        driver.GetPhysicalDeviceFeatures2KHR(physicalDevice, pFeatures);
+    }
+
+    // Conditionally add imageCompressionControlSwapchain if
+    // imageCompressionControl is supported Check for imageCompressionControl in
+    // the pChain
+    bool imageCompressionControl = false;
+    bool imageCompressionControlInChain = false;
+    bool imageCompressionControlSwapchainInChain = false;
+    VkPhysicalDeviceFeatures2* pFeats = pFeatures;
+    while (pFeats) {
+        switch (pFeats->sType) {
+            case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT: {
+                const VkPhysicalDeviceImageCompressionControlFeaturesEXT*
+                    compressionFeat = reinterpret_cast<
+                        const VkPhysicalDeviceImageCompressionControlFeaturesEXT*>(
+                        pFeats);
+                imageCompressionControl =
+                    compressionFeat->imageCompressionControl;
+                imageCompressionControlInChain = true;
+            } break;
+
+            case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT: {
+                VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT*
+                    compressionFeat = reinterpret_cast<
+                        VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT*>(
+                        pFeats);
+                compressionFeat->imageCompressionControlSwapchain = false;
+                imageCompressionControlSwapchainInChain = true;
+            } break;
+
+            default:
+                break;
+        }
+        pFeats = reinterpret_cast<VkPhysicalDeviceFeatures2*>(pFeats->pNext);
+    }
+
+    if (!imageCompressionControlSwapchainInChain) {
         return;
     }
 
-    driver.GetPhysicalDeviceFeatures2KHR(physicalDevice, pFeatures);
+    // If not in pchain, explicitly query for imageCompressionControl
+    if (!imageCompressionControlInChain) {
+        VkPhysicalDeviceImageCompressionControlFeaturesEXT imageCompFeats = {};
+        imageCompFeats.sType =
+            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT;
+        imageCompFeats.pNext = nullptr;
+        imageCompFeats.imageCompressionControl = false;
+
+        VkPhysicalDeviceFeatures2 feats2 = {};
+        feats2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+        feats2.pNext = &imageCompFeats;
+
+        if (driver.GetPhysicalDeviceFeatures2) {
+            driver.GetPhysicalDeviceFeatures2(physicalDevice, &feats2);
+        } else {
+            driver.GetPhysicalDeviceFeatures2KHR(physicalDevice, &feats2);
+        }
+
+        imageCompressionControl = imageCompFeats.imageCompressionControl;
+    }
+
+    // Only enumerate imageCompressionControlSwapchin if imageCompressionControl
+    if (imageCompressionControl) {
+        pFeats = pFeatures;
+        while (pFeats) {
+            switch (pFeats->sType) {
+                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT: {
+                    VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT*
+                        compressionFeat = reinterpret_cast<
+                            VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT*>(
+                            pFeats);
+                    compressionFeat->imageCompressionControlSwapchain = true;
+                } break;
+
+                default:
+                    break;
+            }
+            pFeats =
+                reinterpret_cast<VkPhysicalDeviceFeatures2*>(pFeats->pNext);
+        }
+    }
 }
 
 void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 14c516b..4d2bbd6 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -107,6 +107,8 @@
     VkPhysicalDevice physicalDevice,
     VkPhysicalDevicePresentationPropertiesANDROID* presentation_properties);
 
+bool GetAndroidNativeBufferSpecVersion9Support(VkPhysicalDevice physicalDevice);
+
 VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance,
                                                   const char* pName);
 VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device,
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index b436db1..de98aa7 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -496,6 +496,13 @@
         nullptr,
     },
     {
+        "vkGetSwapchainGrallocUsage3ANDROID",
+        ProcHook::DEVICE,
+        ProcHook::ANDROID_native_buffer,
+        nullptr,
+        nullptr,
+    },
+    {
         "vkGetSwapchainGrallocUsageANDROID",
         ProcHook::DEVICE,
         ProcHook::ANDROID_native_buffer,
@@ -664,6 +671,7 @@
     INIT_PROC(false, dev, GetDeviceQueue2);
     INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsageANDROID);
     INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage2ANDROID);
+    INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage3ANDROID);
     INIT_PROC_EXT(ANDROID_native_buffer, true, dev, AcquireImageANDROID);
     INIT_PROC_EXT(ANDROID_native_buffer, true, dev, QueueSignalReleaseImageANDROID);
     // clang-format on
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 079f9cc..2f60086 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -123,6 +123,7 @@
     PFN_vkGetDeviceQueue2 GetDeviceQueue2;
     PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
     PFN_vkGetSwapchainGrallocUsage2ANDROID GetSwapchainGrallocUsage2ANDROID;
+    PFN_vkGetSwapchainGrallocUsage3ANDROID GetSwapchainGrallocUsage3ANDROID;
     PFN_vkAcquireImageANDROID AcquireImageANDROID;
     PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
     // clang-format on
diff --git a/vulkan/libvulkan/libvulkan.map.txt b/vulkan/libvulkan/libvulkan.map.txt
index f49e8f3..b189c68 100644
--- a/vulkan/libvulkan/libvulkan.map.txt
+++ b/vulkan/libvulkan/libvulkan.map.txt
@@ -178,6 +178,7 @@
     vkGetImageSparseMemoryRequirements;
     vkGetImageSparseMemoryRequirements2; # introduced=28
     vkGetImageSubresourceLayout;
+    vkGetImageSubresourceLayout2EXT; # introduced=UpsideDownCake
     vkGetInstanceProcAddr;
     vkGetMemoryAndroidHardwareBufferANDROID; # introduced=28
     vkGetPhysicalDeviceExternalBufferProperties; # introduced=28
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 6af2cc1..e9935e5 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -508,6 +508,10 @@
         case VK_FORMAT_R8_UNORM:
             native_format = android::PIXEL_FORMAT_R_8;
             break;
+        // TODO: Do we need to query for VK_EXT_rgba10x6_formats here?
+        case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
+            native_format = android::PIXEL_FORMAT_RGBA_10101010;
+            break;
         default:
             ALOGV("unsupported swapchain format %d", format);
             break;
@@ -715,6 +719,17 @@
     capabilities->minImageExtent = VkExtent2D{1, 1};
     capabilities->maxImageExtent = VkExtent2D{4096, 4096};
 
+    if (capabilities->maxImageExtent.height <
+        capabilities->currentExtent.height) {
+        capabilities->maxImageExtent.height =
+            capabilities->currentExtent.height;
+    }
+
+    if (capabilities->maxImageExtent.width <
+        capabilities->currentExtent.width) {
+        capabilities->maxImageExtent.width = capabilities->currentExtent.width;
+    }
+
     capabilities->maxImageArrayLayers = 1;
 
     capabilities->supportedTransforms = kSupportedTransforms;
@@ -743,7 +758,6 @@
 
     const InstanceData& instance_data = GetData(pdev);
 
-    bool wide_color_support = false;
     uint64_t consumer_usage = 0;
     bool colorspace_ext =
         instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
@@ -754,27 +768,15 @@
         if (!surfaceless_enabled) {
             return VK_ERROR_SURFACE_LOST_KHR;
         }
-        // Support for VK_GOOGLE_surfaceless_query.  The EGL loader
-        // unconditionally supports wide color formats, even if they will cause
-        // a SurfaceFlinger fallback.  Based on that, wide_color_support will be
-        // set to true in this case.
-        wide_color_support = true;
+        // Support for VK_GOOGLE_surfaceless_query.
 
         // TODO(b/203826952): research proper value; temporarily use the
         // values seen on Pixel
         consumer_usage = AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY;
     } else {
         Surface& surface = *SurfaceFromHandle(surface_handle);
-        int err = native_window_get_wide_color_support(surface.window.get(),
-                                                       &wide_color_support);
-        if (err) {
-            return VK_ERROR_SURFACE_LOST_KHR;
-        }
-        ALOGV("wide_color_support is: %d", wide_color_support);
-
         consumer_usage = surface.consumer_usage;
     }
-    wide_color_support = wide_color_support && colorspace_ext;
 
     AHardwareBuffer_Desc desc = {};
     desc.width = 1;
@@ -787,17 +789,15 @@
     std::vector<VkSurfaceFormatKHR> all_formats = {
         {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
         {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-        // Also allow to use PASS_THROUGH + HAL_DATASPACE_ARBITRARY
-        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT},
-        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_PASS_THROUGH_EXT},
     };
 
     if (colorspace_ext) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT});
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_PASS_THROUGH_EXT});
+        all_formats.emplace_back(VkSurfaceFormatKHR{
             VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_BT709_LINEAR_EXT});
-    }
-
-    if (wide_color_support) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
             VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
         all_formats.emplace_back(VkSurfaceFormatKHR{
@@ -812,17 +812,21 @@
     if (AHardwareBuffer_isSupported(&desc)) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
             VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
-        all_formats.emplace_back(VkSurfaceFormatKHR{
-            VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_PASS_THROUGH_EXT});
+        if (colorspace_ext) {
+            all_formats.emplace_back(
+                VkSurfaceFormatKHR{VK_FORMAT_R5G6B5_UNORM_PACK16,
+                                   VK_COLOR_SPACE_PASS_THROUGH_EXT});
+        }
     }
 
     desc.format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
     if (AHardwareBuffer_isSupported(&desc)) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
             VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
-        all_formats.emplace_back(VkSurfaceFormatKHR{
-            VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_PASS_THROUGH_EXT});
-        if (wide_color_support) {
+        if (colorspace_ext) {
+            all_formats.emplace_back(
+                VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
+                                   VK_COLOR_SPACE_PASS_THROUGH_EXT});
             all_formats.emplace_back(
                 VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
                                    VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT});
@@ -837,10 +841,10 @@
         all_formats.emplace_back(
             VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
                                VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
-        all_formats.emplace_back(
-            VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
-                               VK_COLOR_SPACE_PASS_THROUGH_EXT});
-        if (wide_color_support) {
+        if (colorspace_ext) {
+            all_formats.emplace_back(
+                VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+                                   VK_COLOR_SPACE_PASS_THROUGH_EXT});
             all_formats.emplace_back(
                 VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
                                    VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
@@ -849,9 +853,26 @@
 
     desc.format = AHARDWAREBUFFER_FORMAT_R8_UNORM;
     if (AHardwareBuffer_isSupported(&desc)) {
+        if (colorspace_ext) {
+            all_formats.emplace_back(VkSurfaceFormatKHR{
+                VK_FORMAT_R8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT});
+        }
+    }
+
+    // TODO query VK_EXT_rgba10x6_formats support
+    desc.format = AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM;
+    if (AHardwareBuffer_isSupported(&desc)) {
         all_formats.emplace_back(
-            VkSurfaceFormatKHR{VK_FORMAT_R8_UNORM,
-                               VK_COLOR_SPACE_PASS_THROUGH_EXT});
+            VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+                               VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+        if (colorspace_ext) {
+            all_formats.emplace_back(
+                VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+                                   VK_COLOR_SPACE_PASS_THROUGH_EXT});
+            all_formats.emplace_back(
+                VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+                                   VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
+        }
     }
 
     // NOTE: Any new formats that are added must be coordinated across different
@@ -929,25 +950,87 @@
         return GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,
                                                   pSurfaceInfo->surface,
                                                   pSurfaceFormatCount, nullptr);
-    } else {
-        // temp vector for forwarding; we'll marshal it into the pSurfaceFormats
-        // after the call.
-        std::vector<VkSurfaceFormatKHR> surface_formats(*pSurfaceFormatCount);
-        VkResult result = GetPhysicalDeviceSurfaceFormatsKHR(
-            physicalDevice, pSurfaceInfo->surface, pSurfaceFormatCount,
-            surface_formats.data());
+    }
 
-        if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
-            // marshal results individually due to stride difference.
-            // completely ignore any chained extension structs.
-            uint32_t formats_to_marshal = *pSurfaceFormatCount;
-            for (uint32_t i = 0u; i < formats_to_marshal; i++) {
-                pSurfaceFormats[i].surfaceFormat = surface_formats[i];
-            }
-        }
+    // temp vector for forwarding; we'll marshal it into the pSurfaceFormats
+    // after the call.
+    std::vector<VkSurfaceFormatKHR> surface_formats(*pSurfaceFormatCount);
+    VkResult result = GetPhysicalDeviceSurfaceFormatsKHR(
+        physicalDevice, pSurfaceInfo->surface, pSurfaceFormatCount,
+        surface_formats.data());
 
+    if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
         return result;
     }
+
+    const auto& driver = GetData(physicalDevice).driver;
+
+    // marshal results individually due to stride difference.
+    uint32_t formats_to_marshal = *pSurfaceFormatCount;
+    for (uint32_t i = 0u; i < formats_to_marshal; i++) {
+        pSurfaceFormats[i].surfaceFormat = surface_formats[i];
+
+        // Query the compression properties for the surface format
+        VkSurfaceFormat2KHR* pSurfaceFormat = &pSurfaceFormats[i];
+        while (pSurfaceFormat->pNext) {
+            pSurfaceFormat =
+                reinterpret_cast<VkSurfaceFormat2KHR*>(pSurfaceFormat->pNext);
+            switch (pSurfaceFormat->sType) {
+                case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT: {
+                    VkImageCompressionPropertiesEXT* surfaceCompressionProps =
+                        reinterpret_cast<VkImageCompressionPropertiesEXT*>(
+                            pSurfaceFormat);
+
+                    if (surfaceCompressionProps &&
+                        driver.GetPhysicalDeviceImageFormatProperties2KHR) {
+                        VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
+                        imageFormatInfo.sType =
+                            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
+                        imageFormatInfo.format =
+                            pSurfaceFormats[i].surfaceFormat.format;
+                        imageFormatInfo.pNext = nullptr;
+
+                        VkImageCompressionControlEXT compressionControl = {};
+                        compressionControl.sType =
+                            VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT;
+                        compressionControl.pNext = imageFormatInfo.pNext;
+
+                        imageFormatInfo.pNext = &compressionControl;
+
+                        VkImageCompressionPropertiesEXT compressionProps = {};
+                        compressionProps.sType =
+                            VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT;
+                        compressionProps.pNext = nullptr;
+
+                        VkImageFormatProperties2KHR imageFormatProps = {};
+                        imageFormatProps.sType =
+                            VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR;
+                        imageFormatProps.pNext = &compressionProps;
+
+                        VkResult compressionRes =
+                            driver.GetPhysicalDeviceImageFormatProperties2KHR(
+                                physicalDevice, &imageFormatInfo,
+                                &imageFormatProps);
+                        if (compressionRes == VK_SUCCESS) {
+                            surfaceCompressionProps->imageCompressionFlags =
+                                compressionProps.imageCompressionFlags;
+                            surfaceCompressionProps
+                                ->imageCompressionFixedRateFlags =
+                                compressionProps.imageCompressionFixedRateFlags;
+                        } else {
+                            return compressionRes;
+                        }
+                    }
+                } break;
+
+                default:
+                    // Ignore all other extension structs
+                    break;
+            }
+        }
+    }
+
+    return result;
 }
 
 VKAPI_ATTR
@@ -1360,8 +1443,48 @@
         num_images = 1;
     }
 
+    void* usage_info_pNext = nullptr;
+    VkImageCompressionControlEXT image_compression = {};
     uint64_t native_usage = 0;
-    if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
+    if (dispatch.GetSwapchainGrallocUsage3ANDROID) {
+        ATRACE_BEGIN("GetSwapchainGrallocUsage3ANDROID");
+        VkGrallocUsageInfoANDROID gralloc_usage_info = {};
+        gralloc_usage_info.sType = VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID;
+        gralloc_usage_info.format = create_info->imageFormat;
+        gralloc_usage_info.imageUsage = create_info->imageUsage;
+
+        // Look through the pNext chain for an image compression control struct
+        // if one is found AND the appropriate extensions are enabled,
+        // append it to be the gralloc usage pNext chain
+        const VkSwapchainCreateInfoKHR* create_infos = create_info;
+        while (create_infos->pNext) {
+            create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
+                create_infos->pNext);
+            switch (create_infos->sType) {
+                case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
+                    const VkImageCompressionControlEXT* compression_infos =
+                        reinterpret_cast<const VkImageCompressionControlEXT*>(
+                            create_infos);
+                    image_compression = *compression_infos;
+                    image_compression.pNext = nullptr;
+                    usage_info_pNext = &image_compression;
+                } break;
+
+                default:
+                    // Ignore all other info structs
+                    break;
+            }
+        }
+        gralloc_usage_info.pNext = usage_info_pNext;
+
+        result = dispatch.GetSwapchainGrallocUsage3ANDROID(
+            device, &gralloc_usage_info, &native_usage);
+        ATRACE_END();
+        if (result != VK_SUCCESS) {
+            ALOGE("vkGetSwapchainGrallocUsage3ANDROID failed: %d", result);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+    } else if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
         uint64_t consumer_usage, producer_usage;
         ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID");
         result = dispatch.GetSwapchainGrallocUsage2ANDROID(
@@ -1373,7 +1496,7 @@
             return VK_ERROR_SURFACE_LOST_KHR;
         }
         native_usage =
-            convertGralloc1ToBufferUsage(consumer_usage, producer_usage);
+            convertGralloc1ToBufferUsage(producer_usage, consumer_usage);
     } else if (dispatch.GetSwapchainGrallocUsageANDROID) {
         ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID");
         int32_t legacy_usage = 0;
@@ -1427,7 +1550,7 @@
 #pragma clang diagnostic ignored "-Wold-style-cast"
         .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID,
 #pragma clang diagnostic pop
-        .pNext = nullptr,
+        .pNext = usage_info_pNext,
         .usage = swapchain_image_usage,
     };
     VkNativeBufferANDROID image_native_buffer = {
@@ -1485,6 +1608,7 @@
         android_convertGralloc0To1Usage(int(img.buffer->usage),
             &image_native_buffer.usage2.producer,
             &image_native_buffer.usage2.consumer);
+        image_native_buffer.usage3 = img.buffer->usage;
 
         ATRACE_BEGIN("CreateImage");
         result =
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 3c91150..f998b1a 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -948,6 +948,17 @@
     return VK_SUCCESS;
 }
 
+VkResult GetSwapchainGrallocUsage3ANDROID(
+    VkDevice,
+    const VkGrallocUsageInfoANDROID* grallocUsageInfo,
+    uint64_t* grallocUsage) {
+    // The null driver never reads or writes the gralloc buffer
+    ALOGV("TODO: vk%s - grallocUsageInfo->format:%i", __FUNCTION__,
+          grallocUsageInfo->format);
+    *grallocUsage = 0;
+    return VK_SUCCESS;
+}
+
 VkResult AcquireImageANDROID(VkDevice,
                              VkImage,
                              int fence,
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index f6dcf09..0cb7bd3 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -261,6 +261,7 @@
     {"vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetRenderAreaGranularity>(GetRenderAreaGranularity))},
     {"vkGetSemaphoreCounterValue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSemaphoreCounterValue>(GetSemaphoreCounterValue))},
     {"vkGetSwapchainGrallocUsage2ANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsage2ANDROID>(GetSwapchainGrallocUsage2ANDROID))},
+    {"vkGetSwapchainGrallocUsage3ANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsage3ANDROID>(GetSwapchainGrallocUsage3ANDROID))},
     {"vkGetSwapchainGrallocUsageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(GetSwapchainGrallocUsageANDROID))},
     {"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkInvalidateMappedMemoryRanges>(InvalidateMappedMemoryRanges))},
     {"vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkMapMemory>(MapMemory))},
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 3e003e3..5c7fea0 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -209,6 +209,7 @@
 VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
 VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
 VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
+VKAPI_ATTR VkResult GetSwapchainGrallocUsage3ANDROID(VkDevice device, const VkGrallocUsageInfoANDROID* grallocUsageInfo, uint64_t* grallocUsage);
 VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
 VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
 VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index 4176509..c25c6cb 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -69,6 +69,7 @@
 _OPTIONAL_COMMANDS = [
     'vkGetSwapchainGrallocUsageANDROID',
     'vkGetSwapchainGrallocUsage2ANDROID',
+    'vkGetSwapchainGrallocUsage3ANDROID',
 ]
 
 # Dict for mapping dispatch table to a type.
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index da6b00a..0284192 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -731,7 +731,7 @@
     visitor->Visit("vulkanMemoryModelAvailabilityVisibilityChains", &features->vulkanMemoryModelAvailabilityVisibilityChains) &&
     visitor->Visit("shaderOutputViewportIndex", &features->shaderOutputViewportIndex) &&
     visitor->Visit("shaderOutputLayer", &features->shaderOutputLayer) &&
-    visitor->Visit("shaderOutputLayer", &features->shaderOutputLayer);
+    visitor->Visit("subgroupBroadcastDynamicId", &features->subgroupBroadcastDynamicId);
 }
 
 template <typename Visitor>