Merge "Added libsensorservice_headers and support for static library"
diff --git a/Android.bp b/Android.bp
index dec6716..615a7a8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -64,14 +64,20 @@
     name: "framework_native_aidl_binder",
     srcs: ["aidl/binder/**/*.aidl"],
     path: "aidl/binder",
-    visibility: ["//frameworks/native"],
+    visibility: [
+        "//frameworks/native",
+        "//frameworks/native/libs/gui",
+    ],
 }
 
 filegroup {
     name: "framework_native_aidl_gui",
     srcs: ["aidl/gui/**/*.aidl"],
     path: "aidl/gui",
-    visibility: ["//frameworks/native"],
+    visibility: [
+        "//frameworks/native",
+        "//frameworks/native/libs/gui",
+    ],
 }
 
 filegroup {
@@ -82,7 +88,7 @@
     ],
 }
 
-cc_library_headers{
+cc_library_headers {
     name: "libandroid_headers_private",
     export_include_dirs: ["include/private"],
 }
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 6d837c2..3480d63 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,8 +1,10 @@
 [Builtin Hooks]
+rustfmt = true
 bpfmt = true
 clang_format = true
 
 [Builtin Hooks Options]
+rustfmt = --config-path=rustfmt.toml
 # Only turn on clang-format check for the following subfolders.
 clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
                cmds/idlcli/
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 952ffd2..2e0c95a 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -296,12 +296,15 @@
     write /sys/kernel/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
     write /sys/kernel/debug/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
 
-# Set up histogram triggers
-    # rss_stat_throttled (bucket size == 512KB)
-    chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
+    # allow creating event triggers
     chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger
-    write /sys/kernel/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
-    write /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
+    chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
+
+on late-init && property:ro.boot.fastboot.boottrace=enabled
+    setprop debug.atrace.tags.enableflags 802922
+    setprop persist.traced.enable 0
+    write /sys/kernel/debug/tracing/tracing_on 1
+    write /sys/kernel/tracing/tracing_on 1
 
 # Only create the tracing instance if persist.mm_events.enabled
 # Attempting to remove the tracing instance after it has been created
@@ -398,3 +401,10 @@
 service boottrace /system/bin/atrace --async_start -f /data/misc/boottrace/categories
     disabled
     oneshot
+
+on property:sys.boot_completed=1 && property:ro.boot.fastboot.boottrace=enabled
+    setprop debug.atrace.tags.enableflags 0
+    setprop persist.traced.enable 1
+    write /sys/kernel/debug/tracing/tracing_on 0
+    write /sys/kernel/tracing/tracing_on 0
+
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index a2491e5..a60972b 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -101,6 +101,7 @@
         "libhidlbase",
         "liblog",
         "libutils",
+        "libvintf",
         "libbinderdebug",
         "packagemanager_aidl-cpp",
     ],
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 890c15f..6dea91b 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "dumpstate"
+#define ATRACE_TAG ATRACE_TAG_ALWAYS
 
 #include <dirent.h>
 #include <errno.h>
@@ -76,6 +77,7 @@
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
+#include <cutils/trace.h>
 #include <debuggerd/client.h>
 #include <dumpsys.h>
 #include <dumputils/dump_utils.h>
@@ -88,6 +90,7 @@
 #include <private/android_logger.h>
 #include <serviceutils/PriorityDumper.h>
 #include <utils/StrongPointer.h>
+#include <vintf/VintfObject.h>
 #include "DumpstateInternal.h"
 #include "DumpstateService.h"
 #include "dumpstate.h"
@@ -829,7 +832,8 @@
 
     // Logging statement  below is useful to time how long each entry takes, but it's too verbose.
     // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
-    int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
+    size_t flags = ZipWriter::kCompress | ZipWriter::kDefaultCompression;
+    int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), flags,
                                                   get_mtime(fd, ds.now_));
     if (err != 0) {
         MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
@@ -921,7 +925,8 @@
 
 bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
     MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
-    int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
+    size_t flags = ZipWriter::kCompress | ZipWriter::kDefaultCompression;
+    int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), flags, ds.now_);
     if (err != 0) {
         MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
                ZipWriter::ErrorCodeString(err));
@@ -1394,6 +1399,23 @@
     }
 }
 
+// Dump all of the files that make up the vendor interface.
+// See the files listed in dumpFileList() for the latest list of files.
+static void DumpVintf() {
+    const auto vintfFiles = android::vintf::details::dumpFileList();
+    for (const auto vintfFile : vintfFiles) {
+        struct stat st;
+        if (stat(vintfFile.c_str(), &st) == 0) {
+            if (S_ISDIR(st.st_mode)) {
+                ds.AddDir(vintfFile, true /* recursive */);
+            } else {
+                ds.EnqueueAddZipEntryAndCleanupIfNeeded(ZIP_ROOT_DIR + vintfFile,
+                        vintfFile);
+            }
+        }
+    }
+}
+
 static void DumpExternalFragmentationInfo() {
     struct stat st;
     if (stat("/proc/buddyinfo", &st) != 0) {
@@ -1486,7 +1508,6 @@
     dprintf(out_fd, "========================================================\n");
 
     RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"}, out_fd);
-    RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"}, out_fd);
     RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"}, out_fd);
     RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"}, out_fd);
     RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"}, out_fd);
@@ -1619,6 +1640,8 @@
         do_dmesg();
     }
 
+    DumpVintf();
+
     RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
 
     RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
@@ -1648,7 +1671,7 @@
 
     DumpPacketStats();
 
-    RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
+    RunDumpsys("EBPF MAP STATS", {"connectivity", "trafficcontroller"});
 
     DoKmsg();
 
@@ -2084,7 +2107,7 @@
     int timeout_failures = 0;
     bool dalvik_found = false;
 
-    const std::set<int> hal_pids = get_interesting_hal_pids();
+    const std::set<int> hal_pids = get_interesting_pids();
 
     struct dirent* d;
     while ((d = readdir(proc.get()))) {
@@ -3076,7 +3099,9 @@
     TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
 
     // Zip the (now complete) .tmp file within the internal directory.
+    ATRACE_BEGIN("FinalizeFile");
     FinalizeFile();
+    ATRACE_END();
 
     // Share the final file with the caller if the user has consented or Shell is the caller.
     Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
@@ -3387,6 +3412,9 @@
         duration_fd_(duration_fd) {
     if (!title_.empty()) {
         started_ = Nanotime();
+        if (title_.find("SHOW MAP") == std::string::npos) {
+            ATRACE_ASYNC_BEGIN(title_.c_str(), 0);
+        }
     }
 }
 
@@ -3401,6 +3429,9 @@
             dprintf(duration_fd_, "------ %.3fs was the duration of '%s' ------\n",
                     elapsed, title_.c_str());
         }
+        if (title_.find("SHOW MAP") == std::string::npos) {
+            ATRACE_ASYNC_END(title_.c_str(), 0);
+        }
     }
 }
 
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 49c1318..f0c19b9 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -65,6 +65,7 @@
                                              const sp<LocalRegistrationCallback>&));
     MOCK_METHOD2(unregisterForNotifications, status_t(const String16&,
                                              const sp<LocalRegistrationCallback>&));
+    MOCK_METHOD0(getServiceDebugInfo, std::vector<ServiceDebugInfo>());
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
 };
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index c9f680b..0f7c489 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -72,8 +72,6 @@
         },
     },
 
-    clang: true,
-
     tidy: true,
     tidy_checks: [
         "-*",
@@ -81,8 +79,9 @@
         "cert-*",
         "-cert-err58-cpp",
     ],
-    tidy_flags: [
-        "-warnings-as-errors=clang-analyzer-security*,cert-*",
+    tidy_checks_as_errors: [
+        "clang-analyzer-security*",
+        "cert-*",
     ],
 }
 
@@ -127,7 +126,6 @@
 cc_test_host {
     name: "run_dex2oat_test",
     test_suites: ["general-tests"],
-    clang: true,
     srcs: [
         "run_dex2oat_test.cpp",
         "run_dex2oat.cpp",
@@ -187,7 +185,6 @@
         "-Wall",
         "-Werror",
     ],
-    clang: true,
 
     srcs: [
         "otapreopt_chroot.cpp",
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 397d432..1d7dd5f 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1869,8 +1869,9 @@
     binder::Status res = ok();
     if (flags & FLAG_STORAGE_DE) {
         auto path = create_data_user_de_path(uuid_, userId);
-        if (delete_dir_contents_and_dir(path, true) != 0) {
-            res = error("Failed to delete " + path);
+        // Contents only, as vold is responsible for the user_de dir itself.
+        if (delete_dir_contents(path, true) != 0) {
+            res = error("Failed to delete contents of " + path);
         }
         auto sdk_sandbox_de_path =
                 create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/false, userId);
@@ -1890,8 +1891,9 @@
     }
     if (flags & FLAG_STORAGE_CE) {
         auto path = create_data_user_ce_path(uuid_, userId);
-        if (delete_dir_contents_and_dir(path, true) != 0) {
-            res = error("Failed to delete " + path);
+        // Contents only, as vold is responsible for the user_ce dir itself.
+        if (delete_dir_contents(path, true) != 0) {
+            res = error("Failed to delete contents of " + path);
         }
         auto sdk_sandbox_ce_path =
                 create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/true, userId);
@@ -1899,8 +1901,9 @@
             res = error("Failed to delete " + sdk_sandbox_ce_path);
         }
         path = findDataMediaPath(uuid, userId);
-        if (delete_dir_contents_and_dir(path, true) != 0) {
-            res = error("Failed to delete " + path);
+        // Contents only, as vold is responsible for the media dir itself.
+        if (delete_dir_contents(path, true) != 0) {
+            res = error("Failed to delete contents of " + path);
         }
     }
     return res;
@@ -1957,17 +1960,43 @@
 #endif // GRANULAR_LOCKS
             FTS *fts;
             FTSENT *p;
+
+            // Create a list of data paths whose children have cache directories
             auto ce_path = create_data_user_ce_path(uuid_, userId);
             auto de_path = create_data_user_de_path(uuid_, userId);
             auto media_path = findDataMediaPath(uuid, userId) + "/Android/data/";
-            char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(),
-                    (char*) media_path.c_str(), nullptr };
+            auto ce_sdk_path = create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/true, userId);
+            auto de_sdk_path = create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/false, userId);
+
+            std::vector<std::string> dataPaths = {ce_path, de_path, media_path};
+            foreach_subdir(ce_sdk_path, [&ce_sdk_path, &dataPaths](const std::string subDir) {
+                const auto fullpath = ce_sdk_path + "/" + subDir;
+                dataPaths.push_back(fullpath);
+            });
+            foreach_subdir(de_sdk_path, [&de_sdk_path, &dataPaths](const std::string subDir) {
+                const auto fullpath = de_sdk_path + "/" + subDir;
+                dataPaths.push_back((char*)fullpath.c_str());
+            });
+
+            char* argv[dataPaths.size() + 1];
+            for (unsigned int i = 0; i < dataPaths.size(); i++) {
+                argv[i] = (char*)dataPaths[i].c_str();
+            }
+            argv[dataPaths.size()] = nullptr;
+
             if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
                 return error("Failed to fts_open");
             }
             while ((p = fts_read(fts)) != nullptr) {
                 if (p->fts_info == FTS_D && p->fts_level == 1) {
                     uid_t uid = p->fts_statp->st_uid;
+
+                    // If uid belongs to sdk sandbox, then the cache should be attributed to the
+                    // original client app.
+                    const auto client_uid = multiuser_convert_sdk_sandbox_to_app_uid(uid);
+                    const bool isSandboxUid = (client_uid != (uid_t)-1);
+                    if (isSandboxUid) uid = client_uid;
+
                     if (multiuser_get_app_id(uid) == AID_MEDIA_RW) {
                         uid = (multiuser_get_app_id(p->fts_statp->st_gid) - AID_EXT_GID_START)
                                 + AID_APP_START;
@@ -2850,6 +2879,9 @@
         auto obbPath = StringPrintf("%s/Android/obb",
                 create_data_media_path(uuid_, userId).c_str());
         calculate_tree_size(obbPath, &obbSize);
+        if (!(flags & FLAG_USE_QUOTA)) {
+            totalSize -= obbSize;
+        }
         ATRACE_END();
     }
 
@@ -2976,13 +3008,15 @@
 // Dumps the contents of a profile file, using pkgname's dex files for pretty
 // printing the result.
 binder::Status InstalldNativeService::dumpProfiles(int32_t uid, const std::string& packageName,
-        const std::string& profileName, const std::string& codePath, bool* _aidl_return) {
+                                                   const std::string& profileName,
+                                                   const std::string& codePath,
+                                                   bool dumpClassesAndMethods, bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     CHECK_ARGUMENT_PATH(codePath);
     LOCK_PACKAGE();
 
-    *_aidl_return = dump_profiles(uid, packageName, profileName, codePath);
+    *_aidl_return = dump_profiles(uid, packageName, profileName, codePath, dumpClassesAndMethods);
     return ok();
 }
 
@@ -3537,10 +3571,10 @@
         return error("Failed to stat " + mirrorVolCePath);
     }
 
-    if (mirrorCeStat.st_ino == ceStat.st_ino) {
+    if (mirrorCeStat.st_ino == ceStat.st_ino && mirrorCeStat.st_dev == ceStat.st_dev) {
         // As it's being called by prepareUserStorage, it can be called multiple times.
         // Hence, we if we mount it already, we should skip it.
-        LOG(WARNING) << "CE dir is mounted already: " + cePath;
+        LOG(INFO) << "CE dir is mounted already: " + cePath;
         return ok();
     }
 
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 0432222..521afc3 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -134,7 +134,8 @@
     binder::Status mergeProfiles(int32_t uid, const std::string& packageName,
             const std::string& profileName, int* _aidl_return);
     binder::Status dumpProfiles(int32_t uid, const std::string& packageName,
-            const std::string& profileName, const std::string& codePath, bool* _aidl_return);
+                                const std::string& profileName, const std::string& codePath,
+                                bool dumpClassesAndMethods, bool* _aidl_return);
     binder::Status copySystemProfile(const std::string& systemProfile,
             int32_t uid, const std::string& packageName, const std::string& profileName,
             bool* _aidl_return);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index db03411..9ad853b 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -77,7 +77,7 @@
 
     int mergeProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String profileName);
     boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String  profileName,
-            @utf8InCpp String codePath);
+            @utf8InCpp String codePath, boolean dumpClassesAndMethods);
     boolean copySystemProfile(@utf8InCpp String systemProfile, int uid,
             @utf8InCpp String packageName, @utf8InCpp String profileName);
     void clearAppProfiles(@utf8InCpp String packageName, @utf8InCpp String profileName);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 894c7d3..ebb7891 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -624,12 +624,15 @@
                   /*for_boot_image*/false);
     }
 
-    void SetupDump(const std::vector<unique_fd>& profiles_fd,
-                   const unique_fd& reference_profile_fd,
+    void SetupDump(const std::vector<unique_fd>& profiles_fd, const unique_fd& reference_profile_fd,
                    const std::vector<std::string>& dex_locations,
-                   const std::vector<unique_fd>& apk_fds,
+                   const std::vector<unique_fd>& apk_fds, bool dump_classes_and_methods,
                    const unique_fd& output_fd) {
-        AddArg("--dump-only");
+        if (dump_classes_and_methods) {
+            AddArg("--dump-classes-and-methods");
+        } else {
+            AddArg("--dump-only");
+        }
         AddArg(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
         SetupArgs(profiles_fd,
                   reference_profile_fd,
@@ -772,7 +775,7 @@
 }
 
 bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
-        const std::string& code_path) {
+                   const std::string& code_path, bool dump_classes_and_methods) {
     std::vector<unique_fd> profile_fds;
     unique_fd reference_profile_fd;
     std::string out_file_name = StringPrintf("/data/misc/profman/%s-%s.txt",
@@ -808,7 +811,8 @@
 
 
     RunProfman profman_dump;
-    profman_dump.SetupDump(profile_fds, reference_profile_fd, dex_locations, apk_fds, output_fd);
+    profman_dump.SetupDump(profile_fds, reference_profile_fd, dex_locations, apk_fds,
+                           dump_classes_and_methods, output_fd);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index f7af929..5cf402c 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -88,10 +88,8 @@
                              const std::string& profile_name,
                              const std::string& classpath);
 
-bool dump_profiles(int32_t uid,
-                   const std::string& pkgname,
-                   const std::string& profile_name,
-                   const std::string& code_path);
+bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
+                   const std::string& code_path, bool dump_classes_and_methods);
 
 bool copy_system_profile(const std::string& system_profile,
                          uid_t packageUid,
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index b3baca5..07f73b9 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -11,7 +11,6 @@
 cc_test {
     name: "installd_utils_test",
     test_suites: ["device-tests"],
-    clang: true,
     srcs: ["installd_utils_test.cpp"],
     cflags: [
         "-Wall",
@@ -36,7 +35,6 @@
 cc_test {
     name: "installd_cache_test",
     test_suites: ["device-tests"],
-    clang: true,
     srcs: ["installd_cache_test.cpp"],
     cflags: [
         "-Wall",
@@ -82,7 +80,6 @@
 cc_test {
     name: "installd_service_test",
     test_suites: ["device-tests"],
-    clang: true,
     srcs: ["installd_service_test.cpp"],
     cflags: [
         "-Wall",
@@ -130,7 +127,6 @@
 cc_test {
     name: "installd_dexopt_test",
     test_suites: ["device-tests"],
-    clang: true,
     srcs: ["installd_dexopt_test.cpp"],
     cflags: [
         "-Wall",
@@ -177,7 +173,6 @@
 cc_test {
     name: "installd_otapreopt_test",
     test_suites: ["device-tests"],
-    clang: true,
     srcs: ["installd_otapreopt_test.cpp"],
     cflags: [
         "-Wall",
@@ -198,7 +193,6 @@
 cc_test {
     name: "installd_file_test",
     test_suites: ["device-tests"],
-    clang: true,
     srcs: ["installd_file_test.cpp"],
     cflags: [
         "-Wall",
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 4eb30e2..3849c40 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -920,6 +920,11 @@
 
 TEST_F(DexoptTest, DexoptDex2oat64Enabled) {
     LOG(INFO) << "DexoptDex2oat64Enabled";
+    std::string zygote_prop = android::base::GetProperty("ro.zygote", "");
+    ASSERT_GT(zygote_prop.size(), 0);
+    if (zygote_prop != "zygote32_64" && zygote_prop != "zygote64_32") {
+        GTEST_SKIP() << "DexoptDex2oat64Enabled skipped for single-bitness Zygote.";
+    }
     const std::string property = "dalvik.vm.dex2oat64.enabled";
     const std::string previous_value = android::base::GetProperty(property, "");
     auto restore_property = android::base::make_scope_guard([=]() {
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 45aeab6..4d9b710 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -1184,8 +1184,8 @@
 int wait_child_with_timeout(pid_t pid, int timeout_ms) {
     int pidfd = pidfd_open(pid, /*flags=*/0);
     if (pidfd < 0) {
-        PLOG(ERROR) << "pidfd_open failed for pid " << pid;
-        kill(pid, SIGKILL);
+        PLOG(ERROR) << "pidfd_open failed for pid " << pid
+                    << ", waiting for child process without timeout";
         return wait_child(pid);
     }
 
diff --git a/cmds/lshal/libprocpartition/Android.bp b/cmds/lshal/libprocpartition/Android.bp
index cbfbdc9..af85666 100644
--- a/cmds/lshal/libprocpartition/Android.bp
+++ b/cmds/lshal/libprocpartition/Android.bp
@@ -35,5 +35,6 @@
     ],
     export_include_dirs: [
         "include",
-    ]
+    ],
+    min_sdk_version: "30",
 }
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp
index b7e520f..711038c 100644
--- a/cmds/servicemanager/Access.cpp
+++ b/cmds/servicemanager/Access.cpp
@@ -30,6 +30,7 @@
 constexpr bool kIsVendor = false;
 #endif
 
+#ifdef __ANDROID__
 static std::string getPidcon(pid_t pid) {
     android_errorWriteLog(0x534e4554, "121035042");
 
@@ -45,7 +46,6 @@
 
 static struct selabel_handle* getSehandle() {
     static struct selabel_handle* gSehandle = nullptr;
-
     if (gSehandle != nullptr && selinux_status_updated()) {
         selabel_close(gSehandle);
         gSehandle = nullptr;
@@ -78,8 +78,10 @@
         ad->tname->c_str());
     return 0;
 }
+#endif
 
 Access::Access() {
+#ifdef __ANDROID__
     union selinux_callback cb;
 
     cb.func_audit = auditCallback;
@@ -91,6 +93,7 @@
     CHECK(selinux_status_open(true /*fallback*/) >= 0);
 
     CHECK(getcon(&mThisProcessContext) == 0);
+#endif
 }
 
 Access::~Access() {
@@ -98,6 +101,7 @@
 }
 
 Access::CallingContext Access::getCallingContext() {
+#ifdef __ANDROID__
     IPCThreadState* ipc = IPCThreadState::self();
 
     const char* callingSid = ipc->getCallingSid();
@@ -108,6 +112,9 @@
         .uid = ipc->getCallingUid(),
         .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid),
     };
+#else
+    return CallingContext();
+#endif
 }
 
 bool Access::canFind(const CallingContext& ctx,const std::string& name) {
@@ -124,6 +131,7 @@
 
 bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm,
         const std::string& tname) {
+#ifdef __ANDROID__
     const char* tclass = "service_manager";
 
     AuditCallbackData data = {
@@ -133,9 +141,18 @@
 
     return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm,
         reinterpret_cast<void*>(&data));
+#else
+    (void)sctx;
+    (void)tctx;
+    (void)perm;
+    (void)tname;
+
+    return true;
+#endif
 }
 
 bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) {
+#ifdef __ANDROID__
     char *tctx = nullptr;
     if (selabel_lookup(getSehandle(), &tctx, name.c_str(), SELABEL_CTX_ANDROID_SERVICE) != 0) {
         LOG(ERROR) << "SELinux: No match for " << name << " in service_contexts.\n";
@@ -145,6 +162,14 @@
     bool allowed = actionAllowed(sctx, tctx, perm, name);
     freecon(tctx);
     return allowed;
+#else
+    (void)sctx;
+    (void)name;
+    (void)perm;
+    (void)kIsVendor;
+
+    return true;
+#endif
 }
 
 }  // android
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 32922ca..25bd9a3 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -44,6 +44,7 @@
     defaults: ["servicemanager_defaults"],
     init_rc: ["servicemanager.rc"],
     srcs: ["main.cpp"],
+    bootstrap: true,
 }
 
 cc_binary {
@@ -86,3 +87,35 @@
     ],
     static_libs: ["libgmock"],
 }
+
+cc_fuzz {
+    name: "servicemanager_fuzzer",
+    defaults: ["servicemanager_defaults"],
+    host_supported: true,
+    static_libs: [
+        "libbase",
+        "libbinder_random_parcel",
+        "libcutils",
+    ],
+    target: {
+        android: {
+            shared_libs: [
+                "libbinder_ndk",
+                "libbinder",
+            ],
+        },
+        host: {
+            static_libs: [
+                "libbinder_ndk",
+                "libbinder",
+            ],
+        },
+    },
+    srcs: ["ServiceManagerFuzzer.cpp"],
+    fuzz_config: {
+        cc: [
+            "smoreland@google.com",
+            "waghpawan@google.com",
+        ],
+    },
+}
diff --git a/cmds/servicemanager/ServiceManagerFuzzer.cpp b/cmds/servicemanager/ServiceManagerFuzzer.cpp
new file mode 100644
index 0000000..9e2e53f
--- /dev/null
+++ b/cmds/servicemanager/ServiceManagerFuzzer.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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_driver.h>
+#include <utils/StrongPointer.h>
+
+#include "Access.h"
+#include "ServiceManager.h"
+
+using ::android::Access;
+using ::android::fuzzService;
+using ::android::ServiceManager;
+using ::android::sp;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    if (size > 50000) {
+        return 0;
+    }
+
+    auto accessPtr = std::make_unique<Access>();
+    auto serviceManager = sp<ServiceManager>::make(std::move(accessPtr));
+    fuzzService(serviceManager, FuzzedDataProvider(data, size));
+
+    return 0;
+}
\ No newline at end of file
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index 2fb9c2b..a831d1b 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/Status.h>
@@ -26,15 +27,14 @@
 #include "ServiceManager.h"
 
 using ::android::Access;
-using ::android::sp;
+using ::android::IPCThreadState;
 using ::android::Looper;
 using ::android::LooperCallback;
 using ::android::ProcessState;
-using ::android::IPCThreadState;
-using ::android::ProcessState;
 using ::android::ServiceManager;
-using ::android::os::IServiceManager;
 using ::android::sp;
+using ::android::base::SetProperty;
+using ::android::os::IServiceManager;
 
 class BinderCallback : public LooperCallback {
 public:
@@ -121,6 +121,8 @@
 
     const char* driver = argc == 2 ? argv[1] : "/dev/binder";
 
+    LOG(INFO) << "Starting sm instance on " << driver;
+
     sp<ProcessState> ps = ProcessState::initWithDriver(driver);
     ps->setThreadPoolMaxThreadCount(0);
     ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
@@ -138,6 +140,12 @@
     BinderCallback::setupTo(looper);
     ClientCallbackCallback::setupTo(looper, manager);
 
+#ifndef VENDORSERVICEMANAGER
+    if (!SetProperty("servicemanager.ready", "true")) {
+        LOG(ERROR) << "Failed to set servicemanager ready property";
+    }
+#endif
+
     while(true) {
         looper->pollAll(-1);
     }
diff --git a/cmds/servicemanager/servicemanager.microdroid.rc b/cmds/servicemanager/servicemanager.microdroid.rc
index e01f132..c516043 100644
--- a/cmds/servicemanager/servicemanager.microdroid.rc
+++ b/cmds/servicemanager/servicemanager.microdroid.rc
@@ -3,6 +3,7 @@
     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 e5d689f..6b35265 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -3,6 +3,7 @@
     user system
     group system readproc
     critical
+    onrestart setprop servicemanager.ready false
     onrestart restart apexd
     onrestart restart audioserver
     onrestart restart gatekeeperd
diff --git a/cmds/servicemanager/servicemanager.recovery.rc b/cmds/servicemanager/servicemanager.recovery.rc
index 067faf9..b927c01 100644
--- a/cmds/servicemanager/servicemanager.recovery.rc
+++ b/cmds/servicemanager/servicemanager.recovery.rc
@@ -1,4 +1,5 @@
 service servicemanager /system/bin/servicemanager
     disabled
     group system readproc
+    onrestart setprop servicemanager.ready false
     seclabel u:r:servicemanager:s0
diff --git a/data/etc/android.hardware.type.automotive.xml b/data/etc/android.hardware.type.automotive.xml
index 113945b..a9b4b05 100644
--- a/data/etc/android.hardware.type.automotive.xml
+++ b/data/etc/android.hardware.type.automotive.xml
@@ -17,6 +17,4 @@
 <!-- These features determine that the device running android is a car. -->
 <permissions>
     <feature name="android.hardware.type.automotive" />
-    <!-- TODO: Revert this after enabling work profiles refer b/170332519 -->
-    <unavailable-feature name="android.software.managed_users"/>
 </permissions>
diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
index 07bd749..0af40dd 100644
--- a/headers/media_plugin/media/openmax/OMX_IndexExt.h
+++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h
@@ -104,6 +104,7 @@
     OMX_IndexConfigLatency,                         /**< reference: OMX_PARAM_U32TYPE */
     OMX_IndexConfigLowLatency,                      /**< reference: OMX_CONFIG_BOOLEANTYPE */
     OMX_IndexConfigAndroidTunnelPeek,               /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigAndroidTunnelPeekLegacyMode,     /**< reference: OMX_CONFIG_BOOLEANTYPE */
     OMX_IndexExtOtherEndUnused,
 
     /* Time configurations */
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index e65b224..4746bc3 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -318,6 +318,9 @@
     OMX_VIDEO_DolbyVisionLevelUhd30   = 0x40,
     OMX_VIDEO_DolbyVisionLevelUhd48   = 0x80,
     OMX_VIDEO_DolbyVisionLevelUhd60   = 0x100,
+    OMX_VIDEO_DolbyVisionLevelUhd120  = 0x200,
+    OMX_VIDEO_DolbyVisionLevel8k30    = 0x400,
+    OMX_VIDEO_DolbyVisionLevel8k60    = 0x800,
     OMX_VIDEO_DolbyVisionLevelmax     = 0x7FFFFFFF
 } OMX_VIDEO_DOLBYVISIONLEVELTYPE;
 
diff --git a/include/android/input.h b/include/android/input.h
index fb5e204..8cd9e95 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -54,7 +54,14 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <android/keycodes.h>
+
+// This file is included by modules that have host support but android/looper.h is not supported
+// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled.
+#ifndef __BIONIC__
+#define __REMOVED_IN(x) __attribute__((deprecated))
+#endif
 #include <android/looper.h>
+
 #include <jni.h>
 
 #if !defined(__INTRODUCED_IN)
@@ -810,7 +817,7 @@
 /**
  * Constants that identify different gesture classification types.
  */
-enum {
+enum AMotionClassification : uint32_t {
     /**
      * Classification constant: None.
      *
@@ -820,7 +827,8 @@
     /**
      * Classification constant: Ambiguous gesture.
      *
-     * The user's intent with respect to the current event stream is not yet determined.
+     * The user's intent with respect to the current event stream is not yet determined. Events
+     * starting in AMBIGUOUS_GESTURE will eventually resolve into either DEEP_PRESS or NONE.
      * Gestural actions, such as scrolling, should be inhibited until the classification resolves
      * to another value or the event stream ends.
      */
@@ -1357,8 +1365,17 @@
  * Get the action button for the motion event. Returns a valid action button when the
  * event is associated with a button press or button release action. For other actions
  * the return value is undefined.
+ *
+ * @see #AMOTION_EVENT_BUTTON_PRIMARY
+ * @see #AMOTION_EVENT_BUTTON_SECONDARY
+ * @see #AMOTION_EVENT_BUTTON_TERTIARY
+ * @see #AMOTION_EVENT_BUTTON_BACK
+ * @see #AMOTION_EVENT_BUTTON_FORWARD
+ * @see #AMOTION_EVENT_BUTTON_STYLUS_PRIMARY
+ * @see #AMOTION_EVENT_BUTTON_STYLUS_SECONDARY
  */
-int32_t AMotionEvent_getActionButton(const AInputEvent* motion_event);
+int32_t AMotionEvent_getActionButton(const AInputEvent* motion_event)
+        __INTRODUCED_IN(__ANDROID_API_T__);
 
 /**
  * Returns the classification for the current gesture.
@@ -1368,7 +1385,8 @@
  * @see #AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE
  * @see #AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS
 */
-int32_t AMotionEvent_getClassification(const AInputEvent* motion_event);
+int32_t AMotionEvent_getClassification(const AInputEvent* motion_event)
+        __INTRODUCED_IN(__ANDROID_API_T__);
 
 /**
  * Creates a native AInputEvent* object that is a copy of the specified Java
diff --git a/include/android/looper.h b/include/android/looper.h
index 718f703..4fe142a 100644
--- a/include/android/looper.h
+++ b/include/android/looper.h
@@ -201,8 +201,11 @@
  * Like ALooper_pollOnce(), but performs all pending callbacks until all
  * data has been consumed or a file descriptor is available with no callback.
  * This function will never return ALOOPER_POLL_CALLBACK.
+ *
+ * Removed in API 34 as ALooper_pollAll can swallow ALooper_wake calls.
+ * Use ALooper_pollOnce instead.
  */
-int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData);
+int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) __REMOVED_IN(1);
 
 /**
  * Wakes the poll asynchronously.
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 6112d5f..105f952 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -45,6 +45,11 @@
  *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
  */
 
+// This file is included by modules that have host support but android/looper.h is not supported
+// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled.
+#ifndef __BIONIC__
+#define __REMOVED_IN(x) __attribute__((deprecated))
+#endif
 #include <android/looper.h>
 
 #include <stdbool.h>
@@ -267,7 +272,8 @@
      * {@link ASENSOR_TYPE_HEAD_TRACKER}
      * reporting-mode: continuous
      *
-     * Measures the orientation and rotational velocity of a user's head.
+     * Measures the orientation and rotational velocity of a user's head. Only for internal use
+     * within the Android system.
      */
     ASENSOR_TYPE_HEAD_TRACKER = 37,
     /**
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h
index 4aa2f60..6794fbf 100644
--- a/include/audiomanager/AudioManager.h
+++ b/include/audiomanager/AudioManager.h
@@ -38,8 +38,52 @@
     PLAYER_STATE_PAUSED   = 3,
     PLAYER_STATE_STOPPED  = 4,
     PLAYER_UPDATE_DEVICE_ID = 5,
+    PLAYER_UPDATE_PORT_ID = 6,
+    PLAYER_UPDATE_MUTED = 7,
 } player_state_t;
 
+static constexpr char
+    kExtraPlayerEventMuteKey[] = "android.media.extra.PLAYER_EVENT_MUTE";
+enum {
+    PLAYER_MUTE_MASTER = (1 << 0),
+    PLAYER_MUTE_STREAM_VOLUME = (1 << 1),
+    PLAYER_MUTE_STREAM_MUTED = (1 << 2),
+    PLAYER_MUTE_PLAYBACK_RESTRICTED = (1 << 3),
+    PLAYER_MUTE_CLIENT_VOLUME = (1 << 4),
+    PLAYER_MUTE_VOLUME_SHAPER = (1 << 5),
+};
+
+struct mute_state_t {
+    /** Flag used when the master volume is causing the mute state. */
+    bool muteFromMasterMute = false;
+    /** Flag used when the stream volume is causing the mute state. */
+    bool muteFromStreamVolume = false;
+    /** Flag used when the stream muted is causing the mute state. */
+    bool muteFromStreamMuted = false;
+    /** Flag used when playback is restricted by AppOps manager with OP_PLAY_AUDIO. */
+    bool muteFromPlaybackRestricted = false;
+    /** Flag used when audio track was muted by client volume. */
+    bool muteFromClientVolume = false;
+     /** Flag used when volume is muted by volume shaper. */
+    bool muteFromVolumeShaper = false;
+
+    explicit operator int() const
+    {
+        int result = muteFromMasterMute * PLAYER_MUTE_MASTER;
+        result |= muteFromStreamVolume * PLAYER_MUTE_STREAM_VOLUME;
+        result |= muteFromStreamMuted * PLAYER_MUTE_STREAM_MUTED;
+        result |= muteFromPlaybackRestricted * PLAYER_MUTE_PLAYBACK_RESTRICTED;
+        result |= muteFromClientVolume * PLAYER_MUTE_CLIENT_VOLUME;
+        result |= muteFromVolumeShaper * PLAYER_MUTE_VOLUME_SHAPER;
+        return result;
+    }
+
+    bool operator==(const mute_state_t& other) const
+    {
+        return static_cast<int>(*this) == static_cast<int>(other);
+    }
+};
+
 // must be kept in sync with definitions in AudioManager.java
 #define RECORD_RIID_INVALID -1
 
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index 426e10c..769670e 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -17,8 +17,10 @@
 #ifndef ANDROID_IAUDIOMANAGER_H
 #define ANDROID_IAUDIOMANAGER_H
 
+#include <audiomanager/AudioManager.h>
 #include <utils/Errors.h>
 #include <binder/IInterface.h>
+#include <binder/PersistableBundle.h>
 #include <hardware/power.h>
 #include <system/audio.h>
 
@@ -40,6 +42,7 @@
         RECORDER_EVENT                        = IBinder::FIRST_CALL_TRANSACTION + 5,
         RELEASE_RECORDER                      = IBinder::FIRST_CALL_TRANSACTION + 6,
         PLAYER_SESSION_ID                     = IBinder::FIRST_CALL_TRANSACTION + 7,
+        PORT_EVENT                            = IBinder::FIRST_CALL_TRANSACTION + 8,
     };
 
     DECLARE_META_INTERFACE(AudioManager)
@@ -52,12 +55,14 @@
     /*oneway*/ virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage,
                 audio_content_type_t content)= 0;
     /*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,
-                audio_port_handle_t deviceId) = 0;
+                audio_port_handle_t eventId) = 0;
     /*oneway*/ virtual status_t releasePlayer(audio_unique_id_t piid) = 0;
     virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) = 0;
     /*oneway*/ virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) = 0;
     /*oneway*/ virtual status_t releaseRecorder(audio_unique_id_t riid) = 0;
     /*oneway*/ virtual status_t playerSessionId(audio_unique_id_t piid, audio_session_t sessionId) = 0;
+    /*oneway*/ virtual status_t portEvent(audio_port_handle_t portId, player_state_t event,
+                const std::unique_ptr<os::PersistableBundle>& extras) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/ftl/details/future.h b/include/ftl/details/future.h
new file mode 100644
index 0000000..df1323e
--- /dev/null
+++ b/include/ftl/details/future.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+namespace android::ftl {
+
+template <typename, template <typename> class>
+class Future;
+
+namespace details {
+
+template <typename T>
+struct future_result {
+  using type = T;
+};
+
+template <typename T>
+struct future_result<std::future<T>> {
+  using type = T;
+};
+
+template <typename T>
+struct future_result<std::shared_future<T>> {
+  using type = T;
+};
+
+template <typename T, template <typename> class FutureImpl>
+struct future_result<Future<T, FutureImpl>> {
+  using type = T;
+};
+
+template <typename T>
+using future_result_t = typename future_result<T>::type;
+
+struct ValueTag {};
+
+template <typename, typename T, template <typename> class>
+class BaseFuture;
+
+template <typename Self, typename T>
+class BaseFuture<Self, T, std::future> {
+  using Impl = std::future<T>;
+
+ public:
+  Future<T, std::shared_future> share() {
+    if (T* value = std::get_if<T>(&self())) {
+      return {ValueTag{}, std::move(*value)};
+    }
+
+    return std::get<Impl>(self()).share();
+  }
+
+ protected:
+  T get() {
+    if (T* value = std::get_if<T>(&self())) {
+      return std::move(*value);
+    }
+
+    return std::get<Impl>(self()).get();
+  }
+
+ private:
+  auto& self() { return static_cast<Self&>(*this).future_; }
+};
+
+template <typename Self, typename T>
+class BaseFuture<Self, T, std::shared_future> {
+  using Impl = std::shared_future<T>;
+
+ protected:
+  const T& get() const {
+    if (const T* value = std::get_if<T>(&self())) {
+      return *value;
+    }
+
+    return std::get<Impl>(self()).get();
+  }
+
+ private:
+  const auto& self() const { return static_cast<const Self&>(*this).future_; }
+};
+
+}  // namespace details
+}  // namespace android::ftl
diff --git a/include/ftl/future.h b/include/ftl/future.h
index dd6358f..c78f9b7 100644
--- a/include/ftl/future.h
+++ b/include/ftl/future.h
@@ -19,18 +19,87 @@
 #include <future>
 #include <type_traits>
 #include <utility>
+#include <variant>
+
+#include <ftl/details/future.h>
 
 namespace android::ftl {
 
-// Creates a future that defers a function call until its result is queried.
+// Thin wrapper around FutureImpl<T> (concretely std::future<T> or std::shared_future<T>) with
+// extensions for pure values (created via ftl::yield) and continuations.
 //
-//   auto future = ftl::defer([](int x) { return x + 1; }, 99);
-//   assert(future.get() == 100);
+// See also SharedFuture<T> shorthand below.
 //
-template <typename F, typename... Args>
-inline auto defer(F&& f, Args&&... args) {
-  return std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
-}
+template <typename T, template <typename> class FutureImpl = std::future>
+class Future final : public details::BaseFuture<Future<T, FutureImpl>, T, FutureImpl> {
+  using Base = details::BaseFuture<Future, T, FutureImpl>;
+
+  friend Base;                                            // For BaseFuture<...>::self.
+  friend details::BaseFuture<Future<T>, T, std::future>;  // For BaseFuture<...>::share.
+
+ public:
+  // Constructs an invalid future.
+  Future() : future_(std::in_place_type<FutureImpl<T>>) {}
+
+  // Constructs a future from its standard counterpart, implicitly.
+  Future(FutureImpl<T>&& f) : future_(std::move(f)) {}
+
+  bool valid() const {
+    return std::holds_alternative<T>(future_) || std::get<FutureImpl<T>>(future_).valid();
+  }
+
+  // Forwarding functions. Base::share is only defined when FutureImpl is std::future, whereas the
+  // following are defined for either FutureImpl:
+  using Base::get;
+
+  // Attaches a continuation to the future. The continuation is a function that maps T to either R
+  // or ftl::Future<R>. In the former case, the chain wraps the result in a future as if by
+  // ftl::yield.
+  //
+  //   auto future = ftl::yield(123);
+  //   ftl::Future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
+  //
+  //   auto chain =
+  //       ftl::Future(std::move(future))
+  //           .then([](int x) { return static_cast<std::size_t>(x % 2); })
+  //           .then([&futures](std::size_t i) { return std::move(futures[i]); });
+  //
+  //   assert(chain.get() == 'b');
+  //
+  template <typename F, typename R = std::invoke_result_t<F, T>>
+  auto then(F&& op) && -> Future<details::future_result_t<R>> {
+    return defer(
+        [](auto&& f, F&& op) {
+          R r = op(f.get());
+          if constexpr (std::is_same_v<R, details::future_result_t<R>>) {
+            return r;
+          } else {
+            return r.get();
+          }
+        },
+        std::move(*this), std::forward<F>(op));
+  }
+
+ private:
+  template <typename V>
+  friend Future<V> yield(V&&);
+
+  template <typename V, typename... Args>
+  friend Future<V> yield(Args&&...);
+
+  template <typename... Args>
+  Future(details::ValueTag, Args&&... args)
+      : future_(std::in_place_type<T>, std::forward<Args>(args)...) {}
+
+  std::variant<T, FutureImpl<T>> future_;
+};
+
+template <typename T>
+using SharedFuture = Future<T, std::shared_future>;
+
+// Deduction guide for implicit conversion.
+template <typename T, template <typename> class FutureImpl>
+Future(FutureImpl<T>&&) -> Future<T, FutureImpl>;
 
 // Creates a future that wraps a value.
 //
@@ -41,69 +110,24 @@
 //   auto future = ftl::yield(std::move(ptr));
 //   assert(*future.get() == '!');
 //
-template <typename T>
-inline std::future<T> yield(T&& v) {
-  return defer([](T&& v) { return std::forward<T>(v); }, std::forward<T>(v));
+template <typename V>
+inline Future<V> yield(V&& value) {
+  return {details::ValueTag{}, std::move(value)};
 }
 
-namespace details {
+template <typename V, typename... Args>
+inline Future<V> yield(Args&&... args) {
+  return {details::ValueTag{}, std::forward<Args>(args)...};
+}
 
-template <typename T>
-struct future_result {
-  using type = T;
-};
-
-template <typename T>
-struct future_result<std::future<T>> {
-  using type = T;
-};
-
-template <typename T>
-using future_result_t = typename future_result<T>::type;
-
-// Attaches a continuation to a future. The continuation is a function that maps T to either R or
-// std::future<R>. In the former case, the chain wraps the result in a future as if by ftl::yield.
+// Creates a future that defers a function call until its result is queried.
 //
-//   auto future = ftl::yield(123);
-//   std::future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
+//   auto future = ftl::defer([](int x) { return x + 1; }, 99);
+//   assert(future.get() == 100);
 //
-//   std::future<char> chain =
-//       ftl::chain(std::move(future))
-//           .then([](int x) { return static_cast<std::size_t>(x % 2); })
-//           .then([&futures](std::size_t i) { return std::move(futures[i]); });
-//
-//   assert(chain.get() == 'b');
-//
-template <typename T>
-struct Chain {
-  // Implicit conversion.
-  Chain(std::future<T>&& f) : future(std::move(f)) {}
-  operator std::future<T>&&() && { return std::move(future); }
-
-  T get() && { return future.get(); }
-
-  template <typename F, typename R = std::invoke_result_t<F, T>>
-  auto then(F&& op) && -> Chain<future_result_t<R>> {
-    return defer(
-        [](auto&& f, F&& op) {
-          R r = op(f.get());
-          if constexpr (std::is_same_v<R, future_result_t<R>>) {
-            return r;
-          } else {
-            return r.get();
-          }
-        },
-        std::move(future), std::forward<F>(op));
-  }
-
-  std::future<T> future;
-};
-
-}  // namespace details
-
-template <typename T>
-inline auto chain(std::future<T>&& f) -> details::Chain<T> {
-  return std::move(f);
+template <typename F, typename... Args>
+inline auto defer(F&& f, Args&&... args) {
+  return Future(std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...));
 }
 
 }  // namespace android::ftl
diff --git a/include/input/Input.h b/include/input/Input.h
index b23a951..a3c9f33 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.
  */
@@ -837,6 +839,8 @@
     std::vector<PointerCoords> mSamplePointerCoords;
 };
 
+std::ostream& operator<<(std::ostream& out, const MotionEvent& event);
+
 /*
  * Focus events.
  */
@@ -1057,6 +1061,48 @@
     uint32_t seq;
 };
 
+/* Pointer icon styles.
+ * Must match the definition in android.view.PointerIcon.
+ *
+ * Due to backwards compatibility and public api constraints, this is a duplicate (but type safe)
+ * definition of PointerIcon.java.
+ *
+ * TODO(b/235023317) move this definition to an aidl and statically assign to the below java public
+ * api values.
+ *
+ * WARNING: Keep these definitions in sync with
+ * frameworks/base/core/java/android/view/PointerIcon.java
+ */
+enum class PointerIconStyle : int32_t {
+    TYPE_CUSTOM = -1,
+    TYPE_NULL = 0,
+    TYPE_ARROW = 1000,
+    TYPE_CONTEXT_MENU = 1001,
+    TYPE_HAND = 1002,
+    TYPE_HELP = 1003,
+    TYPE_WAIT = 1004,
+    TYPE_CELL = 1006,
+    TYPE_CROSSHAIR = 1007,
+    TYPE_TEXT = 1008,
+    TYPE_VERTICAL_TEXT = 1009,
+    TYPE_ALIAS = 1010,
+    TYPE_COPY = 1011,
+    TYPE_NO_DROP = 1012,
+    TYPE_ALL_SCROLL = 1013,
+    TYPE_HORIZONTAL_DOUBLE_ARROW = 1014,
+    TYPE_VERTICAL_DOUBLE_ARROW = 1015,
+    TYPE_TOP_RIGHT_DOUBLE_ARROW = 1016,
+    TYPE_TOP_LEFT_DOUBLE_ARROW = 1017,
+    TYPE_ZOOM_IN = 1018,
+    TYPE_ZOOM_OUT = 1019,
+    TYPE_GRAB = 1020,
+    TYPE_GRABBING = 1021,
+
+    TYPE_SPOT_HOVER = 2000,
+    TYPE_SPOT_TOUCH = 2001,
+    TYPE_SPOT_ANCHOR = 2002,
+};
+
 } // namespace android
 
 #endif // _LIBINPUT_INPUT_H
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index c4f03c9..3585392 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -300,6 +300,8 @@
 /*
  * Gets the path of an input device configuration file, if one is available.
  * Considers both system provided and user installed configuration files.
+ * The optional suffix is appended to the end of the file name (before the
+ * extension).
  *
  * The device identifier is used to construct several default configuration file
  * names to try based on the device name, vendor, product, and version.
@@ -307,8 +309,8 @@
  * Returns an empty string if not found.
  */
 extern std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
-        const InputDeviceIdentifier& deviceIdentifier,
-        InputDeviceConfigurationFileType type);
+        const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type,
+        const char* suffix = "");
 
 /*
  * Gets the path of an input device configuration file, if one is available.
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 5f9a37d..dbc7bfa 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -452,8 +452,11 @@
  */
 class InputConsumer {
 public:
-    /* Creates a consumer associated with an input channel. */
+    /* Create a consumer associated with an input channel. */
     explicit InputConsumer(const std::shared_ptr<InputChannel>& channel);
+    /* Create a consumer associated with an input channel, override resampling system property */
+    explicit InputConsumer(const std::shared_ptr<InputChannel>& channel,
+                           bool enableTouchResampling);
 
     /* Destroys the consumer and releases its input channel. */
     ~InputConsumer();
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index f6f8939..1c9a5ea 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -18,6 +18,7 @@
 #define _LIBINPUT_KEY_CHARACTER_MAP_H
 
 #include <stdint.h>
+#include <list>
 
 #ifdef __linux__
 #include <binder/IBinder.h>
@@ -152,29 +153,22 @@
 
 private:
     struct Behavior {
-        Behavior();
-        Behavior(const Behavior& other);
-
-        /* The next behavior in the list, or NULL if none. */
-        Behavior* next;
-
         /* The meta key modifiers for this behavior. */
-        int32_t metaState;
+        int32_t metaState = 0;
 
         /* The character to insert. */
-        char16_t character;
+        char16_t character = 0;
 
         /* The fallback keycode if the key is not handled. */
-        int32_t fallbackKeyCode;
+        int32_t fallbackKeyCode = 0;
 
         /* The replacement keycode if the key has to be replaced outright. */
-        int32_t replacementKeyCode;
+        int32_t replacementKeyCode = 0;
     };
 
     struct Key {
         Key();
         Key(const Key& other);
-        ~Key();
 
         /* The single character label printed on the key, or 0 if none. */
         char16_t label;
@@ -184,7 +178,7 @@
 
         /* The list of key behaviors sorted from most specific to least specific
          * meta key binding. */
-        Behavior* firstBehavior;
+        std::list<Behavior> behaviors;
     };
 
     class Parser {
@@ -240,8 +234,7 @@
     KeyCharacterMap(const std::string& filename);
 
     bool getKey(int32_t keyCode, const Key** outKey) const;
-    bool getKeyBehavior(int32_t keyCode, int32_t metaState,
-            const Key** outKey, const Behavior** outBehavior) const;
+    const Behavior* getKeyBehavior(int32_t keyCode, int32_t metaState) const;
     static bool matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState);
 
     bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const;
diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h
index b2bd535..1da78aa 100644
--- a/include/input/KeyLayoutMap.h
+++ b/include/input/KeyLayoutMap.h
@@ -20,9 +20,8 @@
 #include <android-base/result.h>
 #include <stdint.h>
 #include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
 #include <utils/Tokenizer.h>
+#include <set>
 
 #include <input/InputDevice.h>
 
@@ -65,18 +64,18 @@
  */
 class KeyLayoutMap {
 public:
-    static base::Result<std::shared_ptr<KeyLayoutMap>> load(const std::string& filename);
-    static base::Result<std::shared_ptr<KeyLayoutMap>> load(Tokenizer* tokenizer);
+    static base::Result<std::shared_ptr<KeyLayoutMap>> load(const std::string& filename,
+                                                            const char* contents = nullptr);
     static base::Result<std::shared_ptr<KeyLayoutMap>> loadContents(const std::string& filename,
                                                                     const char* contents);
 
     status_t mapKey(int32_t scanCode, int32_t usageCode,
             int32_t* outKeyCode, uint32_t* outFlags) const;
-    status_t findScanCodesForKey(int32_t keyCode, std::vector<int32_t>* outScanCodes) const;
-    status_t findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const;
-    status_t findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const;
+    std::vector<int32_t> findScanCodesForKey(int32_t keyCode) const;
+    std::optional<int32_t> findScanCodeForLed(int32_t ledCode) const;
+    std::optional<int32_t> findUsageCodeForLed(int32_t ledCode) const;
 
-    status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
+    std::optional<AxisInfo> mapAxis(int32_t scanCode) const;
     const std::string getLoadFileName() const;
     // Return pair of sensor type and sensor data index, for the input device abs code
     base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t absCode);
@@ -84,6 +83,8 @@
     virtual ~KeyLayoutMap();
 
 private:
+    static base::Result<std::shared_ptr<KeyLayoutMap>> load(Tokenizer* tokenizer);
+
     struct Key {
         int32_t keyCode;
         uint32_t flags;
@@ -98,12 +99,13 @@
         int32_t sensorDataIndex;
     };
 
-    KeyedVector<int32_t, Key> mKeysByScanCode;
-    KeyedVector<int32_t, Key> mKeysByUsageCode;
-    KeyedVector<int32_t, AxisInfo> mAxes;
-    KeyedVector<int32_t, Led> mLedsByScanCode;
-    KeyedVector<int32_t, Led> mLedsByUsageCode;
+    std::unordered_map<int32_t, Key> mKeysByScanCode;
+    std::unordered_map<int32_t, Key> mKeysByUsageCode;
+    std::unordered_map<int32_t, AxisInfo> mAxes;
+    std::unordered_map<int32_t, Led> mLedsByScanCode;
+    std::unordered_map<int32_t, Led> mLedsByUsageCode;
     std::unordered_map<int32_t, Sensor> mSensorsByAbsCode;
+    std::set<std::string> mRequiredKernelConfigs;
     std::string mLoadFileName;
 
     KeyLayoutMap();
@@ -124,6 +126,7 @@
         status_t parseAxis();
         status_t parseLed();
         status_t parseSensor();
+        status_t parseRequiredKernelConfig();
     };
 };
 
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index 08ad8c6..9a3e15f 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -61,9 +61,7 @@
     bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
     status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
     status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
-            const std::string& name);
-    std::string getPath(const InputDeviceIdentifier& deviceIdentifier,
-            const std::string& name, InputDeviceConfigurationFileType type);
+                                 const std::string& name);
 };
 
 /**
diff --git a/include/input/OWNERS b/include/input/OWNERS
new file mode 100644
index 0000000..c88bfe9
--- /dev/null
+++ b/include/input/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/INPUT_OWNERS
diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h
index 7c3b29b..0a75278 100644
--- a/include/input/PrintTools.h
+++ b/include/input/PrintTools.h
@@ -58,4 +58,13 @@
 
 const char* toString(bool value);
 
+/**
+ * Add "prefix" to the beginning of each line in the provided string
+ * "str".
+ * The string 'str' is typically multi-line.
+ * The most common use case for this function is to add some padding
+ * when dumping state.
+ */
+std::string addLinePrefix(std::string str, const std::string& prefix);
+
 } // namespace android
\ No newline at end of file
diff --git a/include/input/PropertyMap.h b/include/input/PropertyMap.h
index 451918b..b1e3f85 100644
--- a/include/input/PropertyMap.h
+++ b/include/input/PropertyMap.h
@@ -18,10 +18,8 @@
 #define _UTILS_PROPERTY_MAP_H
 
 #include <android-base/result.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
 #include <utils/Tokenizer.h>
+#include <unordered_map>
 
 namespace android {
 
@@ -58,30 +56,27 @@
     /* Adds a property.
      * Replaces the property with the same key if it is already present.
      */
-    void addProperty(const String8& key, const String8& value);
-
-    /* Returns true if the property map contains the specified key. */
-    bool hasProperty(const String8& key) const;
+    void addProperty(const std::string& key, const std::string& value);
 
     /* Gets the value of a property and parses it.
      * Returns true and sets outValue if the key was found and its value was parsed successfully.
      * Otherwise returns false and does not modify outValue.  (Also logs a warning.)
      */
-    bool tryGetProperty(const String8& key, String8& outValue) const;
-    bool tryGetProperty(const String8& key, bool& outValue) const;
-    bool tryGetProperty(const String8& key, int32_t& outValue) const;
-    bool tryGetProperty(const String8& key, float& outValue) const;
+    bool tryGetProperty(const std::string& key, std::string& outValue) const;
+    bool tryGetProperty(const std::string& key, bool& outValue) const;
+    bool tryGetProperty(const std::string& key, int32_t& outValue) const;
+    bool tryGetProperty(const std::string& key, float& outValue) const;
 
     /* Adds all values from the specified property map. */
     void addAll(const PropertyMap* map);
 
-    /* Gets the underlying property map. */
-    inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; }
-
     /* Loads a property map from a file. */
     static android::base::Result<std::unique_ptr<PropertyMap>> load(const char* filename);
 
 private:
+    /* Returns true if the property map contains the specified key. */
+    bool hasProperty(const std::string& key) const;
+
     class Parser {
         PropertyMap* mMap;
         Tokenizer* mTokenizer;
@@ -95,11 +90,11 @@
         status_t parseType();
         status_t parseKey();
         status_t parseKeyProperty();
-        status_t parseModifier(const String8& token, int32_t* outMetaState);
+        status_t parseModifier(const std::string& token, int32_t* outMetaState);
         status_t parseCharacterLiteral(char16_t* outCharacter);
     };
 
-    KeyedVector<String8, String8> mProperties;
+    std::unordered_map<std::string, std::string> mProperties;
 };
 
 } // namespace android
diff --git a/libs/adbd_auth/libadbd_auth.map.txt b/libs/adbd_auth/libadbd_auth.map.txt
index 7584ca3..f9f042e 100644
--- a/libs/adbd_auth/libadbd_auth.map.txt
+++ b/libs/adbd_auth/libadbd_auth.map.txt
@@ -1,17 +1,17 @@
 LIBADBD_AUTH {
   global:
-    adbd_auth_new; # apex introduced=30
-    adbd_auth_delete; # apex introduced=30
-    adbd_auth_run; # apex introduced=30
-    adbd_auth_get_public_keys; #apex introduced=30
-    adbd_auth_notify_auth; # apex introduced=30
-    adbd_auth_notify_disconnect; # apex introduced=30
-    adbd_auth_prompt_user; # apex introduced=30
-    adbd_auth_prompt_user_with_id; # apex introduced=30
-    adbd_auth_tls_device_connected; # apex introduced=30
-    adbd_auth_tls_device_disconnected; # apex introduced=30
-    adbd_auth_get_max_version; # apex introduced=30
-    adbd_auth_supports_feature; # apex introduced=30
+    adbd_auth_new; # systemapi introduced=30
+    adbd_auth_delete; # systemapi introduced=30
+    adbd_auth_run; # systemapi introduced=30
+    adbd_auth_get_public_keys; # systemapi introduced=30
+    adbd_auth_notify_auth; # systemapi introduced=30
+    adbd_auth_notify_disconnect; # systemapi introduced=30
+    adbd_auth_prompt_user; # systemapi introduced=30
+    adbd_auth_prompt_user_with_id; # systemapi introduced=30
+    adbd_auth_tls_device_connected; # systemapi introduced=30
+    adbd_auth_tls_device_disconnected; # systemapi introduced=30
+    adbd_auth_get_max_version; # systemapi introduced=30
+    adbd_auth_supports_feature; # systemapi introduced=30
   local:
     *;
 };
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 41b3460..76e3e66 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -39,9 +39,16 @@
 
 cc_library_headers {
     name: "libarect_headers",
+    vendor_available: true,
+    min_sdk_version: "29",
     // TODO(b/153609531): remove when no longer needed.
     native_bridge_supported: true,
     export_include_dirs: ["include"],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media",
+        "com.android.media.swcodec",
+    ],
 }
 
 cc_library_static {
diff --git a/libs/attestation/Android.bp b/libs/attestation/Android.bp
index ea3c341..2bf15d4 100644
--- a/libs/attestation/Android.bp
+++ b/libs/attestation/Android.bp
@@ -28,11 +28,9 @@
         "-Werror",
     ],
     srcs: [
-        "HmacKeyManager.cpp"
+        "HmacKeyManager.cpp",
     ],
 
-    clang: true,
-
     shared_libs: [
         "liblog",
         "libcrypto",
diff --git a/libs/battery/MultiStateCounter.h b/libs/battery/MultiStateCounter.h
index 0caf005..ce9cd1c 100644
--- a/libs/battery/MultiStateCounter.h
+++ b/libs/battery/MultiStateCounter.h
@@ -139,22 +139,35 @@
         return;
     }
 
-    if (!enabled) {
+    if (isEnabled) {
         // Confirm the current state for the side-effect of updating the time-in-state
         // counter for the current state.
         setState(currentState, timestamp);
-    }
+        isEnabled = false;
+    } else {
+        // If the counter is being enabled with an out-of-order timestamp, just push back
+        // the timestamp to avoid having the situation where
+        // timeInStateSinceUpdate > timeSinceUpdate
+        if (timestamp < lastUpdateTimestamp) {
+            timestamp = lastUpdateTimestamp;
+        }
 
-    isEnabled = enabled;
-
-    if (lastStateChangeTimestamp >= 0) {
-        lastStateChangeTimestamp = timestamp;
+        if (lastStateChangeTimestamp >= 0) {
+            lastStateChangeTimestamp = timestamp;
+        }
+        isEnabled = true;
     }
 }
 
 template <class T>
 void MultiStateCounter<T>::setState(state_t state, time_t timestamp) {
-    if (isEnabled && lastStateChangeTimestamp >= 0) {
+    if (isEnabled && lastStateChangeTimestamp >= 0 && lastUpdateTimestamp >= 0) {
+        // If the update arrived out-of-order, just push back the timestamp to
+        // avoid having the situation where timeInStateSinceUpdate > timeSinceUpdate
+        if (timestamp < lastUpdateTimestamp) {
+            timestamp = lastUpdateTimestamp;
+        }
+
         if (timestamp >= lastStateChangeTimestamp) {
             states[currentState].timeInStateSinceUpdate += timestamp - lastStateChangeTimestamp;
         } else {
@@ -185,6 +198,12 @@
     // If the counter is disabled, we ignore the update, except when the counter got disabled after
     // the previous update, in which case we still need to pick up the residual delta.
     if (isEnabled || lastUpdateTimestamp < lastStateChangeTimestamp) {
+        // If the update arrived out of order, just push back the timestamp to
+        // avoid having the situation where timeInStateSinceUpdate > timeSinceUpdate
+        if (timestamp < lastStateChangeTimestamp) {
+            timestamp = lastStateChangeTimestamp;
+        }
+
         // Confirm the current state for the side-effect of updating the time-in-state
         // counter for the current state.
         setState(currentState, timestamp);
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 200586a..5e9f540 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -60,27 +60,19 @@
 //
 // Currently, these are only on system android (not vendor, not host)
 // TODO(b/183654927) - move these into separate libraries
-libbinder_device_interface_sources = [
-    "IPermissionController.cpp",
-    "PermissionCache.cpp",
-    "PermissionController.cpp",
-]
 
-cc_library {
-    name: "libbinder",
+filegroup {
+    name: "libbinder_device_interface_sources",
+    srcs: [
+        "IPermissionController.cpp",
+        "PermissionCache.cpp",
+        "PermissionController.cpp",
+    ],
+}
 
-    version_script: "libbinder.map",
-
-    // for vndbinder
-    vendor_available: true,
-    vndk: {
-        enabled: true,
-    },
-    recovery_available: true,
-    double_loadable: true,
+cc_defaults {
+    name: "libbinder_defaults",
     host_supported: true,
-    // TODO(b/153609531): remove when no longer needed.
-    native_bridge_supported: true,
 
     // TODO(b/31559095): get headers from bionic on host
     include_dirs: [
@@ -88,72 +80,32 @@
         "bionic/libc/kernel/uapi/",
     ],
 
-    // libbinder does not offer a stable wire protocol.
-    // if a second copy of it is installed, then it may break after security
-    // or dessert updates. Instead, apex users should use libbinder_ndk.
-    apex_available: [
-        "//apex_available:platform",
-    ],
-
     srcs: [
         "Binder.cpp",
         "BpBinder.cpp",
-        "BufferedTextOutput.cpp",
         "Debug.cpp",
         "FdTrigger.cpp",
         "IInterface.cpp",
-        "IMemory.cpp",
-        "IPCThreadState.cpp",
         "IResultReceiver.cpp",
-        "IServiceManager.cpp",
-        "IShellCallback.cpp",
-        "LazyServiceRegistrar.cpp",
-        "MemoryBase.cpp",
-        "MemoryDealer.cpp",
-        "MemoryHeapBase.cpp",
+        "OS.cpp",
         "Parcel.cpp",
-        "ParcelableHolder.cpp",
         "ParcelFileDescriptor.cpp",
-        "PersistableBundle.cpp",
-        "ProcessState.cpp",
         "RpcSession.cpp",
         "RpcServer.cpp",
         "RpcState.cpp",
         "RpcTransportRaw.cpp",
-        "Static.cpp",
         "Stability.cpp",
         "Status.cpp",
         "TextOutput.cpp",
         "Utils.cpp",
-        ":libbinder_aidl",
     ],
 
     target: {
-        android: {
-            srcs: libbinder_device_interface_sources,
-
-            // NOT static to keep the wire protocol unfrozen
-            static: {
-                enabled: false,
-            },
-        },
-        vendor: {
-            exclude_srcs: libbinder_device_interface_sources,
-        },
-        darwin: {
-            enabled: false,
-        },
         host: {
             srcs: [
-                "ServiceManagerHost.cpp",
                 "UtilsHost.cpp",
             ],
         },
-        recovery: {
-            exclude_header_libs: [
-                "libandroid_runtime_vm_headers",
-            ],
-        },
     },
 
     aidl: {
@@ -161,7 +113,6 @@
     },
 
     cflags: [
-        "-Wall",
         "-Wextra",
         "-Wextra-semi",
         "-Werror",
@@ -199,7 +150,6 @@
         "libbinder_headers",
     ],
 
-    clang: true,
     sanitize: {
         misc_undefined: ["integer"],
     },
@@ -217,6 +167,7 @@
         "abseil-*",
         "android-*",
         "bugprone-*",
+        "-bugprone-branch-clone", // b/155034972
         "cert-*",
         "clang-analyzer-*",
         "google-*",
@@ -224,10 +175,126 @@
         "performance*",
         "portability*",
     ],
+}
+
+cc_defaults {
+    name: "libbinder_kernel_defaults",
+    srcs: [
+        "BufferedTextOutput.cpp",
+        "IPCThreadState.cpp",
+        "IServiceManager.cpp",
+        "ProcessState.cpp",
+        "Static.cpp",
+        ":libbinder_aidl",
+        ":libbinder_device_interface_sources",
+    ],
+    target: {
+        vendor: {
+            exclude_srcs: [
+                ":libbinder_device_interface_sources",
+            ],
+        },
+        host: {
+            srcs: [
+                "ServiceManagerHost.cpp",
+            ],
+        },
+    },
+    cflags: [
+        "-DBINDER_WITH_KERNEL_IPC",
+    ],
+}
+
+cc_library {
+    name: "libbinder",
+    defaults: [
+        "libbinder_defaults",
+        "libbinder_kernel_defaults",
+    ],
+
+    version_script: "libbinder.map",
+
+    // for vndbinder
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+    recovery_available: true,
+    double_loadable: true,
+    // TODO(b/153609531): remove when no longer needed.
+    native_bridge_supported: true,
+
+    // libbinder does not offer a stable wire protocol.
+    // if a second copy of it is installed, then it may break after security
+    // or dessert updates. Instead, apex users should use libbinder_ndk.
+    apex_available: [
+        "//apex_available:platform",
+    ],
+
+    srcs: [
+        "IMemory.cpp",
+        "IShellCallback.cpp",
+        "LazyServiceRegistrar.cpp",
+        "MemoryBase.cpp",
+        "MemoryDealer.cpp",
+        "MemoryHeapBase.cpp",
+        "ParcelableHolder.cpp",
+        "PersistableBundle.cpp",
+    ],
+
+    target: {
+        android: {
+            // NOT static to keep the wire protocol unfrozen
+            static: {
+                enabled: false,
+            },
+        },
+        darwin: {
+            enabled: false,
+        },
+        recovery: {
+            exclude_header_libs: [
+                "libandroid_runtime_vm_headers",
+            ],
+        },
+    },
 
     afdo: true,
 }
 
+cc_library_static {
+    name: "libbinder_rpc_no_kernel",
+    defaults: ["libbinder_defaults"],
+    visibility: [
+        ":__subpackages__",
+    ],
+}
+
+cc_library_static {
+    name: "libbinder_rpc_single_threaded",
+    defaults: [
+        "libbinder_defaults",
+        "libbinder_kernel_defaults",
+    ],
+    cflags: [
+        "-DBINDER_RPC_SINGLE_THREADED",
+    ],
+    visibility: [
+        ":__subpackages__",
+    ],
+}
+
+cc_library_static {
+    name: "libbinder_rpc_single_threaded_no_kernel",
+    defaults: ["libbinder_defaults"],
+    cflags: [
+        "-DBINDER_RPC_SINGLE_THREADED",
+    ],
+    visibility: [
+        ":__subpackages__",
+    ],
+}
+
 cc_defaults {
     name: "libbinder_tls_shared_deps",
     shared_libs: [
@@ -364,6 +431,7 @@
 
 cc_library {
     name: "libbatterystats_aidl",
+    host_supported: true,
     srcs: [
         "IBatteryStats.cpp",
     ],
@@ -376,6 +444,7 @@
 
 cc_library {
     name: "libprocessinfoservice_aidl",
+    host_supported: true,
     srcs: [
         "IProcessInfoService.cpp",
         "ProcessInfoService.cpp",
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 39befbe..b5ea60f 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -32,9 +32,13 @@
 #include <utils/misc.h>
 
 #include <inttypes.h>
-#include <linux/sched.h>
 #include <stdio.h>
 
+#ifdef __linux__
+#include <linux/sched.h>
+#endif
+
+#include "BuildFlags.h"
 #include "RpcState.h"
 
 namespace android {
@@ -49,10 +53,11 @@
 static_assert(sizeof(BBinder) == 20);
 #endif
 
+// global b/c b/230079120 - consistent symbol table
 #ifdef BINDER_RPC_DEV_SERVERS
-constexpr const bool kEnableRpcDevServers = true;
+bool kEnableRpcDevServers = true;
 #else
-constexpr const bool kEnableRpcDevServers = false;
+bool kEnableRpcDevServers = false;
 #endif
 
 // Log any reply transactions for which the data exceeds this size
@@ -156,10 +161,14 @@
 
 status_t IBinder::setRpcClientDebug(android::base::unique_fd socketFd,
                                     const sp<IBinder>& keepAliveBinder) {
-    if constexpr (!kEnableRpcDevServers) {
+    if (!kEnableRpcDevServers) {
         ALOGW("setRpcClientDebug disallowed because RPC is not enabled");
         return INVALID_OPERATION;
     }
+    if (!kEnableKernelIpc) {
+        ALOGW("setRpcClientDebug disallowed because kernel binder is not enabled");
+        return INVALID_OPERATION;
+    }
 
     BBinder* local = this->localBinder();
     if (local != nullptr) {
@@ -201,6 +210,7 @@
     RpcServerLink(const sp<RpcServer>& rpcServer, const sp<IBinder>& keepAliveBinder,
                   const wp<BBinder>& binder)
           : mRpcServer(rpcServer), mKeepAliveBinder(keepAliveBinder), mBinder(binder) {}
+    virtual ~RpcServerLink();
     void binderDied(const wp<IBinder>&) override {
         LOG_RPC_DETAIL("RpcServerLink: binder died, shutting down RpcServer");
         if (mRpcServer == nullptr) {
@@ -226,16 +236,19 @@
     sp<IBinder> mKeepAliveBinder; // hold to avoid automatically unlinking
     wp<BBinder> mBinder;
 };
+BBinder::RpcServerLink::~RpcServerLink() {}
 
 class BBinder::Extras
 {
 public:
     // unlocked objects
-    bool mRequestingSid = false;
-    bool mInheritRt = false;
     sp<IBinder> mExtension;
+#ifdef __linux__
     int mPolicy = SCHED_NORMAL;
     int mPriority = 0;
+#endif
+    bool mRequestingSid = false;
+    bool mInheritRt = false;
 
     // for below objects
     Mutex mLock;
@@ -404,6 +417,7 @@
     return e->mExtension;
 }
 
+#ifdef __linux__
 void BBinder::setMinSchedulerPolicy(int policy, int priority) {
     LOG_ALWAYS_FATAL_IF(mParceled,
                         "setMinSchedulerPolicy() should not be called after a binder object "
@@ -448,6 +462,7 @@
     if (e == nullptr) return 0;
     return e->mPriority;
 }
+#endif // __linux__
 
 bool BBinder::isInheritRt() {
     Extras* e = mExtras.load(std::memory_order_acquire);
@@ -475,7 +490,12 @@
 }
 
 pid_t BBinder::getDebugPid() {
+#ifdef __linux__
     return getpid();
+#else
+    // TODO: handle other OSes
+    return 0;
+#endif // __linux__
 }
 
 void BBinder::setExtension(const sp<IBinder>& extension) {
@@ -496,10 +516,14 @@
 }
 
 status_t BBinder::setRpcClientDebug(const Parcel& data) {
-    if constexpr (!kEnableRpcDevServers) {
+    if (!kEnableRpcDevServers) {
         ALOGW("%s: disallowed because RPC is not enabled", __PRETTY_FUNCTION__);
         return INVALID_OPERATION;
     }
+    if (!kEnableKernelIpc) {
+        ALOGW("setRpcClientDebug disallowed because kernel binder is not enabled");
+        return INVALID_OPERATION;
+    }
     uid_t uid = IPCThreadState::self()->getCallingUid();
     if (uid != AID_ROOT) {
         ALOGE("%s: not allowed because client %" PRIu32 " is not root", __PRETTY_FUNCTION__, uid);
@@ -521,10 +545,14 @@
 
 status_t BBinder::setRpcClientDebug(android::base::unique_fd socketFd,
                                     const sp<IBinder>& keepAliveBinder) {
-    if constexpr (!kEnableRpcDevServers) {
+    if (!kEnableRpcDevServers) {
         ALOGW("%s: disallowed because RPC is not enabled", __PRETTY_FUNCTION__);
         return INVALID_OPERATION;
     }
+    if (!kEnableKernelIpc) {
+        ALOGW("setRpcClientDebug disallowed because kernel binder is not enabled");
+        return INVALID_OPERATION;
+    }
 
     const int socketFdForPrint = socketFd.get();
     LOG_RPC_DETAIL("%s(fd=%d)", __PRETTY_FUNCTION__, socketFdForPrint);
@@ -539,7 +567,7 @@
         return UNEXPECTED_NULL;
     }
 
-    size_t binderThreadPoolMaxCount = ProcessState::self()->getThreadPoolMaxThreadCount();
+    size_t binderThreadPoolMaxCount = ProcessState::self()->getThreadPoolMaxTotalThreadCount();
     if (binderThreadPoolMaxCount <= 1) {
         ALOGE("%s: ProcessState thread pool max count is %zu. RPC is disabled for this service "
               "because RPC requires the service to support multithreading.",
@@ -582,8 +610,24 @@
 
 BBinder::~BBinder()
 {
-    if (!wasParceled() && getExtension()) {
-        ALOGW("Binder %p destroyed with extension attached before being parceled.", this);
+    if (!wasParceled()) {
+        if (getExtension()) {
+             ALOGW("Binder %p destroyed with extension attached before being parceled.", this);
+        }
+        if (isRequestingSid()) {
+             ALOGW("Binder %p destroyed when requesting SID before being parceled.", this);
+        }
+        if (isInheritRt()) {
+             ALOGW("Binder %p destroyed after setInheritRt before being parceled.", this);
+        }
+#ifdef __linux__
+        if (getMinSchedulerPolicy() != SCHED_NORMAL) {
+             ALOGW("Binder %p destroyed after setMinSchedulerPolicy before being parceled.", this);
+        }
+        if (getMinSchedulerPriority() != 0) {
+             ALOGW("Binder %p destroyed after setMinSchedulerPolicy before being parceled.", this);
+        }
+#endif // __linux__
     }
 
     Extras* e = mExtras.load(std::memory_order_relaxed);
@@ -620,13 +664,14 @@
             for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
                args.add(data.readString16());
             }
-            sp<IShellCallback> shellCallback = IShellCallback::asInterface(
-                    data.readStrongBinder());
+            sp<IBinder> shellCallbackBinder = data.readStrongBinder();
             sp<IResultReceiver> resultReceiver = IResultReceiver::asInterface(
                     data.readStrongBinder());
 
             // XXX can't add virtuals until binaries are updated.
-            //return shellCommand(in, out, err, args, resultReceiver);
+            // sp<IShellCallback> shellCallback = IShellCallback::asInterface(
+            //        shellCallbackBinder);
+            // return shellCommand(in, out, err, args, resultReceiver);
             (void)in;
             (void)out;
             (void)err;
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 921e57c..b6d35ef 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -28,6 +28,8 @@
 
 #include <stdio.h>
 
+#include "BuildFlags.h"
+
 //#undef ALOGV
 //#define ALOGV(...) fprintf(stderr, __VA_ARGS__)
 
@@ -115,6 +117,11 @@
 // ---------------------------------------------------------------------------
 
 sp<BpBinder> BpBinder::create(int32_t handle) {
+    if constexpr (!kEnableKernelIpc) {
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return nullptr;
+    }
+
     int32_t trackedUid = -1;
     if (sCountByUidEnabled) {
         trackedUid = IPCThreadState::self()->getCallingUid();
@@ -177,6 +184,11 @@
 }
 
 BpBinder::BpBinder(BinderHandle&& handle, int32_t trackedUid) : BpBinder(Handle(handle)) {
+    if constexpr (!kEnableKernelIpc) {
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return;
+    }
+
     mTrackedUid = trackedUid;
 
     ALOGV("Creating BpBinder %p handle %d\n", this, this->binderHandle());
@@ -279,7 +291,7 @@
     if (mAlive) {
         bool privateVendor = flags & FLAG_PRIVATE_VENDOR;
         // don't send userspace flags to the kernel
-        flags = flags & ~FLAG_PRIVATE_VENDOR;
+        flags = flags & ~static_cast<uint32_t>(FLAG_PRIVATE_VENDOR);
 
         // user transactions require a given stability level
         if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
@@ -303,6 +315,11 @@
             status = rpcSession()->transact(sp<IBinder>::fromExisting(this), code, data, reply,
                                             flags);
         } else {
+            if constexpr (!kEnableKernelIpc) {
+                LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+                return INVALID_OPERATION;
+            }
+
             status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
         }
         if (data.dataSize() > LOG_TRANSACTIONS_OVER_SIZE) {
@@ -326,7 +343,24 @@
 status_t BpBinder::linkToDeath(
     const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
 {
-    if (isRpcBinder()) return UNKNOWN_TRANSACTION;
+    if (isRpcBinder()) {
+        if (rpcSession()->getMaxIncomingThreads() < 1) {
+            LOG_ALWAYS_FATAL("Cannot register a DeathRecipient without any incoming connections.");
+            return INVALID_OPERATION;
+        }
+    } else if constexpr (!kEnableKernelIpc) {
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return INVALID_OPERATION;
+    } else {
+        if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() == 0) {
+            ALOGW("Linking to death on %s but there are no threads (yet?) listening to incoming "
+                  "transactions. See ProcessState::startThreadPool and "
+                  "ProcessState::setThreadPoolMaxThreadCount. Generally you should setup the "
+                  "binder "
+                  "threadpool before other initialization steps.",
+                  String8(getInterfaceDescriptor()).c_str());
+        }
+    }
 
     Obituary ob;
     ob.recipient = recipient;
@@ -346,10 +380,14 @@
                     return NO_MEMORY;
                 }
                 ALOGV("Requesting death notification: %p handle %d\n", this, binderHandle());
-                getWeakRefs()->incWeak(this);
-                IPCThreadState* self = IPCThreadState::self();
-                self->requestDeathNotification(binderHandle(), this);
-                self->flushCommands();
+                if (!isRpcBinder()) {
+                    if constexpr (kEnableKernelIpc) {
+                        getWeakRefs()->incWeak(this);
+                        IPCThreadState* self = IPCThreadState::self();
+                        self->requestDeathNotification(binderHandle(), this);
+                        self->flushCommands();
+                    }
+                }
             }
             ssize_t res = mObituaries->add(ob);
             return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
@@ -364,7 +402,10 @@
     const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
     wp<DeathRecipient>* outRecipient)
 {
-    if (isRpcBinder()) return UNKNOWN_TRANSACTION;
+    if (!kEnableKernelIpc && !isRpcBinder()) {
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return INVALID_OPERATION;
+    }
 
     AutoMutex _l(mLock);
 
@@ -384,9 +425,13 @@
             mObituaries->removeAt(i);
             if (mObituaries->size() == 0) {
                 ALOGV("Clearing death notification: %p handle %d\n", this, binderHandle());
-                IPCThreadState* self = IPCThreadState::self();
-                self->clearDeathNotification(binderHandle(), this);
-                self->flushCommands();
+                if (!isRpcBinder()) {
+                    if constexpr (kEnableKernelIpc) {
+                        IPCThreadState* self = IPCThreadState::self();
+                        self->clearDeathNotification(binderHandle(), this);
+                        self->flushCommands();
+                    }
+                }
                 delete mObituaries;
                 mObituaries = nullptr;
             }
@@ -399,7 +444,10 @@
 
 void BpBinder::sendObituary()
 {
-    LOG_ALWAYS_FATAL_IF(isRpcBinder(), "Cannot send obituary for remote binder.");
+    if (!kEnableKernelIpc && !isRpcBinder()) {
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return;
+    }
 
     ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n", this, binderHandle(),
           mObitsSent ? "true" : "false");
@@ -411,9 +459,13 @@
     Vector<Obituary>* obits = mObituaries;
     if(obits != nullptr) {
         ALOGV("Clearing sent death notification: %p handle %d\n", this, binderHandle());
-        IPCThreadState* self = IPCThreadState::self();
-        self->clearDeathNotification(binderHandle(), this);
-        self->flushCommands();
+        if (!isRpcBinder()) {
+            if constexpr (kEnableKernelIpc) {
+                IPCThreadState* self = IPCThreadState::self();
+                self->clearDeathNotification(binderHandle(), this);
+                self->flushCommands();
+            }
+        }
         mObituaries = nullptr;
     }
     mObitsSent = 1;
@@ -469,12 +521,16 @@
     return this;
 }
 
-BpBinder::~BpBinder()
-{
-    ALOGV("Destroying BpBinder %p handle %d\n", this, binderHandle());
-
+BpBinder::~BpBinder() {
     if (CC_UNLIKELY(isRpcBinder())) return;
 
+    if constexpr (!kEnableKernelIpc) {
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return;
+    }
+
+    ALOGV("Destroying BpBinder %p handle %d\n", this, binderHandle());
+
     IPCThreadState* ipc = IPCThreadState::self();
 
     if (mTrackedUid >= 0) {
@@ -505,21 +561,31 @@
     }
 }
 
-void BpBinder::onFirstRef()
-{
-    ALOGV("onFirstRef BpBinder %p handle %d\n", this, binderHandle());
+void BpBinder::onFirstRef() {
     if (CC_UNLIKELY(isRpcBinder())) return;
+
+    if constexpr (!kEnableKernelIpc) {
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return;
+    }
+
+    ALOGV("onFirstRef BpBinder %p handle %d\n", this, binderHandle());
     IPCThreadState* ipc = IPCThreadState::self();
     if (ipc) ipc->incStrongHandle(binderHandle(), this);
 }
 
-void BpBinder::onLastStrongRef(const void* /*id*/)
-{
-    ALOGV("onLastStrongRef BpBinder %p handle %d\n", this, binderHandle());
+void BpBinder::onLastStrongRef(const void* /*id*/) {
     if (CC_UNLIKELY(isRpcBinder())) {
         (void)rpcSession()->sendDecStrong(this);
         return;
     }
+
+    if constexpr (!kEnableKernelIpc) {
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return;
+    }
+
+    ALOGV("onLastStrongRef BpBinder %p handle %d\n", this, binderHandle());
     IF_ALOGV() {
         printRefs();
     }
@@ -552,6 +618,11 @@
     // RPC binder doesn't currently support inc from weak binders
     if (CC_UNLIKELY(isRpcBinder())) return false;
 
+    if constexpr (!kEnableKernelIpc) {
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return false;
+    }
+
     ALOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, binderHandle());
     IPCThreadState* ipc = IPCThreadState::self();
     return ipc ? ipc->attemptIncStrongHandle(binderHandle()) == NO_ERROR : false;
diff --git a/libs/binder/BuildFlags.h b/libs/binder/BuildFlags.h
new file mode 100644
index 0000000..3e9d1c2
--- /dev/null
+++ b/libs/binder/BuildFlags.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+namespace android {
+
+#ifdef BINDER_RPC_SINGLE_THREADED
+constexpr bool kEnableRpcThreads = false;
+#else
+constexpr bool kEnableRpcThreads = true;
+#endif
+
+#ifdef BINDER_WITH_KERNEL_IPC
+constexpr bool kEnableKernelIpc = true;
+#else  // BINDER_WITH_KERNEL_IPC
+constexpr bool kEnableKernelIpc = false;
+#endif // BINDER_WITH_KERNEL_IPC
+
+} // namespace android
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index e4ac4b4..c6e4fb3 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "Debug.h"
+#include "BuildFlags.h"
 
 #include <binder/ProcessState.h>
 
@@ -301,6 +302,11 @@
 }
 
 ssize_t getBinderKernelReferences(size_t count, uintptr_t* buf) {
+    if constexpr (!kEnableKernelIpc) {
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return 0;
+    }
+
     sp<ProcessState> proc = ProcessState::selfOrNull();
     if (proc.get() == nullptr) {
         return 0;
diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
index 5e22593..d123fd1 100644
--- a/libs/binder/FdTrigger.cpp
+++ b/libs/binder/FdTrigger.cpp
@@ -28,25 +28,45 @@
 
 std::unique_ptr<FdTrigger> FdTrigger::make() {
     auto ret = std::make_unique<FdTrigger>();
+#ifndef BINDER_RPC_SINGLE_THREADED
     if (!android::base::Pipe(&ret->mRead, &ret->mWrite)) {
         ALOGE("Could not create pipe %s", strerror(errno));
         return nullptr;
     }
+#endif
     return ret;
 }
 
 void FdTrigger::trigger() {
+#ifdef BINDER_RPC_SINGLE_THREADED
+    mTriggered = true;
+#else
     mWrite.reset();
+#endif
 }
 
 bool FdTrigger::isTriggered() {
+#ifdef BINDER_RPC_SINGLE_THREADED
+    return mTriggered;
+#else
     return mWrite == -1;
+#endif
 }
 
 status_t FdTrigger::triggerablePoll(base::borrowed_fd fd, int16_t event) {
+#ifdef BINDER_RPC_SINGLE_THREADED
+    if (mTriggered) {
+        return DEAD_OBJECT;
+    }
+#endif
+
     LOG_ALWAYS_FATAL_IF(event == 0, "triggerablePoll %d with event 0 is not allowed", fd.get());
-    pollfd pfd[]{{.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
-                 {.fd = mRead.get(), .events = 0, .revents = 0}};
+    pollfd pfd[]{
+            {.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
+#ifndef BINDER_RPC_SINGLE_THREADED
+            {.fd = mRead.get(), .events = 0, .revents = 0},
+#endif
+    };
     int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
     if (ret < 0) {
         return -errno;
@@ -55,6 +75,7 @@
 
     // At least one FD has events. Check them.
 
+#ifndef BINDER_RPC_SINGLE_THREADED
     // Detect explicit trigger(): DEAD_OBJECT
     if (pfd[1].revents & POLLHUP) {
         return DEAD_OBJECT;
@@ -68,6 +89,7 @@
 
     // pfd[1].revents is 0, hence pfd[0].revents must be set, and only possible values are
     // a subset of event | POLLHUP | POLLERR | POLLNVAL.
+#endif
 
     // POLLNVAL: invalid FD number, e.g. not opened.
     if (pfd[0].revents & POLLNVAL) {
diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h
index a545d6c..a25dc11 100644
--- a/libs/binder/FdTrigger.h
+++ b/libs/binder/FdTrigger.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #include <memory>
 
@@ -55,7 +56,11 @@
     [[nodiscard]] status_t triggerablePoll(base::borrowed_fd fd, int16_t event);
 
 private:
+#ifdef BINDER_RPC_SINGLE_THREADED
+    bool mTriggered = false;
+#else
     base::unique_fd mWrite;
     base::unique_fd mRead;
+#endif
 };
 } // namespace android
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 3c97dca..b50cfb3 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -638,7 +638,9 @@
 void IPCThreadState::joinThreadPool(bool isMain)
 {
     LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
-
+    pthread_mutex_lock(&mProcess->mThreadCountLock);
+    mProcess->mCurrentThreads++;
+    pthread_mutex_unlock(&mProcess->mThreadCountLock);
     mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
 
     mIsLooper = true;
@@ -666,6 +668,13 @@
     mOut.writeInt32(BC_EXIT_LOOPER);
     mIsLooper = false;
     talkWithDriver(false);
+    pthread_mutex_lock(&mProcess->mThreadCountLock);
+    LOG_ALWAYS_FATAL_IF(mProcess->mCurrentThreads == 0,
+                        "Threadpool thread count = 0. Thread cannot exist and exit in empty "
+                        "threadpool\n"
+                        "Misconfiguration. Increase threadpool max threads configuration\n");
+    mProcess->mCurrentThreads--;
+    pthread_mutex_unlock(&mProcess->mThreadCountLock);
 }
 
 status_t IPCThreadState::setupPolling(int* fd)
@@ -677,6 +686,9 @@
     mOut.writeInt32(BC_ENTER_LOOPER);
     flushCommands();
     *fd = mProcess->mDriverFD;
+    pthread_mutex_lock(&mProcess->mThreadCountLock);
+    mProcess->mCurrentThreads++;
+    pthread_mutex_unlock(&mProcess->mThreadCountLock);
     return 0;
 }
 
@@ -960,18 +972,15 @@
                             freeBuffer);
                     } else {
                         err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
-                        freeBuffer(nullptr,
-                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
-                            tr.data_size,
-                            reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
-                            tr.offsets_size/sizeof(binder_size_t));
+                        freeBuffer(reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+                                   tr.data_size,
+                                   reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
+                                   tr.offsets_size / sizeof(binder_size_t));
                     }
                 } else {
-                    freeBuffer(nullptr,
-                        reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
-                        tr.data_size,
-                        reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
-                        tr.offsets_size/sizeof(binder_size_t));
+                    freeBuffer(reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), tr.data_size,
+                               reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
+                               tr.offsets_size / sizeof(binder_size_t));
                     continue;
                 }
             }
@@ -989,6 +998,7 @@
         if (acquireResult) *acquireResult = err;
         if (reply) reply->setError(err);
         mLastError = err;
+        logExtendedError();
     }
 
     return err;
@@ -1443,17 +1453,30 @@
     return ret;
 }
 
-void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data,
-                                size_t /*dataSize*/,
-                                const binder_size_t* /*objects*/,
-                                size_t /*objectsSize*/)
-{
+void IPCThreadState::logExtendedError() {
+    struct binder_extended_error ee = {.command = BR_OK};
+
+    if (!ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::EXTENDED_ERROR))
+        return;
+
+#if defined(__ANDROID__)
+    if (ioctl(self()->mProcess->mDriverFD, BINDER_GET_EXTENDED_ERROR, &ee) < 0) {
+        ALOGE("Failed to get extended error: %s", strerror(errno));
+        return;
+    }
+#endif
+
+    ALOGE_IF(ee.command != BR_OK, "Binder transaction failure: %d/%d/%d",
+             ee.id, ee.command, ee.param);
+}
+
+void IPCThreadState::freeBuffer(const uint8_t* data, size_t /*dataSize*/,
+                                const binder_size_t* /*objects*/, size_t /*objectsSize*/) {
     //ALOGI("Freeing parcel %p", &parcel);
     IF_LOG_COMMANDS() {
         alog << "Writing BC_FREE_BUFFER for " << data << endl;
     }
     ALOG_ASSERT(data != NULL, "Called with NULL data");
-    if (parcel != nullptr) parcel->closeFileDescriptors();
     IPCThreadState* state = self();
     state->mOut.writeInt32(BC_FREE_BUFFER);
     state->mOut.writePointer((uintptr_t)data);
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index ea2f8d2..c0a8d74 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -21,6 +21,7 @@
 #include <inttypes.h>
 #include <unistd.h>
 
+#include <android-base/properties.h>
 #include <android/os/BnServiceCallback.h>
 #include <android/os/IServiceManager.h>
 #include <binder/IPCThreadState.h>
@@ -99,6 +100,8 @@
 
     status_t unregisterForNotifications(const String16& service,
                                         const sp<AidlRegistrationCallback>& cb) override;
+
+    std::vector<IServiceManager::ServiceDebugInfo> getServiceDebugInfo() override;
     // for legacy ABI
     const String16& getInterfaceDescriptor() const override {
         return mTheRealServiceManager->getInterfaceDescriptor();
@@ -138,6 +141,16 @@
 sp<IServiceManager> defaultServiceManager()
 {
     std::call_once(gSmOnce, []() {
+#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__)
+        /* wait for service manager */ {
+            using std::literals::chrono_literals::operator""s;
+            using android::base::WaitForProperty;
+            while (!WaitForProperty("servicemanager.ready", "true", 1s)) {
+                ALOGE("Waited for servicemanager.ready for a second, waiting another...");
+            }
+        }
+#endif
+
         sp<AidlServiceManager> sm = nullptr;
         while (sm == nullptr) {
             sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));
@@ -165,7 +178,7 @@
     }
 }
 
-#if !defined(__ANDROID_VNDK__) && defined(__ANDROID__)
+#if !defined(__ANDROID_VNDK__)
 // IPermissionController is not accessible to vendors
 
 bool checkCallingPermission(const String16& permission)
@@ -543,6 +556,23 @@
     return OK;
 }
 
+std::vector<IServiceManager::ServiceDebugInfo> ServiceManagerShim::getServiceDebugInfo() {
+    std::vector<os::ServiceDebugInfo> serviceDebugInfos;
+    std::vector<IServiceManager::ServiceDebugInfo> ret;
+    if (Status status = mTheRealServiceManager->getServiceDebugInfo(&serviceDebugInfos);
+        !status.isOk()) {
+        ALOGW("%s Failed to get ServiceDebugInfo", __FUNCTION__);
+        return ret;
+    }
+    for (const auto& serviceDebugInfo : serviceDebugInfos) {
+        IServiceManager::ServiceDebugInfo retInfo;
+        retInfo.pid = serviceDebugInfo.debugPid;
+        retInfo.name = serviceDebugInfo.name;
+        ret.emplace_back(retInfo);
+    }
+    return ret;
+}
+
 #ifndef __ANDROID__
 // ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API.
 // The internal implementation of the AIDL interface android::os::IServiceManager calls into
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index 8132d46..8fe1d2b 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -74,7 +74,7 @@
         fd = memfd_create_region(name ? name : "MemoryHeapBase", size);
         if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
         const int SEAL_FLAGS = ((mFlags & READ_ONLY) ? F_SEAL_FUTURE_WRITE : 0) |
-                ((mFlags & MEMFD_ALLOW_SEALING) ? 0 : F_SEAL_SEAL);
+                ((mFlags & MEMFD_ALLOW_SEALING_FLAG) ? 0 : F_SEAL_SEAL);
         if (SEAL_FLAGS && (fcntl(fd, F_ADD_SEALS, SEAL_FLAGS) == -1)) {
             ALOGE("MemoryHeapBase: MemFD %s sealing with flags %x failed with error  %s", name,
                   SEAL_FLAGS, strerror(errno));
@@ -85,12 +85,9 @@
         }
         return;
 #else
-        mFlags &= ~(FORCE_MEMFD | MEMFD_ALLOW_SEALING);
+        mFlags &= ~(FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG);
 #endif
     }
-    if (mFlags & MEMFD_ALLOW_SEALING) {
-      LOG_ALWAYS_FATAL("Invalid Flags. MEMFD_ALLOW_SEALING only valid with FORCE_MEMFD.");
-    }
     fd = ashmem_create_region(name ? name : "MemoryHeapBase", size);
     ALOGE_IF(fd < 0, "MemoryHeapBase: error creating ashmem region: %s", strerror(errno));
     if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
@@ -103,7 +100,7 @@
     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
       mDevice(nullptr), mNeedUnmap(false), mOffset(0)
 {
-    if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING)) {
+    if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG)) {
         LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
     }
     int open_flags = O_RDWR;
@@ -125,7 +122,7 @@
     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
       mDevice(nullptr), mNeedUnmap(false), mOffset(0)
 {
-    if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING)) {
+    if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG)) {
         LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
     }
     const size_t pagesize = getpagesize();
diff --git a/libs/binder/OS.cpp b/libs/binder/OS.cpp
new file mode 100644
index 0000000..6eb7272
--- /dev/null
+++ b/libs/binder/OS.cpp
@@ -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.
+ */
+
+#include "OS.h"
+
+#include <android-base/file.h>
+#include <string.h>
+
+using android::base::ErrnoError;
+using android::base::Result;
+
+namespace android {
+
+Result<void> setNonBlocking(android::base::borrowed_fd fd) {
+    int flags = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_GETFL));
+    if (flags == -1) {
+        return ErrnoError() << "Could not get flags for fd";
+    }
+    if (int ret = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_SETFL, flags | O_NONBLOCK)); ret == -1) {
+        return ErrnoError() << "Could not set non-blocking flag for fd";
+    }
+    return {};
+}
+
+status_t getRandomBytes(uint8_t* data, size_t size) {
+    int ret = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+    if (ret == -1) {
+        return -errno;
+    }
+
+    base::unique_fd fd(ret);
+    if (!base::ReadFully(fd, data, size)) {
+        return -errno;
+    }
+    return OK;
+}
+
+} // namespace android
diff --git a/libs/binder/OS.h b/libs/binder/OS.h
new file mode 100644
index 0000000..e802e9c
--- /dev/null
+++ b/libs/binder/OS.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <stddef.h>
+#include <cstdint>
+
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+android::base::Result<void> setNonBlocking(android::base::borrowed_fd fd);
+
+status_t getRandomBytes(uint8_t* data, size_t size);
+
+} // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 58b0b35..8b5d118 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -20,15 +20,14 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
-#include <linux/sched.h>
 #include <pthread.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/mman.h>
+#include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <sys/resource.h>
 #include <unistd.h>
 
 #include <binder/Binder.h>
@@ -40,6 +39,7 @@
 #include <binder/Status.h>
 #include <binder/TextOutput.h>
 
+#include <android-base/scopeguard.h>
 #include <cutils/ashmem.h>
 #include <cutils/compiler.h>
 #include <utils/Flattenable.h>
@@ -51,12 +51,27 @@
 #include "RpcState.h"
 #include "Static.h"
 #include "Utils.h"
+
+// A lot of code in this file uses definitions from the
+// Linux kernel header for Binder <linux/android/binder.h>
+// which is included indirectly via "binder_module.h".
+// Non-Linux OSes do not have that header, so libbinder should be
+// built for those targets without kernel binder support, i.e.,
+// without BINDER_WITH_KERNEL_IPC. For this reason, all code in this
+// file that depends on kernel binder, including the header itself,
+// is conditional on BINDER_WITH_KERNEL_IPC.
+#ifdef BINDER_WITH_KERNEL_IPC
+#include <linux/sched.h>
 #include "binder_module.h"
+#else  // BINDER_WITH_KERNEL_IPC
+// Needed by {read,write}Pointer
+typedef uintptr_t binder_uintptr_t;
+#endif // BINDER_WITH_KERNEL_IPC
 
 #define LOG_REFS(...)
-//#define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+// #define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 #define LOG_ALLOC(...)
-//#define LOG_ALLOC(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+// #define LOG_ALLOC(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 
 // ---------------------------------------------------------------------------
 
@@ -87,7 +102,8 @@
 static std::atomic<size_t> gParcelGlobalAllocCount;
 static std::atomic<size_t> gParcelGlobalAllocSize;
 
-static size_t gMaxFds = 0;
+// Maximum number of file descriptors per Parcel.
+constexpr size_t kMaxFds = 1024;
 
 // Maximum size of a blob to transfer in-place.
 static const size_t BLOB_INPLACE_LIMIT = 16 * 1024;
@@ -98,6 +114,7 @@
     BLOB_ASHMEM_MUTABLE = 2,
 };
 
+#ifdef BINDER_WITH_KERNEL_IPC
 static void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj,
                            const void* who) {
     switch (obj.hdr.type) {
@@ -150,6 +167,15 @@
 
     ALOGE("Invalid object type 0x%08x", obj.hdr.type);
 }
+#endif // BINDER_WITH_KERNEL_IPC
+
+static int toRawFd(const std::variant<base::unique_fd, base::borrowed_fd>& v) {
+    return std::visit([](const auto& fd) { return fd.get(); }, v);
+}
+
+Parcel::RpcFields::RpcFields(const sp<RpcSession>& session) : mSession(session) {
+    LOG_ALWAYS_FATAL_IF(mSession == nullptr);
+}
 
 status_t Parcel::finishFlattenBinder(const sp<IBinder>& binder)
 {
@@ -173,22 +199,25 @@
     return OK;
 }
 
+#ifdef BINDER_WITH_KERNEL_IPC
 static constexpr inline int schedPolicyMask(int policy, int priority) {
     return (priority & FLAT_BINDER_FLAG_PRIORITY_MASK) | ((policy & 3) << FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT);
 }
+#endif // BINDER_WITH_KERNEL_IPC
 
 status_t Parcel::flattenBinder(const sp<IBinder>& binder) {
     BBinder* local = nullptr;
     if (binder) local = binder->localBinder();
     if (local) local->setParceled();
 
-    if (isForRpc()) {
+    if (const auto* rpcFields = maybeRpcFields()) {
         if (binder) {
             status_t status = writeInt32(1); // non-null
             if (status != OK) return status;
             uint64_t address;
             // TODO(b/167966510): need to undo this if the Parcel is not sent
-            status = mSession->state()->onBinderLeaving(mSession, binder, &address);
+            status = rpcFields->mSession->state()->onBinderLeaving(rpcFields->mSession, binder,
+                                                                   &address);
             if (status != OK) return status;
             status = writeUint64(address);
             if (status != OK) return status;
@@ -199,6 +228,7 @@
         return finishFlattenBinder(binder);
     }
 
+#ifdef BINDER_WITH_KERNEL_IPC
     flat_binder_object obj;
 
     int schedBits = 0;
@@ -255,13 +285,15 @@
     if (status != OK) return status;
 
     return finishFlattenBinder(binder);
+#else  // BINDER_WITH_KERNEL_IPC
+    LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+    return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
 }
 
 status_t Parcel::unflattenBinder(sp<IBinder>* out) const
 {
-    if (isForRpc()) {
-        LOG_ALWAYS_FATAL_IF(mSession == nullptr, "RpcSession required to read from remote parcel");
-
+    if (const auto* rpcFields = maybeRpcFields()) {
         int32_t isPresent;
         status_t status = readInt32(&isPresent);
         if (status != OK) return status;
@@ -271,10 +303,14 @@
         if (isPresent & 1) {
             uint64_t addr;
             if (status_t status = readUint64(&addr); status != OK) return status;
-            if (status_t status = mSession->state()->onBinderEntering(mSession, addr, &binder);
+            if (status_t status =
+                        rpcFields->mSession->state()->onBinderEntering(rpcFields->mSession, addr,
+                                                                       &binder);
                 status != OK)
                 return status;
-            if (status_t status = mSession->state()->flushExcessBinderRefs(mSession, addr, binder);
+            if (status_t status =
+                        rpcFields->mSession->state()->flushExcessBinderRefs(rpcFields->mSession,
+                                                                            addr, binder);
                 status != OK)
                 return status;
         }
@@ -282,6 +318,7 @@
         return finishUnflattenBinder(binder, out);
     }
 
+#ifdef BINDER_WITH_KERNEL_IPC
     const flat_binder_object* flat = readObject(false);
 
     if (flat) {
@@ -299,6 +336,10 @@
         }
     }
     return BAD_TYPE;
+#else  // BINDER_WITH_KERNEL_IPC
+    LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+    return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
 }
 
 // ---------------------------------------------------------------------------
@@ -378,8 +419,10 @@
     }
 
     mDataPos = pos;
-    mNextObjectHint = 0;
-    mObjectsSorted = false;
+    if (const auto* kernelFields = maybeKernelFields()) {
+        kernelFields->mNextObjectHint = 0;
+        kernelFields->mObjectsSorted = false;
+    }
 }
 
 status_t Parcel::setDataCapacity(size_t size)
@@ -406,25 +449,27 @@
     if (err == NO_ERROR) {
         memcpy(const_cast<uint8_t*>(data()), buffer, len);
         mDataSize = len;
-        mFdsKnown = false;
+        if (auto* kernelFields = maybeKernelFields()) {
+            kernelFields->mFdsKnown = false;
+        }
     }
     return err;
 }
 
-status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len)
-{
-    if (mSession != parcel->mSession) {
+status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) {
+    if (isForRpc() != parcel->isForRpc()) {
         ALOGE("Cannot append Parcel from one context to another. They may be different formats, "
               "and objects are specific to a context.");
         return BAD_TYPE;
     }
+    if (isForRpc() && maybeRpcFields()->mSession != parcel->maybeRpcFields()->mSession) {
+        ALOGE("Cannot append Parcels from different sessions");
+        return BAD_TYPE;
+    }
 
     status_t err;
-    const uint8_t *data = parcel->mData;
-    const binder_size_t *objects = parcel->mObjects;
-    size_t size = parcel->mObjectsSize;
+    const uint8_t* data = parcel->mData;
     int startPos = mDataPos;
-    int firstIndex = -1, lastIndex = -2;
 
     if (len == 0) {
         return NO_ERROR;
@@ -443,18 +488,6 @@
         return BAD_VALUE;
     }
 
-    // Count objects in range
-    for (int i = 0; i < (int) size; i++) {
-        size_t off = objects[i];
-        if ((off >= offset) && (off + sizeof(flat_binder_object) <= offset + len)) {
-            if (firstIndex == -1) {
-                firstIndex = i;
-            }
-            lastIndex = i;
-        }
-    }
-    int numObjects = lastIndex - firstIndex + 1;
-
     if ((mDataSize+len) > mDataCapacity) {
         // grow data
         err = growData(len);
@@ -470,43 +503,125 @@
 
     err = NO_ERROR;
 
-    if (numObjects > 0) {
-        const sp<ProcessState> proc(ProcessState::self());
-        // grow objects
-        if (mObjectsCapacity < mObjectsSize + numObjects) {
-            if ((size_t) numObjects > SIZE_MAX - mObjectsSize) return NO_MEMORY; // overflow
-            if (mObjectsSize + numObjects > SIZE_MAX / 3) return NO_MEMORY; // overflow
-            size_t newSize = ((mObjectsSize + numObjects)*3)/2;
-            if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflow
-            binder_size_t *objects =
-                (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
-            if (objects == (binder_size_t*)nullptr) {
-                return NO_MEMORY;
+    if (auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
+        auto* otherKernelFields = parcel->maybeKernelFields();
+        LOG_ALWAYS_FATAL_IF(otherKernelFields == nullptr);
+
+        const binder_size_t* objects = otherKernelFields->mObjects;
+        size_t size = otherKernelFields->mObjectsSize;
+        // Count objects in range
+        int firstIndex = -1, lastIndex = -2;
+        for (int i = 0; i < (int)size; i++) {
+            size_t off = objects[i];
+            if ((off >= offset) && (off + sizeof(flat_binder_object) <= offset + len)) {
+                if (firstIndex == -1) {
+                    firstIndex = i;
+                }
+                lastIndex = i;
             }
-            mObjects = objects;
-            mObjectsCapacity = newSize;
+        }
+        int numObjects = lastIndex - firstIndex + 1;
+        if (numObjects > 0) {
+            const sp<ProcessState> proc(ProcessState::self());
+            // grow objects
+            if (kernelFields->mObjectsCapacity < kernelFields->mObjectsSize + numObjects) {
+                if ((size_t)numObjects > SIZE_MAX - kernelFields->mObjectsSize)
+                    return NO_MEMORY; // overflow
+                if (kernelFields->mObjectsSize + numObjects > SIZE_MAX / 3)
+                    return NO_MEMORY; // overflow
+                size_t newSize = ((kernelFields->mObjectsSize + numObjects) * 3) / 2;
+                if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflow
+                binder_size_t* objects = (binder_size_t*)realloc(kernelFields->mObjects,
+                                                                 newSize * sizeof(binder_size_t));
+                if (objects == (binder_size_t*)nullptr) {
+                    return NO_MEMORY;
+                }
+                kernelFields->mObjects = objects;
+                kernelFields->mObjectsCapacity = newSize;
+            }
+
+            // append and acquire objects
+            int idx = kernelFields->mObjectsSize;
+            for (int i = firstIndex; i <= lastIndex; i++) {
+                size_t off = objects[i] - offset + startPos;
+                kernelFields->mObjects[idx++] = off;
+                kernelFields->mObjectsSize++;
+
+                flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(mData + off);
+                acquire_object(proc, *flat, this);
+
+                if (flat->hdr.type == BINDER_TYPE_FD) {
+                    // If this is a file descriptor, we need to dup it so the
+                    // new Parcel now owns its own fd, and can declare that we
+                    // officially know we have fds.
+                    flat->handle = fcntl(flat->handle, F_DUPFD_CLOEXEC, 0);
+                    flat->cookie = 1;
+                    kernelFields->mHasFds = kernelFields->mFdsKnown = true;
+                    if (!mAllowFds) {
+                        err = FDS_NOT_ALLOWED;
+                    }
+                }
+            }
+        }
+#else
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
+    } else {
+        auto* rpcFields = maybeRpcFields();
+        LOG_ALWAYS_FATAL_IF(rpcFields == nullptr);
+        auto* otherRpcFields = parcel->maybeRpcFields();
+        if (otherRpcFields == nullptr) {
+            return BAD_TYPE;
+        }
+        if (rpcFields->mSession != otherRpcFields->mSession) {
+            return BAD_TYPE;
         }
 
-        // append and acquire objects
-        int idx = mObjectsSize;
-        for (int i = firstIndex; i <= lastIndex; i++) {
-            size_t off = objects[i] - offset + startPos;
-            mObjects[idx++] = off;
-            mObjectsSize++;
+        const size_t savedDataPos = mDataPos;
+        base::ScopeGuard scopeGuard = [&]() { mDataPos = savedDataPos; };
 
-            flat_binder_object* flat
-                = reinterpret_cast<flat_binder_object*>(mData + off);
-            acquire_object(proc, *flat, this);
+        rpcFields->mObjectPositions.reserve(otherRpcFields->mObjectPositions.size());
+        if (otherRpcFields->mFds != nullptr) {
+            if (rpcFields->mFds == nullptr) {
+                rpcFields->mFds = std::make_unique<decltype(rpcFields->mFds)::element_type>();
+            }
+            rpcFields->mFds->reserve(otherRpcFields->mFds->size());
+        }
+        for (size_t i = 0; i < otherRpcFields->mObjectPositions.size(); i++) {
+            const binder_size_t objPos = otherRpcFields->mObjectPositions[i];
+            if (offset <= objPos && objPos < offset + len) {
+                size_t newDataPos = objPos - offset + startPos;
+                rpcFields->mObjectPositions.push_back(newDataPos);
 
-            if (flat->hdr.type == BINDER_TYPE_FD) {
-                // If this is a file descriptor, we need to dup it so the
-                // new Parcel now owns its own fd, and can declare that we
-                // officially know we have fds.
-                flat->handle = fcntl(flat->handle, F_DUPFD_CLOEXEC, 0);
-                flat->cookie = 1;
-                mHasFds = mFdsKnown = true;
+                mDataPos = newDataPos;
+                int32_t objectType;
+                if (status_t status = readInt32(&objectType); status != OK) {
+                    return status;
+                }
+                if (objectType != RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) {
+                    continue;
+                }
+
                 if (!mAllowFds) {
-                    err = FDS_NOT_ALLOWED;
+                    return FDS_NOT_ALLOWED;
+                }
+
+                // Read FD, duplicate, and add to list.
+                int32_t fdIndex;
+                if (status_t status = readInt32(&fdIndex); status != OK) {
+                    return status;
+                }
+                const auto& oldFd = 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)));
+                // Fixup the index in the data.
+                mDataPos = newDataPos + 4;
+                if (status_t status = writeInt32(rpcFields->mFds->size() - 1); status != OK) {
+                    return status;
                 }
             }
         }
@@ -563,18 +678,28 @@
 
 bool Parcel::hasFileDescriptors() const
 {
-    if (!mFdsKnown) {
+    if (const auto* rpcFields = maybeRpcFields()) {
+        return rpcFields->mFds != nullptr && !rpcFields->mFds->empty();
+    }
+    auto* kernelFields = maybeKernelFields();
+    if (!kernelFields->mFdsKnown) {
         scanForFds();
     }
-    return mHasFds;
+    return kernelFields->mHasFds;
 }
 
 std::vector<sp<IBinder>> Parcel::debugReadAllStrongBinders() const {
     std::vector<sp<IBinder>> ret;
 
+#ifdef BINDER_WITH_KERNEL_IPC
+    const auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return ret;
+    }
+
     size_t initPosition = dataPosition();
-    for (size_t i = 0; i < mObjectsSize; i++) {
-        binder_size_t offset = mObjects[i];
+    for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
+        binder_size_t offset = kernelFields->mObjects[i];
         const flat_binder_object* flat =
                 reinterpret_cast<const flat_binder_object*>(mData + offset);
         if (flat->hdr.type != BINDER_TYPE_BINDER) continue;
@@ -586,27 +711,39 @@
     }
 
     setDataPosition(initPosition);
+#endif // BINDER_WITH_KERNEL_IPC
+
     return ret;
 }
 
 std::vector<int> Parcel::debugReadAllFileDescriptors() const {
     std::vector<int> ret;
 
-    size_t initPosition = dataPosition();
-    for (size_t i = 0; i < mObjectsSize; i++) {
-        binder_size_t offset = mObjects[i];
-        const flat_binder_object* flat =
-                reinterpret_cast<const flat_binder_object*>(mData + offset);
-        if (flat->hdr.type != BINDER_TYPE_FD) continue;
+    if (const auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
+        size_t initPosition = dataPosition();
+        for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
+            binder_size_t offset = kernelFields->mObjects[i];
+            const flat_binder_object* flat =
+                    reinterpret_cast<const flat_binder_object*>(mData + offset);
+            if (flat->hdr.type != BINDER_TYPE_FD) continue;
 
-        setDataPosition(offset);
+            setDataPosition(offset);
 
-        int fd = readFileDescriptor();
-        LOG_ALWAYS_FATAL_IF(fd == -1);
-        ret.push_back(fd);
+            int fd = readFileDescriptor();
+            LOG_ALWAYS_FATAL_IF(fd == -1);
+            ret.push_back(fd);
+        }
+        setDataPosition(initPosition);
+#else
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+#endif
+    } else if (const auto* rpcFields = maybeRpcFields(); rpcFields && rpcFields->mFds) {
+        for (const auto& fd : *rpcFields->mFds) {
+            ret.push_back(toRawFd(fd));
+        }
     }
 
-    setDataPosition(initPosition);
     return ret;
 }
 
@@ -621,17 +758,38 @@
         return BAD_VALUE;
     }
     *result = false;
-    for (size_t i = 0; i < mObjectsSize; i++) {
-        size_t pos = mObjects[i];
-        if (pos < offset) continue;
-        if (pos + sizeof(flat_binder_object) > offset + len) {
-          if (mObjectsSorted) break;
-          else continue;
+    if (const auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
+        for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
+            size_t pos = kernelFields->mObjects[i];
+            if (pos < offset) continue;
+            if (pos + sizeof(flat_binder_object) > offset + len) {
+                if (kernelFields->mObjectsSorted) {
+                    break;
+                } else {
+                    continue;
+                }
+            }
+            const flat_binder_object* flat =
+                    reinterpret_cast<const flat_binder_object*>(mData + pos);
+            if (flat->hdr.type == BINDER_TYPE_FD) {
+                *result = true;
+                break;
+            }
         }
-        const flat_binder_object* flat = reinterpret_cast<const flat_binder_object*>(mData + pos);
-        if (flat->hdr.type == BINDER_TYPE_FD) {
-            *result = true;
-            break;
+#else
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
+    } else if (const auto* rpcFields = maybeRpcFields()) {
+        for (uint32_t pos : rpcFields->mObjectPositions) {
+            if (offset <= pos && pos < limit) {
+                const auto* type = reinterpret_cast<const RpcFields::ObjectType*>(mData + pos);
+                if (*type == RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) {
+                    *result = true;
+                    break;
+                }
+            }
         }
     }
     return NO_ERROR;
@@ -654,23 +812,28 @@
     LOG_ALWAYS_FATAL_IF(mData != nullptr && mOwner == nullptr,
                         "format must be set before data is written OR on IPC data");
 
-    LOG_ALWAYS_FATAL_IF(session == nullptr, "markForRpc requires session");
-    mSession = session;
+    mVariantFields.emplace<RpcFields>(session);
 }
 
 bool Parcel::isForRpc() const {
-    return mSession != nullptr;
+    return std::holds_alternative<RpcFields>(mVariantFields);
 }
 
 void Parcel::updateWorkSourceRequestHeaderPosition() const {
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return;
+    }
+
     // Only update the request headers once. We only want to point
     // to the first headers read/written.
-    if (!mRequestHeaderPresent) {
-        mWorkSourceRequestHeaderPosition = dataPosition();
-        mRequestHeaderPresent = true;
+    if (!kernelFields->mRequestHeaderPresent) {
+        kernelFields->mWorkSourceRequestHeaderPosition = dataPosition();
+        kernelFields->mRequestHeaderPresent = true;
     }
 }
 
+#ifdef BINDER_WITH_KERNEL_IPC
 #if defined(__ANDROID_VNDK__)
 constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
 #elif defined(__ANDROID_RECOVERY__)
@@ -678,6 +841,7 @@
 #else
 constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
 #endif
+#endif // BINDER_WITH_KERNEL_IPC
 
 // Write RPC headers.  (previously just the interface token)
 status_t Parcel::writeInterfaceToken(const String16& interface)
@@ -686,13 +850,18 @@
 }
 
 status_t Parcel::writeInterfaceToken(const char16_t* str, size_t len) {
-    if (CC_LIKELY(!isForRpc())) {
+    if (auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
         const IPCThreadState* threadState = IPCThreadState::self();
         writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
         updateWorkSourceRequestHeaderPosition();
         writeInt32(threadState->shouldPropagateWorkSource() ? threadState->getCallingWorkSourceUid()
                                                             : IPCThreadState::kUnsetWorkSource);
         writeInt32(kHeader);
+#else  // BINDER_WITH_KERNEL_IPC
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
     }
 
     // currently the interface identification token is just its name as a string
@@ -701,12 +870,16 @@
 
 bool Parcel::replaceCallingWorkSourceUid(uid_t uid)
 {
-    if (!mRequestHeaderPresent) {
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return false;
+    }
+    if (!kernelFields->mRequestHeaderPresent) {
         return false;
     }
 
     const size_t initialPosition = dataPosition();
-    setDataPosition(mWorkSourceRequestHeaderPosition);
+    setDataPosition(kernelFields->mWorkSourceRequestHeaderPosition);
     status_t err = writeInt32(uid);
     setDataPosition(initialPosition);
     return err == NO_ERROR;
@@ -714,12 +887,16 @@
 
 uid_t Parcel::readCallingWorkSourceUid() const
 {
-    if (!mRequestHeaderPresent) {
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return false;
+    }
+    if (!kernelFields->mRequestHeaderPresent) {
         return IPCThreadState::kUnsetWorkSource;
     }
 
     const size_t initialPosition = dataPosition();
-    setDataPosition(mWorkSourceRequestHeaderPosition);
+    setDataPosition(kernelFields->mWorkSourceRequestHeaderPosition);
     uid_t uid = readInt32();
     setDataPosition(initialPosition);
     return uid;
@@ -740,7 +917,8 @@
                               size_t len,
                               IPCThreadState* threadState) const
 {
-    if (CC_LIKELY(!isForRpc())) {
+    if (auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
         // StrictModePolicy.
         int32_t strictPolicy = readInt32();
         if (threadState == nullptr) {
@@ -766,6 +944,11 @@
                   header);
             return false;
         }
+#else  // BINDER_WITH_KERNEL_IPC
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        (void)threadState;
+        return false;
+#endif // BINDER_WITH_KERNEL_IPC
     }
 
     // Interface descriptor.
@@ -795,7 +978,10 @@
 
 size_t Parcel::objectsCount() const
 {
-    return mObjectsSize;
+    if (const auto* kernelFields = maybeKernelFields()) {
+        return kernelFields->mObjectsSize;
+    }
+    return 0;
 }
 
 status_t Parcel::errorCheck() const
@@ -1237,13 +1423,43 @@
     return err;
 }
 
-status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership)
-{
-    if (isForRpc()) {
-        ALOGE("Cannot write file descriptor to remote binder.");
-        return BAD_TYPE;
+status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership) {
+    if (auto* rpcFields = maybeRpcFields()) {
+        std::variant<base::unique_fd, base::borrowed_fd> fdVariant;
+        if (takeOwnership) {
+            fdVariant = base::unique_fd(fd);
+        } else {
+            fdVariant = base::borrowed_fd(fd);
+        }
+        if (!mAllowFds) {
+            return FDS_NOT_ALLOWED;
+        }
+        switch (rpcFields->mSession->getFileDescriptorTransportMode()) {
+            case RpcSession::FileDescriptorTransportMode::NONE: {
+                return FDS_NOT_ALLOWED;
+            }
+            case RpcSession::FileDescriptorTransportMode::UNIX: {
+                if (rpcFields->mFds == nullptr) {
+                    rpcFields->mFds = std::make_unique<decltype(rpcFields->mFds)::element_type>();
+                }
+                size_t dataPos = mDataPos;
+                if (dataPos > UINT32_MAX) {
+                    return NO_MEMORY;
+                }
+                if (status_t err = writeInt32(RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR); err != OK) {
+                    return err;
+                }
+                if (status_t err = writeInt32(rpcFields->mFds->size()); err != OK) {
+                    return err;
+                }
+                rpcFields->mObjectPositions.push_back(dataPos);
+                rpcFields->mFds->push_back(std::move(fdVariant));
+                return OK;
+            }
+        }
     }
 
+#ifdef BINDER_WITH_KERNEL_IPC
     flat_binder_object obj;
     obj.hdr.type = BINDER_TYPE_FD;
     obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
@@ -1251,6 +1467,12 @@
     obj.handle = fd;
     obj.cookie = takeOwnership ? 1 : 0;
     return writeObject(obj, true);
+#else  // BINDER_WITH_KERNEL_IPC
+    LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+    (void)fd;
+    (void)takeOwnership;
+    return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
 }
 
 status_t Parcel::writeDupFileDescriptor(int fd)
@@ -1361,7 +1583,7 @@
     const size_t len = val.getFlattenedSize();
     const size_t fd_count = val.getFdCount();
 
-    if ((len > INT32_MAX) || (fd_count >= gMaxFds)) {
+    if ((len > INT32_MAX) || (fd_count > kMaxFds)) {
         // don't accept size_t values which may have come from an
         // inadvertent conversion from a negative int.
         return BAD_VALUE;
@@ -1401,8 +1623,12 @@
 
 status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
 {
+    auto* kernelFields = maybeKernelFields();
+    LOG_ALWAYS_FATAL_IF(kernelFields == nullptr, "Can't write flat_binder_object to RPC Parcel");
+
+#ifdef BINDER_WITH_KERNEL_IPC
     const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
-    const bool enoughObjects = mObjectsSize < mObjectsCapacity;
+    const bool enoughObjects = kernelFields->mObjectsSize < kernelFields->mObjectsCapacity;
     if (enoughData && enoughObjects) {
 restart_write:
         *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
@@ -1413,14 +1639,14 @@
                 // fail before modifying our object index
                 return FDS_NOT_ALLOWED;
             }
-            mHasFds = mFdsKnown = true;
+            kernelFields->mHasFds = kernelFields->mFdsKnown = true;
         }
 
         // Need to write meta-data?
         if (nullMetaData || val.binder != 0) {
-            mObjects[mObjectsSize] = mDataPos;
+            kernelFields->mObjects[kernelFields->mObjectsSize] = mDataPos;
             acquire_object(ProcessState::self(), val, this);
-            mObjectsSize++;
+            kernelFields->mObjectsSize++;
         }
 
         return finishWrite(sizeof(flat_binder_object));
@@ -1431,17 +1657,24 @@
         if (err != NO_ERROR) return err;
     }
     if (!enoughObjects) {
-        if (mObjectsSize > SIZE_MAX - 2) return NO_MEMORY; // overflow
-        if ((mObjectsSize + 2) > SIZE_MAX / 3) return NO_MEMORY; // overflow
-        size_t newSize = ((mObjectsSize+2)*3)/2;
+        if (kernelFields->mObjectsSize > SIZE_MAX - 2) return NO_MEMORY;       // overflow
+        if ((kernelFields->mObjectsSize + 2) > SIZE_MAX / 3) return NO_MEMORY; // overflow
+        size_t newSize = ((kernelFields->mObjectsSize + 2) * 3) / 2;
         if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflow
-        binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
+        binder_size_t* objects =
+                (binder_size_t*)realloc(kernelFields->mObjects, newSize * sizeof(binder_size_t));
         if (objects == nullptr) return NO_MEMORY;
-        mObjects = objects;
-        mObjectsCapacity = newSize;
+        kernelFields->mObjects = objects;
+        kernelFields->mObjectsCapacity = newSize;
     }
 
     goto restart_write;
+#else  // BINDER_WITH_KERNEL_IPC
+    LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+    (void)val;
+    (void)nullMetaData;
+    return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
 }
 
 status_t Parcel::writeNoException()
@@ -1452,55 +1685,70 @@
 
 status_t Parcel::validateReadData(size_t upperBound) const
 {
+    const auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        // Can't validate RPC Parcel reads because the location of binder
+        // objects is unknown.
+        return OK;
+    }
+
+#ifdef BINDER_WITH_KERNEL_IPC
     // Don't allow non-object reads on object data
-    if (mObjectsSorted || mObjectsSize <= 1) {
-data_sorted:
+    if (kernelFields->mObjectsSorted || kernelFields->mObjectsSize <= 1) {
+    data_sorted:
         // Expect to check only against the next object
-        if (mNextObjectHint < mObjectsSize && upperBound > mObjects[mNextObjectHint]) {
+        if (kernelFields->mNextObjectHint < kernelFields->mObjectsSize &&
+            upperBound > kernelFields->mObjects[kernelFields->mNextObjectHint]) {
             // For some reason the current read position is greater than the next object
             // hint. Iterate until we find the right object
-            size_t nextObject = mNextObjectHint;
+            size_t nextObject = kernelFields->mNextObjectHint;
             do {
-                if (mDataPos < mObjects[nextObject] + sizeof(flat_binder_object)) {
+                if (mDataPos < kernelFields->mObjects[nextObject] + sizeof(flat_binder_object)) {
                     // Requested info overlaps with an object
                     ALOGE("Attempt to read from protected data in Parcel %p", this);
                     return PERMISSION_DENIED;
                 }
                 nextObject++;
-            } while (nextObject < mObjectsSize && upperBound > mObjects[nextObject]);
-            mNextObjectHint = nextObject;
+            } while (nextObject < kernelFields->mObjectsSize &&
+                     upperBound > kernelFields->mObjects[nextObject]);
+            kernelFields->mNextObjectHint = nextObject;
         }
         return NO_ERROR;
     }
     // Quickly determine if mObjects is sorted.
-    binder_size_t* currObj = mObjects + mObjectsSize - 1;
+    binder_size_t* currObj = kernelFields->mObjects + kernelFields->mObjectsSize - 1;
     binder_size_t* prevObj = currObj;
-    while (currObj > mObjects) {
+    while (currObj > kernelFields->mObjects) {
         prevObj--;
         if(*prevObj > *currObj) {
             goto data_unsorted;
         }
         currObj--;
     }
-    mObjectsSorted = true;
+    kernelFields->mObjectsSorted = true;
     goto data_sorted;
 
 data_unsorted:
     // Insertion Sort mObjects
     // Great for mostly sorted lists. If randomly sorted or reverse ordered mObjects become common,
     // switch to std::sort(mObjects, mObjects + mObjectsSize);
-    for (binder_size_t* iter0 = mObjects + 1; iter0 < mObjects + mObjectsSize; iter0++) {
+    for (binder_size_t* iter0 = kernelFields->mObjects + 1;
+         iter0 < kernelFields->mObjects + kernelFields->mObjectsSize; iter0++) {
         binder_size_t temp = *iter0;
         binder_size_t* iter1 = iter0 - 1;
-        while (iter1 >= mObjects && *iter1 > temp) {
+        while (iter1 >= kernelFields->mObjects && *iter1 > temp) {
             *(iter1 + 1) = *iter1;
             iter1--;
         }
         *(iter1 + 1) = temp;
     }
-    mNextObjectHint = 0;
-    mObjectsSorted = true;
+    kernelFields->mNextObjectHint = 0;
+    kernelFields->mObjectsSorted = true;
     goto data_sorted;
+#else  // BINDER_WITH_KERNEL_IPC
+    (void)upperBound;
+    return NO_ERROR;
+#endif // BINDER_WITH_KERNEL_IPC
 }
 
 status_t Parcel::read(void* outData, size_t len) const
@@ -1513,7 +1761,8 @@
 
     if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
             && len <= pad_size(len)) {
-        if (mObjectsSize > 0) {
+        const auto* kernelFields = maybeKernelFields();
+        if (kernelFields != nullptr && kernelFields->mObjectsSize > 0) {
             status_t err = validateReadData(mDataPos + pad_size(len));
             if(err != NO_ERROR) {
                 // Still increment the data position by the expected length
@@ -1540,7 +1789,8 @@
 
     if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
             && len <= pad_size(len)) {
-        if (mObjectsSize > 0) {
+        const auto* kernelFields = maybeKernelFields();
+        if (kernelFields != nullptr && kernelFields->mObjectsSize > 0) {
             status_t err = validateReadData(mDataPos + pad_size(len));
             if(err != NO_ERROR) {
                 // Still increment the data position by the expected length
@@ -1587,7 +1837,8 @@
     static_assert(std::is_trivially_copyable_v<T>);
 
     if ((mDataPos+sizeof(T)) <= mDataSize) {
-        if (mObjectsSize > 0) {
+        const auto* kernelFields = maybeKernelFields();
+        if (kernelFields != nullptr && kernelFields->mObjectsSize > 0) {
             status_t err = validateReadData(mDataPos + sizeof(T));
             if(err != NO_ERROR) {
                 // Still increment the data position by the expected length
@@ -1965,8 +2216,32 @@
     return h;
 }
 
-int Parcel::readFileDescriptor() const
-{
+int Parcel::readFileDescriptor() const {
+    if (const auto* rpcFields = maybeRpcFields()) {
+        if (!std::binary_search(rpcFields->mObjectPositions.begin(),
+                                rpcFields->mObjectPositions.end(), mDataPos)) {
+            ALOGW("Attempt to read file descriptor from Parcel %p at offset %zu that is not in the "
+                  "object list",
+                  this, mDataPos);
+            return BAD_TYPE;
+        }
+
+        int32_t objectType = readInt32();
+        if (objectType != RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) {
+            return BAD_TYPE;
+        }
+
+        int32_t fdIndex = readInt32();
+        if (rpcFields->mFds == nullptr || fdIndex < 0 ||
+            static_cast<size_t>(fdIndex) >= rpcFields->mFds->size()) {
+            ALOGE("RPC Parcel contains invalid file descriptor index. index=%d fd_count=%zu",
+                  fdIndex, rpcFields->mFds ? rpcFields->mFds->size() : 0);
+            return BAD_VALUE;
+        }
+        return toRawFd(rpcFields->mFds->at(fdIndex));
+    }
+
+#ifdef BINDER_WITH_KERNEL_IPC
     const flat_binder_object* flat = readObject(true);
 
     if (flat && flat->hdr.type == BINDER_TYPE_FD) {
@@ -1974,10 +2249,13 @@
     }
 
     return BAD_TYPE;
+#else  // BINDER_WITH_KERNEL_IPC
+    LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+    return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
 }
 
-int Parcel::readParcelFileDescriptor() const
-{
+int Parcel::readParcelFileDescriptor() const {
     int32_t hasComm = readInt32();
     int fd = readFileDescriptor();
     if (hasComm != 0) {
@@ -2086,7 +2364,7 @@
     const size_t len = this->readInt32();
     const size_t fd_count = this->readInt32();
 
-    if ((len > INT32_MAX) || (fd_count >= gMaxFds)) {
+    if ((len > INT32_MAX) || (fd_count > kMaxFds)) {
         // don't accept size_t values which may have come from an
         // inadvertent conversion from a negative int.
         return BAD_VALUE;
@@ -2130,8 +2408,15 @@
 
     return err;
 }
+
+#ifdef BINDER_WITH_KERNEL_IPC
 const flat_binder_object* Parcel::readObject(bool nullMetaData) const
 {
+    const auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return nullptr;
+    }
+
     const size_t DPOS = mDataPos;
     if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) {
         const flat_binder_object* obj
@@ -2146,9 +2431,9 @@
         }
 
         // Ensure that this object is valid...
-        binder_size_t* const OBJS = mObjects;
-        const size_t N = mObjectsSize;
-        size_t opos = mNextObjectHint;
+        binder_size_t* const OBJS = kernelFields->mObjects;
+        const size_t N = kernelFields->mObjectsSize;
+        size_t opos = kernelFields->mNextObjectHint;
 
         if (N > 0) {
             ALOGV("Parcel %p looking for obj at %zu, hint=%zu",
@@ -2167,7 +2452,7 @@
                 // Found it!
                 ALOGV("Parcel %p found obj %zu at index %zu with forward search",
                      this, DPOS, opos);
-                mNextObjectHint = opos+1;
+                kernelFields->mNextObjectHint = opos + 1;
                 ALOGV("readObject Setting data pos of %p to %zu", this, mDataPos);
                 return obj;
             }
@@ -2180,7 +2465,7 @@
                 // Found it!
                 ALOGV("Parcel %p found obj %zu at index %zu with backward search",
                      this, DPOS, opos);
-                mNextObjectHint = opos+1;
+                kernelFields->mNextObjectHint = opos + 1;
                 ALOGV("readObject Setting data pos of %p to %zu", this, mDataPos);
                 return obj;
             }
@@ -2190,21 +2475,29 @@
     }
     return nullptr;
 }
+#endif // BINDER_WITH_KERNEL_IPC
 
-void Parcel::closeFileDescriptors()
-{
-    size_t i = mObjectsSize;
-    if (i > 0) {
-        //ALOGI("Closing file descriptors for %zu objects...", i);
-    }
-    while (i > 0) {
-        i--;
-        const flat_binder_object* flat
-            = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
-        if (flat->hdr.type == BINDER_TYPE_FD) {
-            //ALOGI("Closing fd: %ld", flat->handle);
-            close(flat->handle);
+void Parcel::closeFileDescriptors() {
+    if (auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
+        size_t i = kernelFields->mObjectsSize;
+        if (i > 0) {
+            // ALOGI("Closing file descriptors for %zu objects...", i);
         }
+        while (i > 0) {
+            i--;
+            const flat_binder_object* flat =
+                    reinterpret_cast<flat_binder_object*>(mData + kernelFields->mObjects[i]);
+            if (flat->hdr.type == BINDER_TYPE_FD) {
+                // ALOGI("Closing fd: %ld", flat->handle);
+                close(flat->handle);
+            }
+        }
+#else  // BINDER_WITH_KERNEL_IPC
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+#endif // BINDER_WITH_KERNEL_IPC
+    } else if (auto* rpcFields = maybeRpcFields()) {
+        rpcFields->mFds.reset();
     }
 }
 
@@ -2220,35 +2513,44 @@
 
 uintptr_t Parcel::ipcObjects() const
 {
-    return reinterpret_cast<uintptr_t>(mObjects);
+    if (const auto* kernelFields = maybeKernelFields()) {
+        return reinterpret_cast<uintptr_t>(kernelFields->mObjects);
+    }
+    return 0;
 }
 
 size_t Parcel::ipcObjectsCount() const
 {
-    return mObjectsSize;
+    if (const auto* kernelFields = maybeKernelFields()) {
+        return kernelFields->mObjectsSize;
+    }
+    return 0;
 }
 
-void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
-    const binder_size_t* objects, size_t objectsCount, release_func relFunc)
-{
+void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
+                                 size_t objectsCount, release_func relFunc) {
     // this code uses 'mOwner == nullptr' to understand whether it owns memory
     LOG_ALWAYS_FATAL_IF(relFunc == nullptr, "must provide cleanup function");
 
     freeData();
 
+    auto* kernelFields = maybeKernelFields();
+    LOG_ALWAYS_FATAL_IF(kernelFields == nullptr); // guaranteed by freeData.
+
     mData = const_cast<uint8_t*>(data);
     mDataSize = mDataCapacity = dataSize;
-    mObjects = const_cast<binder_size_t*>(objects);
-    mObjectsSize = mObjectsCapacity = objectsCount;
+    kernelFields->mObjects = const_cast<binder_size_t*>(objects);
+    kernelFields->mObjectsSize = kernelFields->mObjectsCapacity = objectsCount;
     mOwner = relFunc;
 
+#ifdef BINDER_WITH_KERNEL_IPC
     binder_size_t minOffset = 0;
-    for (size_t i = 0; i < mObjectsSize; i++) {
-        binder_size_t offset = mObjects[i];
+    for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
+        binder_size_t offset = kernelFields->mObjects[i];
         if (offset < minOffset) {
             ALOGE("%s: bad object offset %" PRIu64 " < %" PRIu64 "\n",
                   __func__, (uint64_t)offset, (uint64_t)minOffset);
-            mObjectsSize = 0;
+            kernelFields->mObjectsSize = 0;
             break;
         }
         const flat_binder_object* flat
@@ -2266,12 +2568,64 @@
 
             // WARNING: callers of ipcSetDataReference need to make sure they
             // don't rely on mObjectsSize in their release_func.
-            mObjectsSize = 0;
+            kernelFields->mObjectsSize = 0;
             break;
         }
         minOffset = offset + sizeof(flat_binder_object);
     }
     scanForFds();
+#else  // BINDER_WITH_KERNEL_IPC
+    LOG_ALWAYS_FATAL_IF(objectsCount != 0,
+                        "Non-zero objects count passed to Parcel with kernel driver disabled");
+#endif // BINDER_WITH_KERNEL_IPC
+}
+
+status_t Parcel::rpcSetDataReference(
+        const sp<RpcSession>& session, const uint8_t* data, size_t dataSize,
+        const uint32_t* objectTable, size_t objectTableSize,
+        std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds,
+        release_func relFunc) {
+    // this code uses 'mOwner == nullptr' to understand whether it owns memory
+    LOG_ALWAYS_FATAL_IF(relFunc == nullptr, "must provide cleanup function");
+
+    LOG_ALWAYS_FATAL_IF(session == nullptr);
+
+    if (objectTableSize != ancillaryFds.size()) {
+        ALOGE("objectTableSize=%zu ancillaryFds.size=%zu", objectTableSize, ancillaryFds.size());
+        relFunc(data, dataSize, nullptr, 0);
+        return BAD_VALUE;
+    }
+    for (size_t i = 0; i < objectTableSize; i++) {
+        uint32_t minObjectEnd;
+        if (__builtin_add_overflow(objectTable[i], sizeof(RpcFields::ObjectType), &minObjectEnd) ||
+            minObjectEnd >= dataSize) {
+            ALOGE("received out of range object position: %" PRIu32 " (parcel size is %zu)",
+                  objectTable[i], dataSize);
+            relFunc(data, dataSize, nullptr, 0);
+            return BAD_VALUE;
+        }
+    }
+
+    freeData();
+    markForRpc(session);
+
+    auto* rpcFields = maybeRpcFields();
+    LOG_ALWAYS_FATAL_IF(rpcFields == nullptr); // guaranteed by markForRpc.
+
+    mData = const_cast<uint8_t*>(data);
+    mDataSize = mDataCapacity = dataSize;
+    mOwner = relFunc;
+
+    rpcFields->mObjectPositions.reserve(objectTableSize);
+    for (size_t i = 0; i < objectTableSize; i++) {
+        rpcFields->mObjectPositions.push_back(objectTable[i]);
+    }
+    if (!ancillaryFds.empty()) {
+        rpcFields->mFds = std::make_unique<decltype(rpcFields->mFds)::element_type>();
+        *rpcFields->mFds = std::move(ancillaryFds);
+    }
+
+    return OK;
 }
 
 void Parcel::print(TextOutput& to, uint32_t /*flags*/) const
@@ -2284,15 +2638,19 @@
     } else if (dataSize() > 0) {
         const uint8_t* DATA = data();
         to << indent << HexDump(DATA, dataSize()) << dedent;
-        const binder_size_t* OBJS = mObjects;
-        const size_t N = objectsCount();
-        for (size_t i=0; i<N; i++) {
-            const flat_binder_object* flat
-                = reinterpret_cast<const flat_binder_object*>(DATA+OBJS[i]);
-            to << endl << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
-                << TypeCode(flat->hdr.type & 0x7f7f7f00)
-                << " = " << flat->binder;
+#ifdef BINDER_WITH_KERNEL_IPC
+        if (const auto* kernelFields = maybeKernelFields()) {
+            const binder_size_t* OBJS = kernelFields->mObjects;
+            const size_t N = objectsCount();
+            for (size_t i = 0; i < N; i++) {
+                const flat_binder_object* flat =
+                        reinterpret_cast<const flat_binder_object*>(DATA + OBJS[i]);
+                to << endl
+                   << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
+                   << TypeCode(flat->hdr.type & 0x7f7f7f00) << " = " << flat->binder;
+            }
         }
+#endif // BINDER_WITH_KERNEL_IPC
     } else {
         to << "NULL";
     }
@@ -2302,36 +2660,48 @@
 
 void Parcel::releaseObjects()
 {
-    size_t i = mObjectsSize;
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return;
+    }
+
+#ifdef BINDER_WITH_KERNEL_IPC
+    size_t i = kernelFields->mObjectsSize;
     if (i == 0) {
         return;
     }
     sp<ProcessState> proc(ProcessState::self());
     uint8_t* const data = mData;
-    binder_size_t* const objects = mObjects;
+    binder_size_t* const objects = kernelFields->mObjects;
     while (i > 0) {
         i--;
-        const flat_binder_object* flat
-            = reinterpret_cast<flat_binder_object*>(data+objects[i]);
+        const flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(data + objects[i]);
         release_object(proc, *flat, this);
     }
+#endif // BINDER_WITH_KERNEL_IPC
 }
 
 void Parcel::acquireObjects()
 {
-    size_t i = mObjectsSize;
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return;
+    }
+
+#ifdef BINDER_WITH_KERNEL_IPC
+    size_t i = kernelFields->mObjectsSize;
     if (i == 0) {
         return;
     }
     const sp<ProcessState> proc(ProcessState::self());
     uint8_t* const data = mData;
-    binder_size_t* const objects = mObjects;
+    binder_size_t* const objects = kernelFields->mObjects;
     while (i > 0) {
         i--;
-        const flat_binder_object* flat
-            = reinterpret_cast<flat_binder_object*>(data+objects[i]);
+        const flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(data + objects[i]);
         acquire_object(proc, *flat, this);
     }
+#endif // BINDER_WITH_KERNEL_IPC
 }
 
 void Parcel::freeData()
@@ -2345,7 +2715,11 @@
     if (mOwner) {
         LOG_ALLOC("Parcel %p: freeing other owner data", this);
         //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
-        mOwner(this, mData, mDataSize, mObjects, mObjectsSize);
+        auto* kernelFields = maybeKernelFields();
+        // Close FDs before freeing, otherwise they will leak for kernel binder.
+        closeFileDescriptors();
+        mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
+               kernelFields ? kernelFields->mObjectsSize : 0);
     } else {
         LOG_ALLOC("Parcel %p: freeing allocated data", this);
         releaseObjects();
@@ -2358,7 +2732,8 @@
             }
             free(mData);
         }
-        if (mObjects) free(mObjects);
+        auto* kernelFields = maybeKernelFields();
+        if (kernelFields && kernelFields->mObjects) free(kernelFields->mObjects);
     }
 }
 
@@ -2433,13 +2808,18 @@
     ALOGV("restartWrite Setting data size of %p to %zu", this, mDataSize);
     ALOGV("restartWrite Setting data pos of %p to %zu", this, mDataPos);
 
-    free(mObjects);
-    mObjects = nullptr;
-    mObjectsSize = mObjectsCapacity = 0;
-    mNextObjectHint = 0;
-    mObjectsSorted = false;
-    mHasFds = false;
-    mFdsKnown = true;
+    if (auto* kernelFields = maybeKernelFields()) {
+        free(kernelFields->mObjects);
+        kernelFields->mObjects = nullptr;
+        kernelFields->mObjectsSize = kernelFields->mObjectsCapacity = 0;
+        kernelFields->mNextObjectHint = 0;
+        kernelFields->mObjectsSorted = false;
+        kernelFields->mHasFds = false;
+        kernelFields->mFdsKnown = true;
+    } else if (auto* rpcFields = maybeRpcFields()) {
+        rpcFields->mObjectPositions.clear();
+        rpcFields->mFds.reset();
+    }
     mAllowFds = true;
 
     return NO_ERROR;
@@ -2453,17 +2833,27 @@
         return BAD_VALUE;
     }
 
+    auto* kernelFields = maybeKernelFields();
+    auto* rpcFields = maybeRpcFields();
+
     // If shrinking, first adjust for any objects that appear
     // after the new data size.
-    size_t objectsSize = mObjectsSize;
+    size_t objectsSize =
+            kernelFields ? kernelFields->mObjectsSize : rpcFields->mObjectPositions.size();
     if (desired < mDataSize) {
         if (desired == 0) {
             objectsSize = 0;
         } else {
-            while (objectsSize > 0) {
-                if (mObjects[objectsSize-1] < desired)
-                    break;
-                objectsSize--;
+            if (kernelFields) {
+                while (objectsSize > 0) {
+                    if (kernelFields->mObjects[objectsSize - 1] < desired) break;
+                    objectsSize--;
+                }
+            } else {
+                while (objectsSize > 0) {
+                    if (rpcFields->mObjectPositions[objectsSize - 1] < desired) break;
+                    objectsSize--;
+                }
             }
         }
     }
@@ -2484,7 +2874,7 @@
         }
         binder_size_t* objects = nullptr;
 
-        if (objectsSize) {
+        if (kernelFields && objectsSize) {
             objects = (binder_size_t*)calloc(objectsSize, sizeof(binder_size_t));
             if (!objects) {
                 free(data);
@@ -2495,20 +2885,32 @@
 
             // Little hack to only acquire references on objects
             // we will be keeping.
-            size_t oldObjectsSize = mObjectsSize;
-            mObjectsSize = objectsSize;
+            size_t oldObjectsSize = kernelFields->mObjectsSize;
+            kernelFields->mObjectsSize = objectsSize;
             acquireObjects();
-            mObjectsSize = oldObjectsSize;
+            kernelFields->mObjectsSize = oldObjectsSize;
+        }
+        if (rpcFields) {
+            if (status_t status = truncateRpcObjects(objectsSize); status != OK) {
+                free(data);
+                return status;
+            }
         }
 
         if (mData) {
             memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
         }
-        if (objects && mObjects) {
-            memcpy(objects, mObjects, objectsSize*sizeof(binder_size_t));
+        if (objects && kernelFields && kernelFields->mObjects) {
+            memcpy(objects, kernelFields->mObjects, objectsSize * sizeof(binder_size_t));
         }
-        //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
-        mOwner(this, mData, mDataSize, mObjects, mObjectsSize);
+        // ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
+        if (kernelFields) {
+            // TODO(b/239222407): This seems wrong. We should only free FDs when
+            // they are in a truncated section of the parcel.
+            closeFileDescriptors();
+        }
+        mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
+               kernelFields ? kernelFields->mObjectsSize : 0);
         mOwner = nullptr;
 
         LOG_ALLOC("Parcel %p: taking ownership of %zu capacity", this, desired);
@@ -2516,43 +2918,55 @@
         gParcelGlobalAllocCount++;
 
         mData = data;
-        mObjects = objects;
         mDataSize = (mDataSize < desired) ? mDataSize : desired;
         ALOGV("continueWrite Setting data size of %p to %zu", this, mDataSize);
         mDataCapacity = desired;
-        mObjectsSize = mObjectsCapacity = objectsSize;
-        mNextObjectHint = 0;
-        mObjectsSorted = false;
+        if (kernelFields) {
+            kernelFields->mObjects = objects;
+            kernelFields->mObjectsSize = kernelFields->mObjectsCapacity = objectsSize;
+            kernelFields->mNextObjectHint = 0;
+            kernelFields->mObjectsSorted = false;
+        }
 
     } else if (mData) {
-        if (objectsSize < mObjectsSize) {
+        if (kernelFields && objectsSize < kernelFields->mObjectsSize) {
+#ifdef BINDER_WITH_KERNEL_IPC
             // Need to release refs on any objects we are dropping.
             const sp<ProcessState> proc(ProcessState::self());
-            for (size_t i=objectsSize; i<mObjectsSize; i++) {
-                const flat_binder_object* flat
-                    = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
+            for (size_t i = objectsSize; i < kernelFields->mObjectsSize; i++) {
+                const flat_binder_object* flat =
+                        reinterpret_cast<flat_binder_object*>(mData + kernelFields->mObjects[i]);
                 if (flat->hdr.type == BINDER_TYPE_FD) {
                     // will need to rescan because we may have lopped off the only FDs
-                    mFdsKnown = false;
+                    kernelFields->mFdsKnown = false;
                 }
                 release_object(proc, *flat, this);
             }
 
             if (objectsSize == 0) {
-                free(mObjects);
-                mObjects = nullptr;
-                mObjectsCapacity = 0;
+                free(kernelFields->mObjects);
+                kernelFields->mObjects = nullptr;
+                kernelFields->mObjectsCapacity = 0;
             } else {
                 binder_size_t* objects =
-                    (binder_size_t*)realloc(mObjects, objectsSize*sizeof(binder_size_t));
+                        (binder_size_t*)realloc(kernelFields->mObjects,
+                                                objectsSize * sizeof(binder_size_t));
                 if (objects) {
-                    mObjects = objects;
-                    mObjectsCapacity = objectsSize;
+                    kernelFields->mObjects = objects;
+                    kernelFields->mObjectsCapacity = objectsSize;
                 }
             }
-            mObjectsSize = objectsSize;
-            mNextObjectHint = 0;
-            mObjectsSorted = false;
+            kernelFields->mObjectsSize = objectsSize;
+            kernelFields->mNextObjectHint = 0;
+            kernelFields->mObjectsSorted = false;
+#else  // BINDER_WITH_KERNEL_IPC
+            LOG_ALWAYS_FATAL("Non-zero numObjects for RPC Parcel");
+#endif // BINDER_WITH_KERNEL_IPC
+        }
+        if (rpcFields) {
+            if (status_t status = truncateRpcObjects(objectsSize); status != OK) {
+                return status;
+            }
         }
 
         // We own the data, so we can just do a realloc().
@@ -2588,9 +3002,12 @@
             return NO_MEMORY;
         }
 
-        if(!(mDataCapacity == 0 && mObjects == nullptr
-             && mObjectsCapacity == 0)) {
-            ALOGE("continueWrite: %zu/%p/%zu/%zu", mDataCapacity, mObjects, mObjectsCapacity, desired);
+        if (!(mDataCapacity == 0 &&
+              (kernelFields == nullptr ||
+               (kernelFields->mObjects == nullptr && kernelFields->mObjectsCapacity == 0)))) {
+            ALOGE("continueWrite: %zu/%p/%zu/%zu", mDataCapacity,
+                  kernelFields ? kernelFields->mObjects : nullptr,
+                  kernelFields ? kernelFields->mObjectsCapacity : 0, desired);
         }
 
         LOG_ALLOC("Parcel %p: allocating with %zu capacity", this, desired);
@@ -2607,6 +3024,35 @@
     return NO_ERROR;
 }
 
+status_t Parcel::truncateRpcObjects(size_t newObjectsSize) {
+    auto* rpcFields = maybeRpcFields();
+    if (newObjectsSize == 0) {
+        rpcFields->mObjectPositions.clear();
+        if (rpcFields->mFds) {
+            rpcFields->mFds->clear();
+        }
+        return OK;
+    }
+    while (rpcFields->mObjectPositions.size() > newObjectsSize) {
+        uint32_t pos = rpcFields->mObjectPositions.back();
+        rpcFields->mObjectPositions.pop_back();
+        const auto type = *reinterpret_cast<const RpcFields::ObjectType*>(mData + pos);
+        if (type == RpcFields::TYPE_NATIVE_FILE_DESCRIPTOR) {
+            const auto fdIndex =
+                    *reinterpret_cast<const int32_t*>(mData + pos + sizeof(RpcFields::ObjectType));
+            if (rpcFields->mFds == nullptr || fdIndex < 0 ||
+                static_cast<size_t>(fdIndex) >= rpcFields->mFds->size()) {
+                ALOGE("RPC Parcel contains invalid file descriptor index. index=%d fd_count=%zu",
+                      fdIndex, rpcFields->mFds ? rpcFields->mFds->size() : 0);
+                return BAD_VALUE;
+            }
+            // In practice, this always removes the last element.
+            rpcFields->mFds->erase(rpcFields->mFds->begin() + fdIndex);
+        }
+    }
+    return OK;
+}
+
 void Parcel::initState()
 {
     LOG_ALLOC("Parcel %p: initState", this);
@@ -2617,39 +3063,23 @@
     mDataPos = 0;
     ALOGV("initState Setting data size of %p to %zu", this, mDataSize);
     ALOGV("initState Setting data pos of %p to %zu", this, mDataPos);
-    mSession = nullptr;
-    mObjects = nullptr;
-    mObjectsSize = 0;
-    mObjectsCapacity = 0;
-    mNextObjectHint = 0;
-    mObjectsSorted = false;
-    mHasFds = false;
-    mFdsKnown = true;
+    mVariantFields.emplace<KernelFields>();
     mAllowFds = true;
     mDeallocZero = false;
     mOwner = nullptr;
-    mWorkSourceRequestHeaderPosition = 0;
-    mRequestHeaderPresent = false;
-
-    // racing multiple init leads only to multiple identical write
-    if (gMaxFds == 0) {
-        struct rlimit result;
-        if (!getrlimit(RLIMIT_NOFILE, &result)) {
-            gMaxFds = (size_t)result.rlim_cur;
-            //ALOGI("parcel fd limit set to %zu", gMaxFds);
-        } else {
-            ALOGW("Unable to getrlimit: %s", strerror(errno));
-            gMaxFds = 1024;
-        }
-    }
 }
 
 void Parcel::scanForFds() const {
-    status_t status = hasFileDescriptorsInRange(0, dataSize(), &mHasFds);
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return;
+    }
+    status_t status = hasFileDescriptorsInRange(0, dataSize(), &kernelFields->mHasFds);
     ALOGE_IF(status != NO_ERROR, "Error %d calling hasFileDescriptorsInRange()", status);
-    mFdsKnown = true;
+    kernelFields->mFdsKnown = true;
 }
 
+#ifdef BINDER_WITH_KERNEL_IPC
 size_t Parcel::getBlobAshmemSize() const
 {
     // This used to return the size of all blobs that were written to ashmem, now we're returning
@@ -2660,10 +3090,15 @@
 
 size_t Parcel::getOpenAshmemSize() const
 {
+    auto* kernelFields = maybeKernelFields();
+    if (kernelFields == nullptr) {
+        return 0;
+    }
+
     size_t openAshmemSize = 0;
-    for (size_t i = 0; i < mObjectsSize; i++) {
+    for (size_t i = 0; i < kernelFields->mObjectsSize; i++) {
         const flat_binder_object* flat =
-                reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
+                reinterpret_cast<const flat_binder_object*>(mData + kernelFields->mObjects[i]);
 
         // cookie is compared against zero for historical reasons
         // > obj.cookie = takeOwnership ? 1 : 0;
@@ -2677,6 +3112,7 @@
     }
     return openAshmemSize;
 }
+#endif // BINDER_WITH_KERNEL_IPC
 
 // --- Parcel::Blob ---
 
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 4a01d81..1f311ac 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -19,6 +19,7 @@
 #include <binder/ProcessState.h>
 
 #include <android-base/result.h>
+#include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 #include <binder/BpBinder.h>
 #include <binder/IPCThreadState.h>
@@ -35,14 +36,15 @@
 
 #include <errno.h>
 #include <fcntl.h>
-#include <mutex>
+#include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <unistd.h>
+#include <mutex>
 
 #define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
 #define DEFAULT_MAX_BINDER_THREADS 15
@@ -100,6 +102,11 @@
 
 sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
 {
+#ifdef BINDER_IPC_32BIT
+    LOG_ALWAYS_FATAL("32-bit binder IPC is not supported for new devices starting in Android P. If "
+                     "you do need to use this mode, please see b/232423610 or file an issue with "
+                     "AOSP upstream as otherwise this will be removed soon.");
+#endif
 
     if (driver == nullptr) {
         std::lock_guard<std::mutex> l(gProcessMutex);
@@ -170,6 +177,10 @@
     // the thread handler is installed
     if (gProcess) {
         gProcess->mForked = true;
+
+        // "O_CLOFORK"
+        close(gProcess->mDriverFD);
+        gProcess->mDriverFD = -1;
     }
     gProcessMutex.unlock();
 }
@@ -182,7 +193,6 @@
             ALOGW("Extra binder thread started, but 0 threads requested. Do not use "
                   "*startThreadPool when zero threads are requested.");
         }
-
         mThreadPoolStarted = true;
         spawnPooledThread(true);
     }
@@ -290,12 +300,17 @@
     return &mHandleToObject.editItemAt(handle);
 }
 
+// see b/166779391: cannot change the VNDK interface, so access like this
+extern sp<BBinder> the_context_object;
+
 sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
 {
     sp<IBinder> result;
 
     AutoMutex _l(mLock);
 
+    if (handle == 0 && the_context_object != nullptr) return the_context_object;
+
     handle_entry* e = lookupHandleLocked(handle);
 
     if (e != nullptr) {
@@ -386,6 +401,9 @@
         ALOGV("Spawning new pooled thread, name=%s\n", name.string());
         sp<Thread> t = sp<PoolThread>::make(isMain);
         t->run(name.string());
+        pthread_mutex_lock(&mThreadCountLock);
+        mKernelStartedThreads++;
+        pthread_mutex_unlock(&mThreadCountLock);
     }
 }
 
@@ -402,12 +420,23 @@
     return result;
 }
 
-size_t ProcessState::getThreadPoolMaxThreadCount() const {
+size_t ProcessState::getThreadPoolMaxTotalThreadCount() const {
+    pthread_mutex_lock(&mThreadCountLock);
+    base::ScopeGuard detachGuard = [&]() { pthread_mutex_unlock(&mThreadCountLock); };
+
     // may actually be one more than this, if join is called
-    if (mThreadPoolStarted) return mMaxThreads;
+    if (mThreadPoolStarted) {
+        return mCurrentThreads < mKernelStartedThreads
+                ? mMaxThreads
+                : mMaxThreads + mCurrentThreads - mKernelStartedThreads;
+    }
     // must not be initialized or maybe has poll thread setup, we
     // currently don't track this in libbinder
-    return 0;
+    LOG_ALWAYS_FATAL_IF(mKernelStartedThreads != 0,
+                        "Expecting 0 kernel started threads but have"
+                        " %zu",
+                        mKernelStartedThreads);
+    return mCurrentThreads;
 }
 
 #define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
@@ -415,6 +444,8 @@
     static const char* const names[] = {
         [static_cast<int>(DriverFeature::ONEWAY_SPAM_DETECTION)] =
             DRIVER_FEATURES_PATH "oneway_spam_detection",
+        [static_cast<int>(DriverFeature::EXTENDED_ERROR)] =
+            DRIVER_FEATURES_PATH "extended_error",
     };
     int fd = open(names[static_cast<int>(feature)], O_RDONLY | O_CLOEXEC);
     char on;
@@ -491,6 +522,8 @@
         mExecutingThreadsCount(0),
         mWaitingForThreads(0),
         mMaxThreads(DEFAULT_MAX_BINDER_THREADS),
+        mCurrentThreads(0),
+        mKernelStartedThreads(0),
         mStarvationStartTimeMs(0),
         mForked(false),
         mThreadPoolStarted(false),
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index ace5cd5..49be4dd 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -24,18 +24,21 @@
 #include <thread>
 #include <vector>
 
-#include <android-base/file.h>
 #include <android-base/hex.h>
 #include <android-base/scopeguard.h>
 #include <binder/Parcel.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcTransportRaw.h>
 #include <log/log.h>
+#include <utils/Compat.h>
 
+#include "BuildFlags.h"
 #include "FdTrigger.h"
+#include "OS.h"
 #include "RpcSocketAddress.h"
 #include "RpcState.h"
 #include "RpcWireFormat.h"
+#include "Utils.h"
 
 namespace android {
 
@@ -121,28 +124,36 @@
     mProtocolVersion = version;
 }
 
+void RpcServer::setSupportedFileDescriptorTransportModes(
+        const std::vector<RpcSession::FileDescriptorTransportMode>& modes) {
+    mSupportedFileDescriptorTransportModes.reset();
+    for (RpcSession::FileDescriptorTransportMode mode : modes) {
+        mSupportedFileDescriptorTransportModes.set(static_cast<size_t>(mode));
+    }
+}
+
 void RpcServer::setRootObject(const sp<IBinder>& binder) {
-    std::lock_guard<std::mutex> _l(mLock);
+    RpcMutexLockGuard _l(mLock);
     mRootObjectFactory = nullptr;
     mRootObjectWeak = mRootObject = binder;
 }
 
 void RpcServer::setRootObjectWeak(const wp<IBinder>& binder) {
-    std::lock_guard<std::mutex> _l(mLock);
+    RpcMutexLockGuard _l(mLock);
     mRootObject.clear();
     mRootObjectFactory = nullptr;
     mRootObjectWeak = binder;
 }
 void RpcServer::setPerSessionRootObject(
-        std::function<sp<IBinder>(const sockaddr*, socklen_t)>&& makeObject) {
-    std::lock_guard<std::mutex> _l(mLock);
+        std::function<sp<IBinder>(const void*, size_t)>&& makeObject) {
+    RpcMutexLockGuard _l(mLock);
     mRootObject.clear();
     mRootObjectWeak.clear();
     mRootObjectFactory = std::move(makeObject);
 }
 
 sp<IBinder> RpcServer::getRootObject() {
-    std::lock_guard<std::mutex> _l(mLock);
+    RpcMutexLockGuard _l(mLock);
     bool hasWeak = mRootObjectWeak.unsafe_get();
     sp<IBinder> ret = mRootObjectWeak.promote();
     ALOGW_IF(hasWeak && ret == nullptr, "RpcServer root object is freed, returning nullptr");
@@ -150,7 +161,7 @@
 }
 
 std::vector<uint8_t> RpcServer::getCertificate(RpcCertificateFormat format) {
-    std::lock_guard<std::mutex> _l(mLock);
+    RpcMutexLockGuard _l(mLock);
     return mCtx->getCertificate(format);
 }
 
@@ -159,15 +170,17 @@
 }
 
 void RpcServer::start() {
-    std::lock_guard<std::mutex> _l(mLock);
+    RpcMutexLockGuard _l(mLock);
     LOG_ALWAYS_FATAL_IF(mJoinThread.get(), "Already started!");
-    mJoinThread = std::make_unique<std::thread>(&joinRpcServer, sp<RpcServer>::fromExisting(this));
+    mJoinThread =
+            std::make_unique<RpcMaybeThread>(&joinRpcServer, sp<RpcServer>::fromExisting(this));
+    rpcJoinIfSingleThreaded(*mJoinThread);
 }
 
 void RpcServer::join() {
 
     {
-        std::lock_guard<std::mutex> _l(mLock);
+        RpcMutexLockGuard _l(mLock);
         LOG_ALWAYS_FATAL_IF(!mServer.ok(), "RpcServer must be setup to join.");
         LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Already joined");
         mJoinThreadRunning = true;
@@ -177,14 +190,16 @@
 
     status_t status;
     while ((status = mShutdownTrigger->triggerablePoll(mServer, POLLIN)) == OK) {
-        sockaddr_storage addr;
-        socklen_t addrLen = sizeof(addr);
+        std::array<uint8_t, kRpcAddressSize> addr;
+        static_assert(addr.size() >= sizeof(sockaddr_storage), "kRpcAddressSize is too small");
 
+        socklen_t addrLen = addr.size();
         unique_fd clientFd(
-                TEMP_FAILURE_RETRY(accept4(mServer.get(), reinterpret_cast<sockaddr*>(&addr),
+                TEMP_FAILURE_RETRY(accept4(mServer.get(), reinterpret_cast<sockaddr*>(addr.data()),
                                            &addrLen, SOCK_CLOEXEC | SOCK_NONBLOCK)));
 
-        LOG_ALWAYS_FATAL_IF(addrLen > static_cast<socklen_t>(sizeof(addr)), "Truncated address");
+        LOG_ALWAYS_FATAL_IF(addrLen > static_cast<socklen_t>(sizeof(sockaddr_storage)),
+                            "Truncated address");
 
         if (clientFd < 0) {
             ALOGE("Could not accept4 socket: %s", strerror(errno));
@@ -193,24 +208,32 @@
         LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
 
         {
-            std::lock_guard<std::mutex> _l(mLock);
-            std::thread thread =
-                    std::thread(&RpcServer::establishConnection, sp<RpcServer>::fromExisting(this),
-                                std::move(clientFd), addr, addrLen);
-            mConnectingThreads[thread.get_id()] = std::move(thread);
+            RpcMutexLockGuard _l(mLock);
+            RpcMaybeThread thread =
+                    RpcMaybeThread(&RpcServer::establishConnection,
+                                   sp<RpcServer>::fromExisting(this), std::move(clientFd), addr,
+                                   addrLen, RpcSession::join);
+
+            auto& threadRef = mConnectingThreads[thread.get_id()];
+            threadRef = std::move(thread);
+            rpcJoinIfSingleThreaded(threadRef);
         }
     }
     LOG_RPC_DETAIL("RpcServer::join exiting with %s", statusToString(status).c_str());
 
-    {
-        std::lock_guard<std::mutex> _l(mLock);
+    if constexpr (kEnableRpcThreads) {
+        RpcMutexLockGuard _l(mLock);
         mJoinThreadRunning = false;
+    } else {
+        // Multi-threaded builds clear this in shutdown(), but we need it valid
+        // so the loop above exits cleanly
+        mShutdownTrigger = nullptr;
     }
     mShutdownCv.notify_all();
 }
 
 bool RpcServer::shutdown() {
-    std::unique_lock<std::mutex> _l(mLock);
+    RpcMutexUniqueLock _l(mLock);
     if (mShutdownTrigger == nullptr) {
         LOG_RPC_DETAIL("Cannot shutdown. No shutdown trigger installed (already shutdown?)");
         return false;
@@ -221,10 +244,16 @@
     for (auto& [id, session] : mSessions) {
         (void)id;
         // server lock is a more general lock
-        std::lock_guard<std::mutex> _lSession(session->mMutex);
+        RpcMutexLockGuard _lSession(session->mMutex);
         session->mShutdownTrigger->trigger();
     }
 
+    if constexpr (!kEnableRpcThreads) {
+        // In single-threaded mode we're done here, everything else that
+        // needs to happen should be at the end of RpcServer::join()
+        return true;
+    }
+
     while (mJoinThreadRunning || !mConnectingThreads.empty() || !mSessions.empty()) {
         if (std::cv_status::timeout == mShutdownCv.wait_for(_l, std::chrono::seconds(1))) {
             ALOGE("Waiting for RpcServer to shut down (1s w/o progress). Join thread running: %d, "
@@ -252,7 +281,7 @@
 }
 
 std::vector<sp<RpcSession>> RpcServer::listSessions() {
-    std::lock_guard<std::mutex> _l(mLock);
+    RpcMutexLockGuard _l(mLock);
     std::vector<sp<RpcSession>> sessions;
     for (auto& [id, session] : mSessions) {
         (void)id;
@@ -262,12 +291,14 @@
 }
 
 size_t RpcServer::numUninitializedSessions() {
-    std::lock_guard<std::mutex> _l(mLock);
+    RpcMutexLockGuard _l(mLock);
     return mConnectingThreads.size();
 }
 
-void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
-                                    const sockaddr_storage addr, socklen_t addrLen) {
+void RpcServer::establishConnection(
+        sp<RpcServer>&& server, base::unique_fd clientFd, std::array<uint8_t, kRpcAddressSize> addr,
+        size_t addrLen,
+        std::function<void(sp<RpcSession>&&, RpcSession::PreJoinSetupResult&&)>&& joinFn) {
     // mShutdownTrigger can only be cleared once connection threads have joined.
     // It must be set before this thread is started
     LOG_ALWAYS_FATAL_IF(server->mShutdownTrigger == nullptr);
@@ -288,7 +319,8 @@
     RpcConnectionHeader header;
     if (status == OK) {
         iovec iov{&header, sizeof(header)};
-        status = client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1, {});
+        status = client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1,
+                                                std::nullopt, /*ancillaryFds=*/nullptr);
         if (status != OK) {
             ALOGE("Failed to read ID for client connecting to RPC server: %s",
                   statusToString(status).c_str());
@@ -302,8 +334,8 @@
             if (header.sessionIdSize == kSessionIdBytes) {
                 sessionId.resize(header.sessionIdSize);
                 iovec iov{sessionId.data(), sessionId.size()};
-                status =
-                        client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1, {});
+                status = client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1,
+                                                        std::nullopt, /*ancillaryFds=*/nullptr);
                 if (status != OK) {
                     ALOGE("Failed to read session ID for client connecting to RPC server: %s",
                           statusToString(status).c_str());
@@ -333,7 +365,8 @@
             };
 
             iovec iov{&response, sizeof(response)};
-            status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &iov, 1, {});
+            status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &iov, 1,
+                                                     std::nullopt, nullptr);
             if (status != OK) {
                 ALOGE("Failed to send new session response: %s", statusToString(status).c_str());
                 // still need to cleanup before we can return
@@ -341,12 +374,12 @@
         }
     }
 
-    std::thread thisThread;
+    RpcMaybeThread thisThread;
     sp<RpcSession> session;
     {
-        std::unique_lock<std::mutex> _l(server->mLock);
+        RpcMutexUniqueLock _l(server->mLock);
 
-        auto threadId = server->mConnectingThreads.find(std::this_thread::get_id());
+        auto threadId = server->mConnectingThreads.find(rpc_this_thread::get_id());
         LOG_ALWAYS_FATAL_IF(threadId == server->mConnectingThreads.end(),
                             "Must establish connection on owned thread");
         thisThread = std::move(threadId->second);
@@ -380,24 +413,34 @@
                     return;
                 }
 
-                base::unique_fd fd(TEMP_FAILURE_RETRY(
-                        open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW)));
-                if (!base::ReadFully(fd, sessionId.data(), sessionId.size())) {
-                    ALOGE("Could not read from /dev/urandom to create session ID");
+                auto status = getRandomBytes(sessionId.data(), sessionId.size());
+                if (status != OK) {
+                    ALOGE("Failed to read random session ID: %s", strerror(-status));
                     return;
                 }
             } while (server->mSessions.end() != server->mSessions.find(sessionId));
 
-            session = RpcSession::make();
+            session = sp<RpcSession>::make(nullptr);
             session->setMaxIncomingThreads(server->mMaxThreads);
             if (!session->setProtocolVersion(protocolVersion)) return;
 
+            if (header.fileDescriptorTransportMode <
+                        server->mSupportedFileDescriptorTransportModes.size() &&
+                server->mSupportedFileDescriptorTransportModes.test(
+                        header.fileDescriptorTransportMode)) {
+                session->setFileDescriptorTransportMode(
+                        static_cast<RpcSession::FileDescriptorTransportMode>(
+                                header.fileDescriptorTransportMode));
+            } else {
+                ALOGE("Rejecting connection: FileDescriptorTransportMode is not supported: %hhu",
+                      header.fileDescriptorTransportMode);
+                return;
+            }
+
             // if null, falls back to server root
             sp<IBinder> sessionSpecificRoot;
             if (server->mRootObjectFactory != nullptr) {
-                sessionSpecificRoot =
-                        server->mRootObjectFactory(reinterpret_cast<const sockaddr*>(&addr),
-                                                   addrLen);
+                sessionSpecificRoot = server->mRootObjectFactory(addr.data(), addrLen);
                 if (sessionSpecificRoot == nullptr) {
                     ALOGE("Warning: server returned null from root object factory");
                 }
@@ -438,7 +481,7 @@
     // avoid strong cycle
     server = nullptr;
 
-    RpcSession::join(std::move(session), std::move(setupResult));
+    joinFn(std::move(session), std::move(setupResult));
 }
 
 status_t RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
@@ -484,7 +527,7 @@
     LOG_RPC_DETAIL("Dropping session with address %s",
                    base::HexString(id.data(), id.size()).c_str());
 
-    std::lock_guard<std::mutex> _l(mLock);
+    RpcMutexLockGuard _l(mLock);
     auto it = mSessions.find(id);
     LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %s",
                         base::HexString(id.data(), id.size()).c_str());
@@ -498,17 +541,17 @@
 }
 
 bool RpcServer::hasServer() {
-    std::lock_guard<std::mutex> _l(mLock);
+    RpcMutexLockGuard _l(mLock);
     return mServer.ok();
 }
 
 unique_fd RpcServer::releaseServer() {
-    std::lock_guard<std::mutex> _l(mLock);
+    RpcMutexLockGuard _l(mLock);
     return std::move(mServer);
 }
 
 status_t RpcServer::setupExternalServer(base::unique_fd serverFd) {
-    std::lock_guard<std::mutex> _l(mLock);
+    RpcMutexLockGuard _l(mLock);
     if (mServer.ok()) {
         ALOGE("Each RpcServer can only have one server.");
         return INVALID_OPERATION;
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index d40778a..d347262 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -21,7 +21,6 @@
 #include <dlfcn.h>
 #include <inttypes.h>
 #include <poll.h>
-#include <pthread.h>
 #include <unistd.h>
 
 #include <string_view>
@@ -34,19 +33,18 @@
 #include <binder/RpcServer.h>
 #include <binder/RpcTransportRaw.h>
 #include <binder/Stability.h>
+#include <utils/Compat.h>
 #include <utils/String8.h>
 
+#include "BuildFlags.h"
 #include "FdTrigger.h"
+#include "OS.h"
 #include "RpcSocketAddress.h"
 #include "RpcState.h"
 #include "RpcWireFormat.h"
 #include "Utils.h"
 
-#ifdef __GLIBC__
-extern "C" pid_t gettid();
-#endif
-
-#ifndef __ANDROID_RECOVERY__
+#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
 #include <android_runtime/vm.h>
 #include <jni.h>
 #endif
@@ -63,7 +61,7 @@
 RpcSession::~RpcSession() {
     LOG_RPC_DETAIL("RpcSession destroyed %p", this);
 
-    std::lock_guard<std::mutex> _l(mMutex);
+    RpcMutexLockGuard _l(mMutex);
     LOG_ALWAYS_FATAL_IF(mConnections.mIncoming.size() != 0,
                         "Should not be able to destroy a session with servers in use.");
 }
@@ -80,34 +78,30 @@
 }
 
 void RpcSession::setMaxIncomingThreads(size_t threads) {
-    std::lock_guard<std::mutex> _l(mMutex);
-    LOG_ALWAYS_FATAL_IF(!mConnections.mOutgoing.empty() || !mConnections.mIncoming.empty(),
-                        "Must set max incoming threads before setting up connections, but has %zu "
-                        "client(s) and %zu server(s)",
-                        mConnections.mOutgoing.size(), mConnections.mIncoming.size());
+    RpcMutexLockGuard _l(mMutex);
+    LOG_ALWAYS_FATAL_IF(mStartedSetup,
+                        "Must set max incoming threads before setting up connections");
     mMaxIncomingThreads = threads;
 }
 
 size_t RpcSession::getMaxIncomingThreads() {
-    std::lock_guard<std::mutex> _l(mMutex);
+    RpcMutexLockGuard _l(mMutex);
     return mMaxIncomingThreads;
 }
 
 void RpcSession::setMaxOutgoingThreads(size_t threads) {
-    std::lock_guard<std::mutex> _l(mMutex);
-    LOG_ALWAYS_FATAL_IF(!mConnections.mOutgoing.empty() || !mConnections.mIncoming.empty(),
-                        "Must set max outgoing threads before setting up connections, but has %zu "
-                        "client(s) and %zu server(s)",
-                        mConnections.mOutgoing.size(), mConnections.mIncoming.size());
+    RpcMutexLockGuard _l(mMutex);
+    LOG_ALWAYS_FATAL_IF(mStartedSetup,
+                        "Must set max outgoing threads before setting up connections");
     mMaxOutgoingThreads = threads;
 }
 
 size_t RpcSession::getMaxOutgoingThreads() {
-    std::lock_guard<std::mutex> _l(mMutex);
+    RpcMutexLockGuard _l(mMutex);
     return mMaxOutgoingThreads;
 }
 
-bool RpcSession::setProtocolVersion(uint32_t version) {
+bool RpcSession::setProtocolVersionInternal(uint32_t version, bool checkStarted) {
     if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT &&
         version != RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
         ALOGE("Cannot start RPC session with version %u which is unknown (current protocol version "
@@ -116,7 +110,9 @@
         return false;
     }
 
-    std::lock_guard<std::mutex> _l(mMutex);
+    RpcMutexLockGuard _l(mMutex);
+    LOG_ALWAYS_FATAL_IF(checkStarted && mStartedSetup,
+                        "Must set protocol version before setting up connections");
     if (mProtocolVersion && version > *mProtocolVersion) {
         ALOGE("Cannot upgrade explicitly capped protocol version %u to newer version %u",
               *mProtocolVersion, version);
@@ -127,11 +123,26 @@
     return true;
 }
 
+bool RpcSession::setProtocolVersion(uint32_t version) {
+    return setProtocolVersionInternal(version, true);
+}
+
 std::optional<uint32_t> RpcSession::getProtocolVersion() {
-    std::lock_guard<std::mutex> _l(mMutex);
+    RpcMutexLockGuard _l(mMutex);
     return mProtocolVersion;
 }
 
+void RpcSession::setFileDescriptorTransportMode(FileDescriptorTransportMode mode) {
+    RpcMutexLockGuard _l(mMutex);
+    LOG_ALWAYS_FATAL_IF(mStartedSetup,
+                        "Must set file descriptor transport mode before setting up connections");
+    mFileDescriptorTransportMode = mode;
+}
+
+RpcSession::FileDescriptorTransportMode RpcSession::getFileDescriptorTransportMode() {
+    return mFileDescriptorTransportMode;
+}
+
 status_t RpcSession::setupUnixDomainClient(const char* path) {
     return setupSocketClient(UnixSocketAddress(path));
 }
@@ -152,13 +163,7 @@
 }
 
 status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
-    // Why passing raw fd? When fd is passed as reference, Clang analyzer sees that the variable
-    // `fd` is a moved-from object. To work-around the issue, unwrap the raw fd from the outer `fd`,
-    // pass the raw fd by value to the lambda, and then finally wrap it in unique_fd inside the
-    // lambda.
-    return setupClient([&, raw = fd.release()](const std::vector<uint8_t>& sessionId,
-                                               bool incoming) -> status_t {
-        unique_fd fd(raw);
+    return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) -> status_t {
         if (!fd.ok()) {
             fd = request();
             if (!fd.ok()) return BAD_VALUE;
@@ -167,7 +172,9 @@
             ALOGE("setupPreconnectedClient: %s", res.error().message().c_str());
             return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code();
         }
-        return initAndAddConnection(std::move(fd), sessionId, incoming);
+        status_t status = initAndAddConnection(std::move(fd), sessionId, incoming);
+        fd = unique_fd(); // Explicitly reset after move to avoid analyzer warning.
+        return status;
     });
 }
 
@@ -208,7 +215,7 @@
 }
 
 bool RpcSession::shutdownAndWait(bool wait) {
-    std::unique_lock<std::mutex> _l(mMutex);
+    RpcMutexUniqueLock _l(mMutex);
     LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr, "Shutdown trigger not installed");
 
     mShutdownTrigger->trigger();
@@ -221,6 +228,12 @@
     }
 
     _l.unlock();
+
+    if (status_t res = state()->sendObituaries(sp<RpcSession>::fromExisting(this)); res != OK) {
+        ALOGE("Failed to send obituaries as the RpcSession is shutting down: %s",
+              statusToString(res).c_str());
+    }
+
     mRpcBinderState->clear();
 
     return true;
@@ -255,7 +268,7 @@
 
 status_t RpcSession::readId() {
     {
-        std::lock_guard<std::mutex> _l(mMutex);
+        RpcMutexLockGuard _l(mMutex);
         LOG_ALWAYS_FATAL_IF(mForServer != nullptr, "Can only update ID for client.");
     }
 
@@ -281,7 +294,7 @@
     mCv.notify_all();
 }
 
-void RpcSession::WaitForShutdownListener::waitForShutdown(std::unique_lock<std::mutex>& lock,
+void RpcSession::WaitForShutdownListener::waitForShutdown(RpcMutexUniqueLock& lock,
                                                           const sp<RpcSession>& session) {
     while (session->mConnections.mIncoming.size() > 0) {
         if (std::cv_status::timeout == mCv.wait_for(lock, std::chrono::seconds(1))) {
@@ -292,11 +305,11 @@
     }
 }
 
-void RpcSession::preJoinThreadOwnership(std::thread thread) {
-    LOG_ALWAYS_FATAL_IF(thread.get_id() != std::this_thread::get_id(), "Must own this thread");
+void RpcSession::preJoinThreadOwnership(RpcMaybeThread thread) {
+    LOG_ALWAYS_FATAL_IF(thread.get_id() != rpc_this_thread::get_id(), "Must own this thread");
 
     {
-        std::lock_guard<std::mutex> _l(mMutex);
+        RpcMutexLockGuard _l(mMutex);
         mConnections.mThreads[thread.get_id()] = std::move(thread);
     }
 }
@@ -323,7 +336,7 @@
 }
 
 namespace {
-#ifdef __ANDROID_RECOVERY__
+#if !defined(__ANDROID__) || defined(__ANDROID_RECOVERY__)
 class JavaThreadAttacher {};
 #else
 // RAII object for attaching / detaching current thread to JVM if Android Runtime exists. If
@@ -403,8 +416,8 @@
 
     sp<RpcSession::EventListener> listener;
     {
-        std::lock_guard<std::mutex> _l(session->mMutex);
-        auto it = session->mConnections.mThreads.find(std::this_thread::get_id());
+        RpcMutexLockGuard _l(session->mMutex);
+        auto it = session->mConnections.mThreads.find(rpc_this_thread::get_id());
         LOG_ALWAYS_FATAL_IF(it == session->mConnections.mThreads.end());
         it->second.detach();
         session->mConnections.mThreads.erase(it);
@@ -437,10 +450,17 @@
 status_t RpcSession::setupClient(const std::function<status_t(const std::vector<uint8_t>& sessionId,
                                                               bool incoming)>& connectAndInit) {
     {
-        std::lock_guard<std::mutex> _l(mMutex);
-        LOG_ALWAYS_FATAL_IF(mConnections.mOutgoing.size() != 0,
-                            "Must only setup session once, but already has %zu clients",
-                            mConnections.mOutgoing.size());
+        RpcMutexLockGuard _l(mMutex);
+        LOG_ALWAYS_FATAL_IF(mStartedSetup, "Must only setup session once");
+        mStartedSetup = true;
+
+        if constexpr (!kEnableRpcThreads) {
+            LOG_ALWAYS_FATAL_IF(mMaxIncomingThreads > 0,
+                                "Incoming threads are not supported on single-threaded libbinder");
+            // mMaxIncomingThreads should not change from here to its use below,
+            // since we set mStartedSetup==true and setMaxIncomingThreads checks
+            // for that
+        }
     }
 
     if (auto status = initShutdownTrigger(); status != OK) return status;
@@ -481,7 +501,7 @@
                                                     sp<RpcSession>::fromExisting(this), &version);
             status != OK)
             return status;
-        if (!setProtocolVersion(version)) return BAD_VALUE;
+        if (!setProtocolVersionInternal(version, false)) return BAD_VALUE;
     }
 
     // TODO(b/189955605): we should add additional sessions dynamically
@@ -613,6 +633,7 @@
     RpcConnectionHeader header{
             .version = mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION),
             .options = 0,
+            .fileDescriptorTransportMode = static_cast<uint8_t>(mFileDescriptorTransportMode),
             .sessionIdSize = static_cast<uint16_t>(sessionId.size()),
     };
 
@@ -621,8 +642,8 @@
     }
 
     iovec headerIov{&header, sizeof(header)};
-    auto sendHeaderStatus =
-            server->interruptableWriteFully(mShutdownTrigger.get(), &headerIov, 1, {});
+    auto sendHeaderStatus = server->interruptableWriteFully(mShutdownTrigger.get(), &headerIov, 1,
+                                                            std::nullopt, nullptr);
     if (sendHeaderStatus != OK) {
         ALOGE("Could not write connection header to socket: %s",
               statusToString(sendHeaderStatus).c_str());
@@ -633,7 +654,8 @@
         iovec sessionIov{const_cast<void*>(static_cast<const void*>(sessionId.data())),
                          sessionId.size()};
         auto sendSessionIdStatus =
-                server->interruptableWriteFully(mShutdownTrigger.get(), &sessionIov, 1, {});
+                server->interruptableWriteFully(mShutdownTrigger.get(), &sessionIov, 1,
+                                                std::nullopt, nullptr);
         if (sendSessionIdStatus != OK) {
             ALOGE("Could not write session ID ('%s') to socket: %s",
                   base::HexString(sessionId.data(), sessionId.size()).c_str(),
@@ -652,14 +674,14 @@
 }
 
 status_t RpcSession::addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport) {
-    std::mutex mutex;
-    std::condition_variable joinCv;
-    std::unique_lock<std::mutex> lock(mutex);
-    std::thread thread;
+    RpcMutex mutex;
+    RpcConditionVariable joinCv;
+    RpcMutexUniqueLock lock(mutex);
+    RpcMaybeThread thread;
     sp<RpcSession> thiz = sp<RpcSession>::fromExisting(this);
     bool ownershipTransferred = false;
-    thread = std::thread([&]() {
-        std::unique_lock<std::mutex> threadLock(mutex);
+    thread = RpcMaybeThread([&]() {
+        RpcMutexUniqueLock threadLock(mutex);
         std::unique_ptr<RpcTransport> movedRpcTransport = std::move(rpcTransport);
         // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
         sp<RpcSession> session = thiz;
@@ -675,6 +697,7 @@
 
         RpcSession::join(std::move(session), std::move(setupResult));
     });
+    rpcJoinIfSingleThreaded(thread);
     joinCv.wait(lock, [&] { return ownershipTransferred; });
     LOG_ALWAYS_FATAL_IF(!ownershipTransferred);
     return OK;
@@ -694,9 +717,9 @@
 status_t RpcSession::addOutgoingConnection(std::unique_ptr<RpcTransport> rpcTransport, bool init) {
     sp<RpcConnection> connection = sp<RpcConnection>::make();
     {
-        std::lock_guard<std::mutex> _l(mMutex);
+        RpcMutexLockGuard _l(mMutex);
         connection->rpcTransport = std::move(rpcTransport);
-        connection->exclusiveTid = gettid();
+        connection->exclusiveTid = rpcGetThreadId();
         mConnections.mOutgoing.push_back(connection);
     }
 
@@ -706,10 +729,7 @@
                 mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
     }
 
-    {
-        std::lock_guard<std::mutex> _l(mMutex);
-        connection->exclusiveTid = std::nullopt;
-    }
+    clearConnectionTid(connection);
 
     return status;
 }
@@ -722,6 +742,7 @@
     LOG_ALWAYS_FATAL_IF(mEventListener != nullptr);
     LOG_ALWAYS_FATAL_IF(eventListener == nullptr);
     LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr);
+    LOG_ALWAYS_FATAL_IF(mCtx != nullptr);
 
     mShutdownTrigger = FdTrigger::make();
     if (mShutdownTrigger == nullptr) return false;
@@ -735,7 +756,7 @@
 
 sp<RpcSession::RpcConnection> RpcSession::assignIncomingConnectionToThisThread(
         std::unique_ptr<RpcTransport> rpcTransport) {
-    std::lock_guard<std::mutex> _l(mMutex);
+    RpcMutexLockGuard _l(mMutex);
 
     if (mConnections.mIncoming.size() >= mMaxIncomingThreads) {
         ALOGE("Cannot add thread to session with %zu threads (max is set to %zu)",
@@ -753,7 +774,7 @@
 
     sp<RpcConnection> session = sp<RpcConnection>::make();
     session->rpcTransport = std::move(rpcTransport);
-    session->exclusiveTid = gettid();
+    session->exclusiveTid = rpcGetThreadId();
 
     mConnections.mIncoming.push_back(session);
     mConnections.mMaxIncoming = mConnections.mIncoming.size();
@@ -762,7 +783,7 @@
 }
 
 bool RpcSession::removeIncomingConnection(const sp<RpcConnection>& connection) {
-    std::unique_lock<std::mutex> _l(mMutex);
+    RpcMutexUniqueLock _l(mMutex);
     if (auto it =
                 std::find(mConnections.mIncoming.begin(), mConnections.mIncoming.end(), connection);
         it != mConnections.mIncoming.end()) {
@@ -779,6 +800,15 @@
     return false;
 }
 
+void RpcSession::clearConnectionTid(const sp<RpcConnection>& connection) {
+    RpcMutexUniqueLock _l(mMutex);
+    connection->exclusiveTid = std::nullopt;
+    if (mConnections.mWaitingThreads > 0) {
+        _l.unlock();
+        mAvailableConnectionCv.notify_one();
+    }
+}
+
 std::vector<uint8_t> RpcSession::getCertificate(RpcCertificateFormat format) {
     return mCtx->getCertificate(format);
 }
@@ -789,8 +819,8 @@
     connection->mConnection = nullptr;
     connection->mReentrant = false;
 
-    pid_t tid = gettid();
-    std::unique_lock<std::mutex> _l(session->mMutex);
+    uint64_t tid = rpcGetThreadId();
+    RpcMutexUniqueLock _l(session->mMutex);
 
     session->mConnections.mWaitingThreads++;
     while (true) {
@@ -876,7 +906,7 @@
     return OK;
 }
 
-void RpcSession::ExclusiveConnection::findConnection(pid_t tid, sp<RpcConnection>* exclusive,
+void RpcSession::ExclusiveConnection::findConnection(uint64_t tid, sp<RpcConnection>* exclusive,
                                                      sp<RpcConnection>* available,
                                                      std::vector<sp<RpcConnection>>& sockets,
                                                      size_t socketsIndexHint) {
@@ -908,12 +938,7 @@
     // is using this fd, and it retains the right to it. So, we don't give up
     // exclusive ownership, and no thread is freed.
     if (!mReentrant && mConnection != nullptr) {
-        std::unique_lock<std::mutex> _l(mSession->mMutex);
-        mConnection->exclusiveTid = std::nullopt;
-        if (mSession->mConnections.mWaitingThreads > 0) {
-            _l.unlock();
-            mSession->mAvailableConnectionCv.notify_one();
-        }
+        mSession->clearConnectionTid(mConnection);
     }
 }
 
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 6d89064..c0e36c4 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -21,12 +21,14 @@
 #include <android-base/hex.h>
 #include <android-base/macros.h>
 #include <android-base/scopeguard.h>
+#include <android-base/stringprintf.h>
 #include <binder/BpBinder.h>
 #include <binder/IPCThreadState.h>
 #include <binder/RpcServer.h>
 
 #include "Debug.h"
 #include "RpcWireFormat.h"
+#include "Utils.h"
 
 #include <random>
 
@@ -34,7 +36,7 @@
 
 namespace android {
 
-using base::ScopeGuard;
+using base::StringPrintf;
 
 #if RPC_FLAKE_PRONE
 void rpcMaybeWaitToFlake() {
@@ -42,13 +44,22 @@
     [[clang::no_destroy]] static std::mutex m;
     unsigned num;
     {
-        std::lock_guard<std::mutex> lock(m);
+        RpcMutexLockGuard lock(m);
         num = r();
     }
     if (num % 10 == 0) usleep(num % 1000);
 }
 #endif
 
+static bool enableAncillaryFds(RpcSession::FileDescriptorTransportMode mode) {
+    switch (mode) {
+        case RpcSession::FileDescriptorTransportMode::NONE:
+            return false;
+        case RpcSession::FileDescriptorTransportMode::UNIX:
+            return true;
+    }
+}
+
 RpcState::RpcState() {}
 RpcState::~RpcState() {}
 
@@ -77,7 +88,7 @@
         return INVALID_OPERATION;
     }
 
-    std::lock_guard<std::mutex> _l(mNodeMutex);
+    RpcMutexLockGuard _l(mNodeMutex);
     if (mTerminated) return DEAD_OBJECT;
 
     // TODO(b/182939933): maybe move address out of BpBinder, and keep binder->address map
@@ -153,7 +164,7 @@
         return BAD_VALUE;
     }
 
-    std::lock_guard<std::mutex> _l(mNodeMutex);
+    RpcMutexLockGuard _l(mNodeMutex);
     if (mTerminated) return DEAD_OBJECT;
 
     if (auto it = mNodeForAddress.find(address); it != mNodeForAddress.end()) {
@@ -188,7 +199,7 @@
     // extra reference counting packets now.
     if (binder->remoteBinder()) return OK;
 
-    std::unique_lock<std::mutex> _l(mNodeMutex);
+    RpcMutexUniqueLock _l(mNodeMutex);
     if (mTerminated) return DEAD_OBJECT;
 
     auto it = mNodeForAddress.find(address);
@@ -215,78 +226,105 @@
     return OK;
 }
 
+status_t RpcState::sendObituaries(const sp<RpcSession>& session) {
+    RpcMutexUniqueLock _l(mNodeMutex);
+
+    // Gather strong pointers to all of the remote binders for this session so
+    // we hold the strong references. remoteBinder() returns a raw pointer.
+    // Send the obituaries and drop the strong pointers outside of the lock so
+    // the destructors and the onBinderDied calls are not done while locked.
+    std::vector<sp<IBinder>> remoteBinders;
+    for (const auto& [_, binderNode] : mNodeForAddress) {
+        if (auto binder = binderNode.binder.promote()) {
+            remoteBinders.push_back(std::move(binder));
+        }
+    }
+    _l.unlock();
+
+    for (const auto& binder : remoteBinders) {
+        if (binder->remoteBinder() &&
+            binder->remoteBinder()->getPrivateAccessor().rpcSession() == session) {
+            binder->remoteBinder()->sendObituary();
+        }
+    }
+    return OK;
+}
+
 size_t RpcState::countBinders() {
-    std::lock_guard<std::mutex> _l(mNodeMutex);
+    RpcMutexLockGuard _l(mNodeMutex);
     return mNodeForAddress.size();
 }
 
 void RpcState::dump() {
-    std::lock_guard<std::mutex> _l(mNodeMutex);
+    RpcMutexLockGuard _l(mNodeMutex);
     dumpLocked();
 }
 
 void RpcState::clear() {
-    std::unique_lock<std::mutex> _l(mNodeMutex);
+    RpcMutexUniqueLock _l(mNodeMutex);
 
     if (mTerminated) {
         LOG_ALWAYS_FATAL_IF(!mNodeForAddress.empty(),
                             "New state should be impossible after terminating!");
         return;
     }
+    mTerminated = true;
 
     if (SHOULD_LOG_RPC_DETAIL) {
         ALOGE("RpcState::clear()");
         dumpLocked();
     }
 
-    // if the destructor of a binder object makes another RPC call, then calling
-    // decStrong could deadlock. So, we must hold onto these binders until
-    // mNodeMutex is no longer taken.
-    std::vector<sp<IBinder>> tempHoldBinder;
-
-    mTerminated = true;
+    // invariants
     for (auto& [address, node] : mNodeForAddress) {
-        sp<IBinder> binder = node.binder.promote();
-        LOG_ALWAYS_FATAL_IF(binder == nullptr, "Binder %p expected to be owned.", binder.get());
-
-        if (node.sentRef != nullptr) {
-            tempHoldBinder.push_back(node.sentRef);
+        bool guaranteedHaveBinder = node.timesSent > 0;
+        if (guaranteedHaveBinder) {
+            LOG_ALWAYS_FATAL_IF(node.sentRef == nullptr,
+                                "Binder expected to be owned with address: %" PRIu64 " %s", address,
+                                node.toString().c_str());
         }
     }
 
-    mNodeForAddress.clear();
+    // if the destructor of a binder object makes another RPC call, then calling
+    // decStrong could deadlock. So, we must hold onto these binders until
+    // mNodeMutex is no longer taken.
+    auto temp = std::move(mNodeForAddress);
+    mNodeForAddress.clear(); // RpcState isn't reusable, but for future/explicit
 
     _l.unlock();
-    tempHoldBinder.clear(); // explicit
+    temp.clear(); // explicit
 }
 
 void RpcState::dumpLocked() {
     ALOGE("DUMP OF RpcState %p", this);
     ALOGE("DUMP OF RpcState (%zu nodes)", mNodeForAddress.size());
     for (const auto& [address, node] : mNodeForAddress) {
-        sp<IBinder> binder = node.binder.promote();
-
-        const char* desc;
-        if (binder) {
-            if (binder->remoteBinder()) {
-                if (binder->remoteBinder()->isRpcBinder()) {
-                    desc = "(rpc binder proxy)";
-                } else {
-                    desc = "(binder proxy)";
-                }
-            } else {
-                desc = "(local binder)";
-            }
-        } else {
-            desc = "(null)";
-        }
-
-        ALOGE("- BINDER NODE: %p times sent:%zu times recd: %zu a: %" PRIu64 " type: %s",
-              node.binder.unsafe_get(), node.timesSent, node.timesRecd, address, desc);
+        ALOGE("- address: %" PRIu64 " %s", address, node.toString().c_str());
     }
     ALOGE("END DUMP OF RpcState");
 }
 
+std::string RpcState::BinderNode::toString() const {
+    sp<IBinder> strongBinder = this->binder.promote();
+
+    const char* desc;
+    if (strongBinder) {
+        if (strongBinder->remoteBinder()) {
+            if (strongBinder->remoteBinder()->isRpcBinder()) {
+                desc = "(rpc binder proxy)";
+            } else {
+                desc = "(binder proxy)";
+            }
+        } else {
+            desc = "(local binder)";
+        }
+    } else {
+        desc = "(not promotable)";
+    }
+
+    return StringPrintf("node{%p times sent: %zu times recd: %zu type: %s}",
+                        this->binder.unsafe_get(), this->timesSent, this->timesRecd, desc);
+}
 
 RpcState::CommandData::CommandData(size_t size) : mSize(size) {
     // The maximum size for regular binder is 1MB for all concurrent
@@ -309,9 +347,11 @@
     mData.reset(new (std::nothrow) uint8_t[size]);
 }
 
-status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection,
-                           const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs,
-                           const std::function<status_t()>& altPoll) {
+status_t RpcState::rpcSend(
+        const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+        const char* what, iovec* iovs, int niovs,
+        const std::optional<android::base::function_ref<status_t()>>& altPoll,
+        const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
     for (int i = 0; i < niovs; i++) {
         LOG_RPC_DETAIL("Sending %s (part %d of %d) on RpcTransport %p: %s",
                        what, i + 1, niovs, connection->rpcTransport.get(),
@@ -320,7 +360,8 @@
 
     if (status_t status =
                 connection->rpcTransport->interruptableWriteFully(session->mShutdownTrigger.get(),
-                                                                  iovs, niovs, altPoll);
+                                                                  iovs, niovs, altPoll,
+                                                                  ancillaryFds);
         status != OK) {
         LOG_RPC_DETAIL("Failed to write %s (%d iovs) on RpcTransport %p, error: %s", what, niovs,
                        connection->rpcTransport.get(), statusToString(status).c_str());
@@ -331,11 +372,14 @@
     return OK;
 }
 
-status_t RpcState::rpcRec(const sp<RpcSession::RpcConnection>& connection,
-                          const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs) {
+status_t RpcState::rpcRec(
+        const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+        const char* what, iovec* iovs, int niovs,
+        std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
     if (status_t status =
                 connection->rpcTransport->interruptableReadFully(session->mShutdownTrigger.get(),
-                                                                 iovs, niovs, {});
+                                                                 iovs, niovs, std::nullopt,
+                                                                 ancillaryFds);
         status != OK) {
         LOG_RPC_DETAIL("Failed to read %s (%d iovs) on RpcTransport %p, error: %s", what, niovs,
                        connection->rpcTransport.get(), statusToString(status).c_str());
@@ -355,7 +399,7 @@
                                           const sp<RpcSession>& session, uint32_t* version) {
     RpcNewSessionResponse response;
     iovec iov{&response, sizeof(response)};
-    if (status_t status = rpcRec(connection, session, "new session response", &iov, 1);
+    if (status_t status = rpcRec(connection, session, "new session response", &iov, 1, nullptr);
         status != OK) {
         return status;
     }
@@ -369,14 +413,15 @@
             .msg = RPC_CONNECTION_INIT_OKAY,
     };
     iovec iov{&init, sizeof(init)};
-    return rpcSend(connection, session, "connection init", &iov, 1);
+    return rpcSend(connection, session, "connection init", &iov, 1, std::nullopt);
 }
 
 status_t RpcState::readConnectionInit(const sp<RpcSession::RpcConnection>& connection,
                                       const sp<RpcSession>& session) {
     RpcOutgoingConnectionInit init;
     iovec iov{&init, sizeof(init)};
-    if (status_t status = rpcRec(connection, session, "connection init", &iov, 1); status != OK)
+    if (status_t status = rpcRec(connection, session, "connection init", &iov, 1, nullptr);
+        status != OK)
         return status;
 
     static_assert(sizeof(init.msg) == sizeof(RPC_CONNECTION_INIT_OKAY));
@@ -448,20 +493,12 @@
 status_t RpcState::transact(const sp<RpcSession::RpcConnection>& connection,
                             const sp<IBinder>& binder, uint32_t code, const Parcel& data,
                             const sp<RpcSession>& session, Parcel* reply, uint32_t flags) {
-    if (!data.isForRpc()) {
-        ALOGE("Refusing to send RPC with parcel not crafted for RPC call on binder %p code "
-              "%" PRIu32,
-              binder.get(), code);
-        return BAD_TYPE;
+    std::string errorMsg;
+    if (status_t status = validateParcel(session, data, &errorMsg); status != OK) {
+        ALOGE("Refusing to send RPC on binder %p code %" PRIu32 ": Parcel %p failed validation: %s",
+              binder.get(), code, &data, errorMsg.c_str());
+        return status;
     }
-
-    if (data.objectsCount() != 0) {
-        ALOGE("Parcel at %p has attached objects but is being used in an RPC call on binder %p "
-              "code %" PRIu32,
-              &data, binder.get(), code);
-        return BAD_TYPE;
-    }
-
     uint64_t address;
     if (status_t status = onBinderLeaving(session, binder, &address); status != OK) return status;
 
@@ -477,7 +514,7 @@
     uint64_t asyncNumber = 0;
 
     if (address != 0) {
-        std::unique_lock<std::mutex> _l(mNodeMutex);
+        RpcMutexUniqueLock _l(mNodeMutex);
         if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
         auto it = mNodeForAddress.find(address);
         LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(),
@@ -493,14 +530,21 @@
         }
     }
 
-    LOG_ALWAYS_FATAL_IF(std::numeric_limits<int32_t>::max() - sizeof(RpcWireHeader) -
-                                        sizeof(RpcWireTransaction) <
-                                data.dataSize(),
-                        "Too much data %zu", data.dataSize());
+    auto* rpcFields = data.maybeRpcFields();
+    LOG_ALWAYS_FATAL_IF(rpcFields == nullptr);
 
+    Span<const uint32_t> objectTableSpan = Span<const uint32_t>{rpcFields->mObjectPositions.data(),
+                                                                rpcFields->mObjectPositions.size()};
+
+    uint32_t bodySize;
+    LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(sizeof(RpcWireTransaction), data.dataSize(),
+                                               &bodySize) ||
+                                __builtin_add_overflow(objectTableSpan.byteSize(), bodySize,
+                                                       &bodySize),
+                        "Too much data %zu", data.dataSize());
     RpcWireHeader command{
             .command = RPC_COMMAND_TRANSACT,
-            .bodySize = static_cast<uint32_t>(sizeof(RpcWireTransaction) + data.dataSize()),
+            .bodySize = bodySize,
     };
 
     RpcWireTransaction transaction{
@@ -508,6 +552,8 @@
             .code = code,
             .flags = flags,
             .asyncNumber = asyncNumber,
+            // bodySize didn't overflow => this cast is safe
+            .parcelDataSize = static_cast<uint32_t>(data.dataSize()),
     };
 
     constexpr size_t kWaitMaxUs = 1000000;
@@ -516,31 +562,33 @@
 
     // Oneway calls have no sync point, so if many are sent before, whether this
     // is a twoway or oneway transaction, they may have filled up the socket.
-    // So, make sure we drain them before polling.
-    std::function<status_t()> drainRefs = [&] {
-        if (waitUs > kWaitLogUs) {
-            ALOGE("Cannot send command, trying to process pending refcounts. Waiting %zuus. Too "
-                  "many oneway calls?",
-                  waitUs);
-        }
-
-        if (waitUs > 0) {
-            usleep(waitUs);
-            waitUs = std::min(kWaitMaxUs, waitUs * 2);
-        } else {
-            waitUs = 1;
-        }
-
-        return drainCommands(connection, session, CommandType::CONTROL_ONLY);
-    };
+    // So, make sure we drain them before polling
 
     iovec iovs[]{
             {&command, sizeof(RpcWireHeader)},
             {&transaction, sizeof(RpcWireTransaction)},
             {const_cast<uint8_t*>(data.data()), data.dataSize()},
+            objectTableSpan.toIovec(),
     };
-    if (status_t status =
-                rpcSend(connection, session, "transaction", iovs, arraysize(iovs), drainRefs);
+    if (status_t status = rpcSend(
+                connection, session, "transaction", iovs, arraysize(iovs),
+                [&] {
+                    if (waitUs > kWaitLogUs) {
+                        ALOGE("Cannot send command, trying to process pending refcounts. Waiting "
+                              "%zuus. Too many oneway calls?",
+                              waitUs);
+                    }
+
+                    if (waitUs > 0) {
+                        usleep(waitUs);
+                        waitUs = std::min(kWaitMaxUs, waitUs * 2);
+                    } else {
+                        waitUs = 1;
+                    }
+
+                    return drainCommands(connection, session, CommandType::CONTROL_ONLY);
+                },
+                rpcFields->mFds.get());
         status != OK) {
         // TODO(b/167966510): need to undo onBinderLeaving - we know the
         // refcount isn't successfully transferred.
@@ -560,54 +608,91 @@
     return waitForReply(connection, session, reply);
 }
 
-static void cleanup_reply_data(Parcel* p, const uint8_t* data, size_t dataSize,
-                               const binder_size_t* objects, size_t objectsCount) {
-    (void)p;
-    delete[] const_cast<uint8_t*>(data - offsetof(RpcWireReply, data));
+static void cleanup_reply_data(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
+                               size_t objectsCount) {
+    delete[] const_cast<uint8_t*>(data);
     (void)dataSize;
     LOG_ALWAYS_FATAL_IF(objects != nullptr);
-    LOG_ALWAYS_FATAL_IF(objectsCount != 0, "%zu objects remaining", objectsCount);
+    (void)objectsCount;
 }
 
 status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
                                 const sp<RpcSession>& session, Parcel* reply) {
+    std::vector<std::variant<base::unique_fd, base::borrowed_fd>> ancillaryFds;
     RpcWireHeader command;
     while (true) {
         iovec iov{&command, sizeof(command)};
-        if (status_t status = rpcRec(connection, session, "command header (for reply)", &iov, 1);
+        if (status_t status = rpcRec(connection, session, "command header (for reply)", &iov, 1,
+                                     enableAncillaryFds(session->getFileDescriptorTransportMode())
+                                             ? &ancillaryFds
+                                             : nullptr);
             status != OK)
             return status;
 
         if (command.command == RPC_COMMAND_REPLY) break;
 
-        if (status_t status = processCommand(connection, session, command, CommandType::ANY);
+        if (status_t status = processCommand(connection, session, command, CommandType::ANY,
+                                             std::move(ancillaryFds));
             status != OK)
             return status;
+
+        // Reset to avoid spurious use-after-move warning from clang-tidy.
+        ancillaryFds = decltype(ancillaryFds)();
     }
 
-    CommandData data(command.bodySize);
-    if (!data.valid()) return NO_MEMORY;
+    const size_t rpcReplyWireSize = RpcWireReply::wireSize(session->getProtocolVersion().value());
 
-    iovec iov{data.data(), command.bodySize};
-    if (status_t status = rpcRec(connection, session, "reply body", &iov, 1); status != OK)
-        return status;
-
-    if (command.bodySize < sizeof(RpcWireReply)) {
+    if (command.bodySize < rpcReplyWireSize) {
         ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireReply. Terminating!",
               sizeof(RpcWireReply), command.bodySize);
         (void)session->shutdownAndWait(false);
         return BAD_VALUE;
     }
-    RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data.data());
-    if (rpcReply->status != OK) return rpcReply->status;
+
+    RpcWireReply rpcReply;
+    memset(&rpcReply, 0, sizeof(RpcWireReply)); // zero because of potential short read
+
+    CommandData data(command.bodySize - rpcReplyWireSize);
+    if (!data.valid()) return NO_MEMORY;
+
+    iovec iovs[]{
+            {&rpcReply, rpcReplyWireSize},
+            {data.data(), data.size()},
+    };
+    if (status_t status = rpcRec(connection, session, "reply body", iovs, arraysize(iovs), nullptr);
+        status != OK)
+        return status;
+
+    if (rpcReply.status != OK) return rpcReply.status;
+
+    Span<const uint8_t> parcelSpan = {data.data(), data.size()};
+    Span<const uint32_t> objectTableSpan;
+    if (session->getProtocolVersion().value() >=
+        RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
+        std::optional<Span<const uint8_t>> objectTableBytes =
+                parcelSpan.splitOff(rpcReply.parcelDataSize);
+        if (!objectTableBytes.has_value()) {
+            ALOGE("Parcel size larger than available bytes: %" PRId32 " vs %zu. Terminating!",
+                  rpcReply.parcelDataSize, parcelSpan.byteSize());
+            (void)session->shutdownAndWait(false);
+            return BAD_VALUE;
+        }
+        std::optional<Span<const uint32_t>> maybeSpan =
+                objectTableBytes->reinterpret<const uint32_t>();
+        if (!maybeSpan.has_value()) {
+            ALOGE("Bad object table size inferred from RpcWireReply. Saw bodySize=%" PRId32
+                  " sizeofHeader=%zu parcelSize=%" PRId32 " objectTableBytesSize=%zu. Terminating!",
+                  command.bodySize, rpcReplyWireSize, rpcReply.parcelDataSize,
+                  objectTableBytes->size);
+            return BAD_VALUE;
+        }
+        objectTableSpan = *maybeSpan;
+    }
 
     data.release();
-    reply->ipcSetDataReference(rpcReply->data, command.bodySize - offsetof(RpcWireReply, data),
-                               nullptr, 0, cleanup_reply_data);
-
-    reply->markForRpc(session);
-
-    return OK;
+    return reply->rpcSetDataReference(session, parcelSpan.data, parcelSpan.size,
+                                      objectTableSpan.data, objectTableSpan.size,
+                                      std::move(ancillaryFds), cleanup_reply_data);
 }
 
 status_t RpcState::sendDecStrongToTarget(const sp<RpcSession::RpcConnection>& connection,
@@ -618,7 +703,7 @@
     };
 
     {
-        std::lock_guard<std::mutex> _l(mNodeMutex);
+        RpcMutexLockGuard _l(mNodeMutex);
         if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
         auto it = mNodeForAddress.find(addr);
         LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(),
@@ -643,31 +728,32 @@
             .bodySize = sizeof(RpcDecStrong),
     };
     iovec iovs[]{{&cmd, sizeof(cmd)}, {&body, sizeof(body)}};
-    return rpcSend(connection, session, "dec ref", iovs, arraysize(iovs));
+    return rpcSend(connection, session, "dec ref", iovs, arraysize(iovs), std::nullopt);
 }
 
 status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& connection,
                                         const sp<RpcSession>& session, CommandType type) {
     LOG_RPC_DETAIL("getAndExecuteCommand on RpcTransport %p", connection->rpcTransport.get());
 
+    std::vector<std::variant<base::unique_fd, base::borrowed_fd>> ancillaryFds;
     RpcWireHeader command;
     iovec iov{&command, sizeof(command)};
-    if (status_t status = rpcRec(connection, session, "command header (for server)", &iov, 1);
+    if (status_t status =
+                rpcRec(connection, session, "command header (for server)", &iov, 1,
+                       enableAncillaryFds(session->getFileDescriptorTransportMode()) ? &ancillaryFds
+                                                                                     : nullptr);
         status != OK)
         return status;
 
-    return processCommand(connection, session, command, type);
+    return processCommand(connection, session, command, type, std::move(ancillaryFds));
 }
 
 status_t RpcState::drainCommands(const sp<RpcSession::RpcConnection>& connection,
                                  const sp<RpcSession>& session, CommandType type) {
-    uint8_t buf;
     while (true) {
-        size_t num_bytes;
-        status_t status = connection->rpcTransport->peek(&buf, sizeof(buf), &num_bytes);
+        status_t status = connection->rpcTransport->pollRead();
         if (status == WOULD_BLOCK) break;
         if (status != OK) return status;
-        if (!num_bytes) break;
 
         status = getAndExecuteCommand(connection, session, type);
         if (status != OK) return status;
@@ -675,28 +761,33 @@
     return OK;
 }
 
-status_t RpcState::processCommand(const sp<RpcSession::RpcConnection>& connection,
-                                  const sp<RpcSession>& session, const RpcWireHeader& command,
-                                  CommandType type) {
+status_t RpcState::processCommand(
+        const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+        const RpcWireHeader& command, CommandType type,
+        std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds) {
+#ifdef BINDER_WITH_KERNEL_IPC
     IPCThreadState* kernelBinderState = IPCThreadState::selfOrNull();
     IPCThreadState::SpGuard spGuard{
             .address = __builtin_frame_address(0),
-            .context = "processing binder RPC command",
+            .context = "processing binder RPC command (where RpcServer::setPerSessionRootObject is "
+                       "used to distinguish callers)",
     };
     const IPCThreadState::SpGuard* origGuard;
     if (kernelBinderState != nullptr) {
         origGuard = kernelBinderState->pushGetCallingSpGuard(&spGuard);
     }
-    ScopeGuard guardUnguard = [&]() {
+
+    base::ScopeGuard guardUnguard = [&]() {
         if (kernelBinderState != nullptr) {
             kernelBinderState->restoreGetCallingSpGuard(origGuard);
         }
     };
+#endif // BINDER_WITH_KERNEL_IPC
 
     switch (command.command) {
         case RPC_COMMAND_TRANSACT:
             if (type != CommandType::ANY) return BAD_TYPE;
-            return processTransact(connection, session, command);
+            return processTransact(connection, session, command, std::move(ancillaryFds));
         case RPC_COMMAND_DEC_STRONG:
             return processDecStrong(connection, session, command);
     }
@@ -710,8 +801,10 @@
     (void)session->shutdownAndWait(false);
     return DEAD_OBJECT;
 }
-status_t RpcState::processTransact(const sp<RpcSession::RpcConnection>& connection,
-                                   const sp<RpcSession>& session, const RpcWireHeader& command) {
+status_t RpcState::processTransact(
+        const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+        const RpcWireHeader& command,
+        std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds) {
     LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_TRANSACT, "command: %d", command.command);
 
     CommandData transactionData(command.bodySize);
@@ -719,24 +812,26 @@
         return NO_MEMORY;
     }
     iovec iov{transactionData.data(), transactionData.size()};
-    if (status_t status = rpcRec(connection, session, "transaction body", &iov, 1); status != OK)
+    if (status_t status = rpcRec(connection, session, "transaction body", &iov, 1, nullptr);
+        status != OK)
         return status;
 
-    return processTransactInternal(connection, session, std::move(transactionData));
+    return processTransactInternal(connection, session, std::move(transactionData),
+                                   std::move(ancillaryFds));
 }
 
-static void do_nothing_to_transact_data(Parcel* p, const uint8_t* data, size_t dataSize,
+static void do_nothing_to_transact_data(const uint8_t* data, size_t dataSize,
                                         const binder_size_t* objects, size_t objectsCount) {
-    (void)p;
     (void)data;
     (void)dataSize;
     (void)objects;
     (void)objectsCount;
 }
 
-status_t RpcState::processTransactInternal(const sp<RpcSession::RpcConnection>& connection,
-                                           const sp<RpcSession>& session,
-                                           CommandData transactionData) {
+status_t RpcState::processTransactInternal(
+        const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+        CommandData transactionData,
+        std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds) {
     // for 'recursive' calls to this, we have already read and processed the
     // binder from the transaction data and taken reference counts into account,
     // so it is cached here.
@@ -780,7 +875,7 @@
             (void)session->shutdownAndWait(false);
             replyStatus = BAD_VALUE;
         } else if (oneway) {
-            std::unique_lock<std::mutex> _l(mNodeMutex);
+            RpcMutexUniqueLock _l(mNodeMutex);
             auto it = mNodeForAddress.find(addr);
             if (it->second.binder.promote() != target) {
                 ALOGE("Binder became invalid during transaction. Bad client? %" PRIu64, addr);
@@ -824,54 +919,85 @@
     reply.markForRpc(session);
 
     if (replyStatus == OK) {
+        Span<const uint8_t> parcelSpan = {transaction->data,
+                                          transactionData.size() -
+                                                  offsetof(RpcWireTransaction, data)};
+        Span<const uint32_t> objectTableSpan;
+        if (session->getProtocolVersion().value() >
+            RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
+            std::optional<Span<const uint8_t>> objectTableBytes =
+                    parcelSpan.splitOff(transaction->parcelDataSize);
+            if (!objectTableBytes.has_value()) {
+                ALOGE("Parcel size (%" PRId32 ") greater than available bytes (%zu). Terminating!",
+                      transaction->parcelDataSize, parcelSpan.byteSize());
+                (void)session->shutdownAndWait(false);
+                return BAD_VALUE;
+            }
+            std::optional<Span<const uint32_t>> maybeSpan =
+                    objectTableBytes->reinterpret<const uint32_t>();
+            if (!maybeSpan.has_value()) {
+                ALOGE("Bad object table size inferred from RpcWireTransaction. Saw bodySize=%zu "
+                      "sizeofHeader=%zu parcelSize=%" PRId32
+                      " objectTableBytesSize=%zu. Terminating!",
+                      transactionData.size(), sizeof(RpcWireTransaction),
+                      transaction->parcelDataSize, objectTableBytes->size);
+                return BAD_VALUE;
+            }
+            objectTableSpan = *maybeSpan;
+        }
+
         Parcel data;
         // transaction->data is owned by this function. Parcel borrows this data and
         // only holds onto it for the duration of this function call. Parcel will be
         // deleted before the 'transactionData' object.
-        data.ipcSetDataReference(transaction->data,
-                                 transactionData.size() - offsetof(RpcWireTransaction, data),
-                                 nullptr /*object*/, 0 /*objectCount*/,
-                                 do_nothing_to_transact_data);
-        data.markForRpc(session);
 
-        if (target) {
-            bool origAllowNested = connection->allowNested;
-            connection->allowNested = !oneway;
+        replyStatus =
+                data.rpcSetDataReference(session, parcelSpan.data, parcelSpan.size,
+                                         objectTableSpan.data, objectTableSpan.size,
+                                         std::move(ancillaryFds), do_nothing_to_transact_data);
+        // Reset to avoid spurious use-after-move warning from clang-tidy.
+        ancillaryFds = std::remove_reference<decltype(ancillaryFds)>::type();
 
-            replyStatus = target->transact(transaction->code, data, &reply, transaction->flags);
+        if (replyStatus == OK) {
+            if (target) {
+                bool origAllowNested = connection->allowNested;
+                connection->allowNested = !oneway;
 
-            connection->allowNested = origAllowNested;
-        } else {
-            LOG_RPC_DETAIL("Got special transaction %u", transaction->code);
+                replyStatus = target->transact(transaction->code, data, &reply, transaction->flags);
 
-            switch (transaction->code) {
-                case RPC_SPECIAL_TRANSACT_GET_MAX_THREADS: {
-                    replyStatus = reply.writeInt32(session->getMaxIncomingThreads());
-                    break;
-                }
-                case RPC_SPECIAL_TRANSACT_GET_SESSION_ID: {
-                    // for client connections, this should always report the value
-                    // originally returned from the server, so this is asserting
-                    // that it exists
-                    replyStatus = reply.writeByteVector(session->mId);
-                    break;
-                }
-                default: {
-                    sp<RpcServer> server = session->server();
-                    if (server) {
-                        switch (transaction->code) {
-                            case RPC_SPECIAL_TRANSACT_GET_ROOT: {
-                                sp<IBinder> root = session->mSessionSpecificRootObject
-                                        ?: server->getRootObject();
-                                replyStatus = reply.writeStrongBinder(root);
-                                break;
+                connection->allowNested = origAllowNested;
+            } else {
+                LOG_RPC_DETAIL("Got special transaction %u", transaction->code);
+
+                switch (transaction->code) {
+                    case RPC_SPECIAL_TRANSACT_GET_MAX_THREADS: {
+                        replyStatus = reply.writeInt32(session->getMaxIncomingThreads());
+                        break;
+                    }
+                    case RPC_SPECIAL_TRANSACT_GET_SESSION_ID: {
+                        // for client connections, this should always report the value
+                        // originally returned from the server, so this is asserting
+                        // that it exists
+                        replyStatus = reply.writeByteVector(session->mId);
+                        break;
+                    }
+                    default: {
+                        sp<RpcServer> server = session->server();
+                        if (server) {
+                            switch (transaction->code) {
+                                case RPC_SPECIAL_TRANSACT_GET_ROOT: {
+                                    sp<IBinder> root = session->mSessionSpecificRootObject
+                                            ?: server->getRootObject();
+                                    replyStatus = reply.writeStrongBinder(root);
+                                    break;
+                                }
+                                default: {
+                                    replyStatus = UNKNOWN_TRANSACTION;
+                                }
                             }
-                            default: {
-                                replyStatus = UNKNOWN_TRANSACTION;
-                            }
+                        } else {
+                            ALOGE("Special command sent, but no server object attached.");
                         }
-                    } else {
-                        ALOGE("Special command sent, but no server object attached.");
                     }
                 }
             }
@@ -897,7 +1023,7 @@
         // downside: asynchronous transactions may drown out synchronous
         // transactions.
         {
-            std::unique_lock<std::mutex> _l(mNodeMutex);
+            RpcMutexUniqueLock _l(mNodeMutex);
             auto it = mNodeForAddress.find(addr);
             // last refcount dropped after this transaction happened
             if (it == mNodeForAddress.end()) return OK;
@@ -943,49 +1069,69 @@
         replyStatus = flushExcessBinderRefs(session, addr, target);
     }
 
-    LOG_ALWAYS_FATAL_IF(std::numeric_limits<int32_t>::max() - sizeof(RpcWireHeader) -
-                                        sizeof(RpcWireReply) <
-                                reply.dataSize(),
-                        "Too much data for reply %zu", reply.dataSize());
+    std::string errorMsg;
+    if (status_t status = validateParcel(session, reply, &errorMsg); status != OK) {
+        ALOGE("Reply Parcel failed validation: %s", errorMsg.c_str());
+        // Forward the error to the client of the transaction.
+        reply.freeData();
+        reply.markForRpc(session);
+        replyStatus = status;
+    }
 
+    auto* rpcFields = reply.maybeRpcFields();
+    LOG_ALWAYS_FATAL_IF(rpcFields == nullptr);
+
+    const size_t rpcReplyWireSize = RpcWireReply::wireSize(session->getProtocolVersion().value());
+
+    Span<const uint32_t> objectTableSpan = Span<const uint32_t>{rpcFields->mObjectPositions.data(),
+                                                                rpcFields->mObjectPositions.size()};
+
+    uint32_t bodySize;
+    LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(rpcReplyWireSize, reply.dataSize(), &bodySize) ||
+                                __builtin_add_overflow(objectTableSpan.byteSize(), bodySize,
+                                                       &bodySize),
+                        "Too much data for reply %zu", reply.dataSize());
     RpcWireHeader cmdReply{
             .command = RPC_COMMAND_REPLY,
-            .bodySize = static_cast<uint32_t>(sizeof(RpcWireReply) + reply.dataSize()),
+            .bodySize = bodySize,
     };
     RpcWireReply rpcReply{
             .status = replyStatus,
+            // NOTE: Not necessarily written to socket depending on session
+            // version.
+            // NOTE: bodySize didn't overflow => this cast is safe
+            .parcelDataSize = static_cast<uint32_t>(reply.dataSize()),
+            .reserved = {0, 0, 0},
     };
-
     iovec iovs[]{
             {&cmdReply, sizeof(RpcWireHeader)},
-            {&rpcReply, sizeof(RpcWireReply)},
+            {&rpcReply, rpcReplyWireSize},
             {const_cast<uint8_t*>(reply.data()), reply.dataSize()},
+            objectTableSpan.toIovec(),
     };
-    return rpcSend(connection, session, "reply", iovs, arraysize(iovs));
+    return rpcSend(connection, session, "reply", iovs, arraysize(iovs), std::nullopt,
+                   rpcFields->mFds.get());
 }
 
 status_t RpcState::processDecStrong(const sp<RpcSession::RpcConnection>& connection,
                                     const sp<RpcSession>& session, const RpcWireHeader& command) {
     LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_DEC_STRONG, "command: %d", command.command);
 
-    CommandData commandData(command.bodySize);
-    if (!commandData.valid()) {
-        return NO_MEMORY;
-    }
-    iovec iov{commandData.data(), commandData.size()};
-    if (status_t status = rpcRec(connection, session, "dec ref body", &iov, 1); status != OK)
-        return status;
-
     if (command.bodySize != sizeof(RpcDecStrong)) {
         ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcDecStrong. Terminating!",
               sizeof(RpcDecStrong), command.bodySize);
         (void)session->shutdownAndWait(false);
         return BAD_VALUE;
     }
-    RpcDecStrong* body = reinterpret_cast<RpcDecStrong*>(commandData.data());
 
-    uint64_t addr = RpcWireAddress::toRaw(body->address);
-    std::unique_lock<std::mutex> _l(mNodeMutex);
+    RpcDecStrong body;
+    iovec iov{&body, sizeof(RpcDecStrong)};
+    if (status_t status = rpcRec(connection, session, "dec ref body", &iov, 1, nullptr);
+        status != OK)
+        return status;
+
+    uint64_t addr = RpcWireAddress::toRaw(body.address);
+    RpcMutexUniqueLock _l(mNodeMutex);
     auto it = mNodeForAddress.find(addr);
     if (it == mNodeForAddress.end()) {
         ALOGE("Unknown binder address %" PRIu64 " for dec strong.", addr);
@@ -1002,19 +1148,19 @@
         return BAD_VALUE;
     }
 
-    if (it->second.timesSent < body->amount) {
+    if (it->second.timesSent < body.amount) {
         ALOGE("Record of sending binder %zu times, but requested decStrong for %" PRIu64 " of %u",
-              it->second.timesSent, addr, body->amount);
+              it->second.timesSent, addr, body.amount);
         return OK;
     }
 
     LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %" PRIu64,
                         addr);
 
-    LOG_RPC_DETAIL("Processing dec strong of %" PRIu64 " by %u from %zu", addr, body->amount,
+    LOG_RPC_DETAIL("Processing dec strong of %" PRIu64 " by %u from %zu", addr, body.amount,
                    it->second.timesSent);
 
-    it->second.timesSent -= body->amount;
+    it->second.timesSent -= body.amount;
     sp<IBinder> tempHold = tryEraseNode(it);
     _l.unlock();
     tempHold = nullptr; // destructor may make binder calls on this session
@@ -1022,6 +1168,50 @@
     return OK;
 }
 
+status_t RpcState::validateParcel(const sp<RpcSession>& session, const Parcel& parcel,
+                                  std::string* errorMsg) {
+    auto* rpcFields = parcel.maybeRpcFields();
+    if (rpcFields == nullptr) {
+        *errorMsg = "Parcel not crafted for RPC call";
+        return BAD_TYPE;
+    }
+
+    if (rpcFields->mSession != session) {
+        *errorMsg = "Parcel's session doesn't match";
+        return BAD_TYPE;
+    }
+
+    uint32_t protocolVersion = session->getProtocolVersion().value();
+    if (protocolVersion < RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE &&
+        !rpcFields->mObjectPositions.empty()) {
+        *errorMsg = StringPrintf("Parcel has attached objects but the session's protocol version "
+                                 "(%" PRIu32 ") is too old, must be at least %" PRIu32,
+                                 protocolVersion,
+                                 RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE);
+        return BAD_VALUE;
+    }
+
+    if (rpcFields->mFds && !rpcFields->mFds->empty()) {
+        switch (session->getFileDescriptorTransportMode()) {
+            case RpcSession::FileDescriptorTransportMode::NONE:
+                *errorMsg =
+                        "Parcel has file descriptors, but no file descriptor transport is enabled";
+                return FDS_NOT_ALLOWED;
+            case RpcSession::FileDescriptorTransportMode::UNIX: {
+                constexpr size_t kMaxFdsPerMsg = 253;
+                if (rpcFields->mFds->size() > kMaxFdsPerMsg) {
+                    *errorMsg = StringPrintf("Too many file descriptors in Parcel for unix "
+                                             "domain socket: %zu (max is %zu)",
+                                             rpcFields->mFds->size(), kMaxFdsPerMsg);
+                    return BAD_VALUE;
+                }
+            }
+        }
+    }
+
+    return OK;
+}
+
 sp<IBinder> RpcState::tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it) {
     sp<IBinder> ref;
 
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index f4a0894..7aab5ee 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -19,6 +19,7 @@
 #include <binder/IBinder.h>
 #include <binder/Parcel.h>
 #include <binder/RpcSession.h>
+#include <binder/RpcThreads.h>
 
 #include <map>
 #include <optional>
@@ -139,6 +140,11 @@
      */
     [[nodiscard]] status_t flushExcessBinderRefs(const sp<RpcSession>& session, uint64_t address,
                                                  const sp<IBinder>& binder);
+    /**
+     * Called when the RpcSession is shutdown.
+     * Send obituaries for each known remote binder with this session.
+     */
+    [[nodiscard]] status_t sendObituaries(const sp<RpcSession>& session);
 
     size_t countBinders();
     void dump();
@@ -178,28 +184,39 @@
         size_t mSize;
     };
 
-    [[nodiscard]] status_t rpcSend(const sp<RpcSession::RpcConnection>& connection,
-                                   const sp<RpcSession>& session, const char* what, iovec* iovs,
-                                   int niovs, const std::function<status_t()>& altPoll = nullptr);
-    [[nodiscard]] status_t rpcRec(const sp<RpcSession::RpcConnection>& connection,
-                                  const sp<RpcSession>& session, const char* what, iovec* iovs,
-                                  int niovs);
+    [[nodiscard]] status_t rpcSend(
+            const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+            const char* what, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds =
+                    nullptr);
+    [[nodiscard]] status_t rpcRec(
+            const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+            const char* what, iovec* iovs, int niovs,
+            std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds = nullptr);
 
     [[nodiscard]] status_t waitForReply(const sp<RpcSession::RpcConnection>& connection,
                                         const sp<RpcSession>& session, Parcel* reply);
-    [[nodiscard]] status_t processCommand(const sp<RpcSession::RpcConnection>& connection,
-                                          const sp<RpcSession>& session,
-                                          const RpcWireHeader& command, CommandType type);
-    [[nodiscard]] status_t processTransact(const sp<RpcSession::RpcConnection>& connection,
-                                           const sp<RpcSession>& session,
-                                           const RpcWireHeader& command);
-    [[nodiscard]] status_t processTransactInternal(const sp<RpcSession::RpcConnection>& connection,
-                                                   const sp<RpcSession>& session,
-                                                   CommandData transactionData);
+    [[nodiscard]] status_t processCommand(
+            const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+            const RpcWireHeader& command, CommandType type,
+            std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds);
+    [[nodiscard]] status_t processTransact(
+            const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+            const RpcWireHeader& command,
+            std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds);
+    [[nodiscard]] status_t processTransactInternal(
+            const sp<RpcSession::RpcConnection>& connection, const sp<RpcSession>& session,
+            CommandData transactionData,
+            std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds);
     [[nodiscard]] status_t processDecStrong(const sp<RpcSession::RpcConnection>& connection,
                                             const sp<RpcSession>& session,
                                             const RpcWireHeader& command);
 
+    // Whether `parcel` is compatible with `session`.
+    [[nodiscard]] static status_t validateParcel(const sp<RpcSession>& session,
+                                                 const Parcel& parcel, std::string* errorMsg);
+
     struct BinderNode {
         // Two cases:
         // A - local binder we are serving
@@ -246,6 +263,8 @@
         //
 
         // (no additional data specific to remote binders)
+
+        std::string toString() const;
     };
 
     // checks if there is any reference left to a node and erases it. If erase
@@ -257,7 +276,7 @@
     // false - session shutdown, halt
     [[nodiscard]] bool nodeProgressAsyncNumber(BinderNode* node);
 
-    std::mutex mNodeMutex;
+    RpcMutex mNodeMutex;
     bool mTerminated = false;
     uint32_t mNextId = 0;
     // binders known by both sides of a session
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 7cfc780..51326f6 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -18,137 +18,163 @@
 #include <log/log.h>
 
 #include <poll.h>
+#include <stddef.h>
 
 #include <binder/RpcTransportRaw.h>
 
 #include "FdTrigger.h"
 #include "RpcState.h"
+#include "RpcTransportUtils.h"
 
 namespace android {
 
 namespace {
 
+// Linux kernel supports up to 253 (from SCM_MAX_FD) for unix sockets.
+constexpr size_t kMaxFdsPerMsg = 253;
+
 // RpcTransport with TLS disabled.
 class RpcTransportRaw : public RpcTransport {
 public:
     explicit RpcTransportRaw(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
-    status_t peek(void* buf, size_t size, size_t* out_size) override {
-        ssize_t ret = TEMP_FAILURE_RETRY(::recv(mSocket.get(), buf, size, MSG_PEEK));
+    status_t pollRead(void) override {
+        uint8_t buf;
+        ssize_t ret = TEMP_FAILURE_RETRY(
+                ::recv(mSocket.get(), &buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT));
         if (ret < 0) {
             int savedErrno = errno;
             if (savedErrno == EAGAIN || savedErrno == EWOULDBLOCK) {
                 return WOULD_BLOCK;
             }
 
-            LOG_RPC_DETAIL("RpcTransport peek(): %s", strerror(savedErrno));
+            LOG_RPC_DETAIL("RpcTransport poll(): %s", strerror(savedErrno));
             return -savedErrno;
-        }
-
-        *out_size = static_cast<size_t>(ret);
-        return OK;
-    }
-
-    template <typename SendOrReceive>
-    status_t interruptableReadOrWrite(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                      SendOrReceive sendOrReceiveFun, const char* funName,
-                                      int16_t event, const std::function<status_t()>& altPoll) {
-        MAYBE_WAIT_IN_FLAKE_MODE;
-
-        if (niovs < 0) {
-            return BAD_VALUE;
-        }
-
-        // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
-        // may never know we should be shutting down.
-        if (fdTrigger->isTriggered()) {
+        } else if (ret == 0) {
             return DEAD_OBJECT;
         }
 
-        // If iovs has one or more empty vectors at the end and
-        // we somehow advance past all the preceding vectors and
-        // pass some or all of the empty ones to sendmsg/recvmsg,
-        // the call will return processSize == 0. In that case
-        // we should be returning OK but instead return DEAD_OBJECT.
-        // To avoid this problem, we make sure here that the last
-        // vector at iovs[niovs - 1] has a non-zero length.
-        while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
-            niovs--;
-        }
-        if (niovs == 0) {
-            // The vectors are all empty, so we have nothing to send.
-            return OK;
-        }
+        return OK;
+    }
 
-        bool havePolled = false;
-        while (true) {
+    status_t interruptableWriteFully(
+            FdTrigger* fdTrigger, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
+            override {
+        bool sentFds = false;
+        auto send = [&](iovec* iovs, int niovs) -> ssize_t {
+            if (ancillaryFds != nullptr && !ancillaryFds->empty() && !sentFds) {
+                if (ancillaryFds->size() > kMaxFdsPerMsg) {
+                    // This shouldn't happen because we check the FD count in RpcState.
+                    ALOGE("Saw too many file descriptors in RpcTransportCtxRaw: %zu (max is %zu). "
+                          "Aborting session.",
+                          ancillaryFds->size(), kMaxFdsPerMsg);
+                    errno = EINVAL;
+                    return -1;
+                }
+
+                // CMSG_DATA is not necessarily aligned, so we copy the FDs into a buffer and then
+                // use memcpy.
+                int fds[kMaxFdsPerMsg];
+                for (size_t i = 0; i < ancillaryFds->size(); i++) {
+                    fds[i] = std::visit([](const auto& fd) { return fd.get(); },
+                                        ancillaryFds->at(i));
+                }
+                const size_t fdsByteSize = sizeof(int) * ancillaryFds->size();
+
+                alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(int) * kMaxFdsPerMsg)];
+
+                msghdr msg{
+                        .msg_iov = iovs,
+                        .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+                        .msg_control = msgControlBuf,
+                        .msg_controllen = sizeof(msgControlBuf),
+                };
+
+                cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+                cmsg->cmsg_level = SOL_SOCKET;
+                cmsg->cmsg_type = SCM_RIGHTS;
+                cmsg->cmsg_len = CMSG_LEN(fdsByteSize);
+                memcpy(CMSG_DATA(cmsg), fds, fdsByteSize);
+
+                msg.msg_controllen = CMSG_SPACE(fdsByteSize);
+
+                ssize_t processedSize = TEMP_FAILURE_RETRY(
+                        sendmsg(mSocket.get(), &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC));
+                if (processedSize > 0) {
+                    sentFds = true;
+                }
+                return processedSize;
+            }
+
             msghdr msg{
                     .msg_iov = iovs,
                     // posix uses int, glibc uses size_t.  niovs is a
                     // non-negative int and can be cast to either.
                     .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
             };
-            ssize_t processSize =
-                    TEMP_FAILURE_RETRY(sendOrReceiveFun(mSocket.get(), &msg, MSG_NOSIGNAL));
+            return TEMP_FAILURE_RETRY(sendmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
+        };
+        return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, send, "sendmsg",
+                                        POLLOUT, altPoll);
+    }
 
-            if (processSize < 0) {
-                int savedErrno = errno;
+    status_t interruptableReadFully(
+            FdTrigger* fdTrigger, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override {
+        auto recv = [&](iovec* iovs, int niovs) -> ssize_t {
+            if (ancillaryFds != nullptr) {
+                int fdBuffer[kMaxFdsPerMsg];
+                alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(fdBuffer))];
 
-                // Still return the error on later passes, since it would expose
-                // a problem with polling
-                if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
-                    LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
-                    return -savedErrno;
+                msghdr msg{
+                        .msg_iov = iovs,
+                        .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+                        .msg_control = msgControlBuf,
+                        .msg_controllen = sizeof(msgControlBuf),
+                };
+                ssize_t processSize =
+                        TEMP_FAILURE_RETRY(recvmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
+                if (processSize < 0) {
+                    return -1;
                 }
-            } else if (processSize == 0) {
-                return DEAD_OBJECT;
-            } else {
-                while (processSize > 0 && niovs > 0) {
-                    auto& iov = iovs[0];
-                    if (static_cast<size_t>(processSize) < iov.iov_len) {
-                        // Advance the base of the current iovec
-                        iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
-                        iov.iov_len -= processSize;
+
+                for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr;
+                     cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+                    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+                        // NOTE: It is tempting to reinterpret_cast, but cmsg(3) explicitly asks
+                        // application devs to memcpy the data to ensure memory alignment.
+                        size_t dataLen = cmsg->cmsg_len - CMSG_LEN(0);
+                        LOG_ALWAYS_FATAL_IF(dataLen > sizeof(fdBuffer)); // sanity check
+                        memcpy(fdBuffer, CMSG_DATA(cmsg), dataLen);
+                        size_t fdCount = dataLen / sizeof(int);
+                        ancillaryFds->reserve(ancillaryFds->size() + fdCount);
+                        for (size_t i = 0; i < fdCount; i++) {
+                            ancillaryFds->emplace_back(base::unique_fd(fdBuffer[i]));
+                        }
                         break;
                     }
+                }
 
-                    // The current iovec was fully written
-                    processSize -= iov.iov_len;
-                    iovs++;
-                    niovs--;
+                if (msg.msg_flags & MSG_CTRUNC) {
+                    ALOGE("msg was truncated. Aborting session.");
+                    errno = EPIPE;
+                    return -1;
                 }
-                if (niovs == 0) {
-                    LOG_ALWAYS_FATAL_IF(processSize > 0,
-                                        "Reached the end of iovecs "
-                                        "with %zd bytes remaining",
-                                        processSize);
-                    return OK;
-                }
+
+                return processSize;
             }
-
-            if (altPoll) {
-                if (status_t status = altPoll(); status != OK) return status;
-                if (fdTrigger->isTriggered()) {
-                    return DEAD_OBJECT;
-                }
-            } else {
-                if (status_t status = fdTrigger->triggerablePoll(mSocket.get(), event);
-                    status != OK)
-                    return status;
-                if (!havePolled) havePolled = true;
-            }
-        }
-    }
-
-    status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                     const std::function<status_t()>& altPoll) override {
-        return interruptableReadOrWrite(fdTrigger, iovs, niovs, sendmsg, "sendmsg", POLLOUT,
-                                        altPoll);
-    }
-
-    status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                    const std::function<status_t()>& altPoll) override {
-        return interruptableReadOrWrite(fdTrigger, iovs, niovs, recvmsg, "recvmsg", POLLIN,
-                                        altPoll);
+            msghdr msg{
+                    .msg_iov = iovs,
+                    // posix uses int, glibc uses size_t.  niovs is a
+                    // non-negative int and can be cast to either.
+                    .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+            };
+            return TEMP_FAILURE_RETRY(recvmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
+        };
+        return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, recv, "recvmsg",
+                                        POLLIN, altPoll);
     }
 
 private:
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index bc68c37..09b5c17 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -181,9 +181,10 @@
     // |sslError| should be from Ssl::getError().
     // If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
     // return error. Also return error if |fdTrigger| is triggered before or during poll().
-    status_t pollForSslError(android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger,
-                             const char* fnString, int additionalEvent,
-                             const std::function<status_t()>& altPoll) {
+    status_t pollForSslError(
+            android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger, const char* fnString,
+            int additionalEvent,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll) {
         switch (sslError) {
             case SSL_ERROR_WANT_READ:
                 return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString, altPoll);
@@ -198,10 +199,11 @@
     bool mHandled = false;
 
     status_t handlePoll(int event, android::base::borrowed_fd fd, FdTrigger* fdTrigger,
-                        const char* fnString, const std::function<status_t()>& altPoll) {
+                        const char* fnString,
+                        const std::optional<android::base::function_ref<status_t()>>& altPoll) {
         status_t ret;
         if (altPoll) {
-            ret = altPoll();
+            ret = (*altPoll)();
             if (fdTrigger->isTriggered()) ret = DEAD_OBJECT;
         } else {
             ret = fdTrigger->triggerablePoll(fd, event);
@@ -277,11 +279,16 @@
 public:
     RpcTransportTls(android::base::unique_fd socket, Ssl ssl)
           : mSocket(std::move(socket)), mSsl(std::move(ssl)) {}
-    status_t peek(void* buf, size_t size, size_t* out_size) override;
-    status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                     const std::function<status_t()>& altPoll) override;
-    status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                    const std::function<status_t()>& altPoll) override;
+    status_t pollRead(void) override;
+    status_t interruptableWriteFully(
+            FdTrigger* fdTrigger, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
+            override;
+    status_t interruptableReadFully(
+            FdTrigger* fdTrigger, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override;
 
 private:
     android::base::unique_fd mSocket;
@@ -289,9 +296,9 @@
 };
 
 // Error code is errno.
-status_t RpcTransportTls::peek(void* buf, size_t size, size_t* out_size) {
-    size_t todo = std::min<size_t>(size, std::numeric_limits<int>::max());
-    auto [ret, errorQueue] = mSsl.call(SSL_peek, buf, static_cast<int>(todo));
+status_t RpcTransportTls::pollRead(void) {
+    uint8_t buf;
+    auto [ret, errorQueue] = mSsl.call(SSL_peek, &buf, sizeof(buf));
     if (ret < 0) {
         int err = mSsl.getError(ret);
         if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
@@ -304,12 +311,15 @@
     }
     errorQueue.clear();
     LOG_TLS_DETAIL("TLS: Peeked %d bytes!", ret);
-    *out_size = static_cast<size_t>(ret);
     return OK;
 }
 
-status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                                  const std::function<status_t()>& altPoll) {
+status_t RpcTransportTls::interruptableWriteFully(
+        FdTrigger* fdTrigger, iovec* iovs, int niovs,
+        const std::optional<android::base::function_ref<status_t()>>& altPoll,
+        const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
+    (void)ancillaryFds;
+
     MAYBE_WAIT_IN_FLAKE_MODE;
 
     if (niovs < 0) return BAD_VALUE;
@@ -350,8 +360,12 @@
     return OK;
 }
 
-status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
-                                                 const std::function<status_t()>& altPoll) {
+status_t RpcTransportTls::interruptableReadFully(
+        FdTrigger* fdTrigger, iovec* iovs, int niovs,
+        const std::optional<android::base::function_ref<status_t()>>& altPoll,
+        std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) {
+    (void)ancillaryFds;
+
     MAYBE_WAIT_IN_FLAKE_MODE;
 
     if (niovs < 0) return BAD_VALUE;
@@ -416,8 +430,8 @@
             return false;
         }
         int sslError = ssl->getError(ret);
-        status_t pollStatus =
-                errorQueue.pollForSslError(fd, sslError, fdTrigger, "SSL_do_handshake", 0, {});
+        status_t pollStatus = errorQueue.pollForSslError(fd, sslError, fdTrigger,
+                                                         "SSL_do_handshake", 0, std::nullopt);
         if (pollStatus != OK) return false;
     }
 }
diff --git a/libs/binder/RpcTransportUtils.h b/libs/binder/RpcTransportUtils.h
new file mode 100644
index 0000000..00cb2af
--- /dev/null
+++ b/libs/binder/RpcTransportUtils.h
@@ -0,0 +1,109 @@
+/*
+ * 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 <android-base/unique_fd.h>
+#include <poll.h>
+
+#include "FdTrigger.h"
+#include "RpcState.h"
+
+namespace android {
+
+template <typename SendOrReceive>
+status_t interruptableReadOrWrite(
+        int socketFd, FdTrigger* fdTrigger, iovec* iovs, int niovs, SendOrReceive sendOrReceiveFun,
+        const char* funName, int16_t event,
+        const std::optional<android::base::function_ref<status_t()>>& altPoll) {
+    MAYBE_WAIT_IN_FLAKE_MODE;
+
+    if (niovs < 0) {
+        return BAD_VALUE;
+    }
+
+    // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
+    // may never know we should be shutting down.
+    if (fdTrigger->isTriggered()) {
+        return DEAD_OBJECT;
+    }
+
+    // If iovs has one or more empty vectors at the end and
+    // we somehow advance past all the preceding vectors and
+    // pass some or all of the empty ones to sendmsg/recvmsg,
+    // the call will return processSize == 0. In that case
+    // we should be returning OK but instead return DEAD_OBJECT.
+    // To avoid this problem, we make sure here that the last
+    // vector at iovs[niovs - 1] has a non-zero length.
+    while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
+        niovs--;
+    }
+    if (niovs == 0) {
+        // The vectors are all empty, so we have nothing to send.
+        return OK;
+    }
+
+    bool havePolled = false;
+    while (true) {
+        ssize_t processSize = sendOrReceiveFun(iovs, niovs);
+        if (processSize < 0) {
+            int savedErrno = errno;
+
+            // Still return the error on later passes, since it would expose
+            // a problem with polling
+            if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
+                LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
+                return -savedErrno;
+            }
+        } else if (processSize == 0) {
+            return DEAD_OBJECT;
+        } else {
+            while (processSize > 0 && niovs > 0) {
+                auto& iov = iovs[0];
+                if (static_cast<size_t>(processSize) < iov.iov_len) {
+                    // Advance the base of the current iovec
+                    iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
+                    iov.iov_len -= processSize;
+                    break;
+                }
+
+                // The current iovec was fully written
+                processSize -= iov.iov_len;
+                iovs++;
+                niovs--;
+            }
+            if (niovs == 0) {
+                LOG_ALWAYS_FATAL_IF(processSize > 0,
+                                    "Reached the end of iovecs "
+                                    "with %zd bytes remaining",
+                                    processSize);
+                return OK;
+            }
+        }
+
+        if (altPoll) {
+            if (status_t status = (*altPoll)(); status != OK) return status;
+            if (fdTrigger->isTriggered()) {
+                return DEAD_OBJECT;
+            }
+        } else {
+            if (status_t status = fdTrigger->triggerablePoll(socketFd, event); status != OK)
+                return status;
+            if (!havePolled) havePolled = true;
+        }
+    }
+}
+
+} // namespace android
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index 171550e..ff1b01a 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -45,7 +45,8 @@
 struct RpcConnectionHeader {
     uint32_t version; // maximum supported by caller
     uint8_t options;
-    uint8_t reservered[9];
+    uint8_t fileDescriptorTransportMode;
+    uint8_t reservered[8];
     // Follows is sessionIdSize bytes.
     // if size is 0, this is requesting a new session.
     uint16_t sessionIdSize;
@@ -108,6 +109,10 @@
 
 // serialization is like:
 // |RpcWireHeader|struct desginated by 'command'| (over and over again)
+//
+// When file descriptors are included in out-of-band data (e.g. in unix domain
+// sockets), they are always paired with the RpcWireHeader bytes of the
+// transaction or reply the file descriptors belong to.
 
 struct RpcWireHeader {
     uint32_t command; // RPC_COMMAND_*
@@ -131,7 +136,10 @@
 
     uint64_t asyncNumber;
 
-    uint32_t reserved[4];
+    // The size of the Parcel data directly following RpcWireTransaction.
+    uint32_t parcelDataSize;
+
+    uint32_t reserved[3];
 
     uint8_t data[];
 };
@@ -139,9 +147,23 @@
 
 struct RpcWireReply {
     int32_t status; // transact return
-    uint8_t data[];
+
+    // -- Fields below only transmitted starting at protocol version 1 --
+
+    // The size of the Parcel data directly following RpcWireReply.
+    uint32_t parcelDataSize;
+
+    uint32_t reserved[3];
+
+    // Byte size of RpcWireReply in the wire protocol.
+    static size_t wireSize(uint32_t protocolVersion) {
+        if (protocolVersion == 0) {
+            return sizeof(int32_t);
+        }
+        return sizeof(RpcWireReply);
+    }
 };
-static_assert(sizeof(RpcWireReply) == 4);
+static_assert(sizeof(RpcWireReply) == 20);
 
 #pragma clang diagnostic pop
 
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index 83b97d0..dba6587 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -139,6 +139,9 @@
     mMessage = String8(message.value_or(String16()));
 
     // Skip over the remote stack trace data
+    const size_t remote_start = parcel.dataPosition();
+    // Get available size before reading more
+    const size_t remote_avail = parcel.dataAvail();
     int32_t remote_stack_trace_header_size;
     status = parcel.readInt32(&remote_stack_trace_header_size);
     if (status != OK) {
@@ -146,13 +149,16 @@
         return status;
     }
     if (remote_stack_trace_header_size < 0 ||
-        static_cast<size_t>(remote_stack_trace_header_size) > parcel.dataAvail()) {
+        static_cast<size_t>(remote_stack_trace_header_size) > remote_avail) {
 
         android_errorWriteLog(0x534e4554, "132650049");
         setFromStatusT(UNKNOWN_ERROR);
         return UNKNOWN_ERROR;
     }
-    parcel.setDataPosition(parcel.dataPosition() + remote_stack_trace_header_size);
+
+    if (remote_stack_trace_header_size != 0) {
+        parcel.setDataPosition(remote_start + remote_stack_trace_header_size);
+    }
 
     if (mException == EX_SERVICE_SPECIFIC) {
         status = parcel.readInt32(&mErrorCode);
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index ebb0d27..c91d56c 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -28,9 +28,6 @@
       "name": "binderLibTest"
     },
     {
-      "name": "binderRpcTest"
-    },
-    {
       "name": "binderStabilityTest"
     },
     {
@@ -83,5 +80,24 @@
     {
       "name": "rustBinderSerializationTest"
     }
+  ],
+  "presubmit-large": [
+    {
+      "name": "binderRpcTest"
+    },
+    {
+      "name": "binderRpcTestNoKernel"
+    },
+    {
+      "name": "binderRpcTestSingleThreaded"
+    },
+    {
+      "name": "binderRpcTestSingleThreadedNoKernel"
+    }
+  ],
+  "hwasan-presubmit": [
+    {
+      "name": "binderLibTest"
+    }
   ]
 }
diff --git a/libs/binder/Utils.cpp b/libs/binder/Utils.cpp
index d2a5be1..0314b0f 100644
--- a/libs/binder/Utils.cpp
+++ b/libs/binder/Utils.cpp
@@ -18,24 +18,10 @@
 
 #include <string.h>
 
-using android::base::ErrnoError;
-using android::base::Result;
-
 namespace android {
 
 void zeroMemory(uint8_t* data, size_t size) {
     memset(data, 0, size);
 }
 
-Result<void> setNonBlocking(android::base::borrowed_fd fd) {
-    int flags = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_GETFL));
-    if (flags == -1) {
-        return ErrnoError() << "Could not get flags for fd";
-    }
-    if (int ret = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_SETFL, flags | O_NONBLOCK)); ret == -1) {
-        return ErrnoError() << "Could not set non-blocking flag for fd";
-    }
-    return {};
-}
-
 } // namespace android
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index ff2fad8..e04199c 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-#include <cstdint>
 #include <stddef.h>
+#include <sys/uio.h>
+#include <cstdint>
+#include <optional>
 
-#include <android-base/result.h>
-#include <android-base/unique_fd.h>
 #include <log/log.h>
+#include <utils/Errors.h>
 
 #define TEST_AND_RETURN(value, expr)            \
     do {                                        \
@@ -34,6 +35,39 @@
 // avoid optimizations
 void zeroMemory(uint8_t* data, size_t size);
 
-android::base::Result<void> setNonBlocking(android::base::borrowed_fd fd);
+// View of contiguous sequence. Similar to std::span.
+template <typename T>
+struct Span {
+    T* data = nullptr;
+    size_t size = 0;
+
+    size_t byteSize() { return size * sizeof(T); }
+
+    iovec toIovec() { return {const_cast<std::remove_const_t<T>*>(data), byteSize()}; }
+
+    // Truncates `this` to a length of `offset` and returns a span with the
+    // remainder.
+    //
+    // `std::nullopt` iff offset > size.
+    std::optional<Span<T>> splitOff(size_t offset) {
+        if (offset > size) {
+            return std::nullopt;
+        }
+        Span<T> rest = {data + offset, size - offset};
+        size = offset;
+        return rest;
+    }
+
+    // Returns nullopt if the byte size of `this` isn't evenly divisible by sizeof(U).
+    template <typename U>
+    std::optional<Span<U>> reinterpret() const {
+        // Only allow casting from bytes for simplicity.
+        static_assert(std::is_same_v<std::remove_const_t<T>, uint8_t>);
+        if (size % sizeof(U) != 0) {
+            return std::nullopt;
+        }
+        return Span<U>{reinterpret_cast<U*>(data), size / sizeof(U)};
+    }
+};
 
 }   // namespace android
diff --git a/libs/binder/binder_module.h b/libs/binder/binder_module.h
index 793795e..7574c29 100644
--- a/libs/binder/binder_module.h
+++ b/libs/binder/binder_module.h
@@ -100,4 +100,23 @@
 #define BINDER_ENABLE_ONEWAY_SPAM_DETECTION _IOW('b', 16, __u32)
 #endif // BINDER_ENABLE_ONEWAY_SPAM_DETECTION
 
+#ifndef BINDER_GET_EXTENDED_ERROR
+/* struct binder_extened_error - extended error information
+ * @id:      identifier for the failed operation
+ * @command: command as defined by binder_driver_return_protocol
+ * @param:   parameter holding a negative errno value
+ *
+ * Used with BINDER_GET_EXTENDED_ERROR. This extends the error information
+ * returned by the driver upon a failed operation. Userspace can pull this
+ * data to properly handle specific error scenarios.
+ */
+struct binder_extended_error {
+    __u32 id;
+    __u32 command;
+    __s32 param;
+};
+
+#define BINDER_GET_EXTENDED_ERROR _IOWR('b', 17, struct binder_extended_error)
+#endif // BINDER_GET_EXTENDED_ERROR
+
 #endif // _BINDER_MODULE_H_
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 1576c94..dc572ac 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -72,9 +72,9 @@
 public:
     virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
     virtual const String16&     getInterfaceDescriptor() const;
+    typedef INTERFACE BaseInterface;
 
 protected:
-    typedef INTERFACE           BaseInterface;
     virtual IBinder*            onAsBinder();
 };
 
@@ -85,9 +85,9 @@
 {
 public:
     explicit                    BpInterface(const sp<IBinder>& remote);
+    typedef INTERFACE BaseInterface;
 
 protected:
-    typedef INTERFACE           BaseInterface;
     virtual IBinder*            onAsBinder();
 };
 
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index bf02099..c01e92f 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -28,6 +28,10 @@
 // ---------------------------------------------------------------------------
 namespace android {
 
+/**
+ * Kernel binder thread state. All operations here refer to kernel binder. This
+ * object is allocated per-thread.
+ */
 class IPCThreadState
 {
 public:
@@ -213,9 +217,9 @@
             void                clearCaller();
 
     static  void                threadDestructor(void *st);
-    static  void                freeBuffer(Parcel* parcel,
-                                           const uint8_t* data, size_t dataSize,
-                                           const binder_size_t* objects, size_t objectsSize);
+    static void freeBuffer(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
+                           size_t objectsSize);
+    static  void                logExtendedError();
 
     const   sp<ProcessState>    mProcess;
             Vector<BBinder*>    mPendingStrongDerefs;
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index bb55831..413c97f 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -134,6 +134,12 @@
 
     virtual status_t unregisterForNotifications(const String16& name,
                                                 const sp<LocalRegistrationCallback>& callback) = 0;
+
+    struct ServiceDebugInfo {
+        std::string name;
+        int pid;
+    };
+    virtual std::vector<ServiceDebugInfo> getServiceDebugInfo() = 0;
 };
 
 sp<IServiceManager> defaultServiceManager();
diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
index 15dd28f..c7177bd 100644
--- a/libs/binder/include/binder/MemoryHeapBase.h
+++ b/libs/binder/include/binder/MemoryHeapBase.h
@@ -26,9 +26,10 @@
 
 // ---------------------------------------------------------------------------
 
-class MemoryHeapBase : public virtual BnMemoryHeap
+class MemoryHeapBase : public BnMemoryHeap
 {
 public:
+    static constexpr auto MEMFD_ALLOW_SEALING_FLAG = 0x00000800;
     enum {
         READ_ONLY = IMemoryHeap::READ_ONLY,
         // memory won't be mapped locally, but will be mapped in the remote
@@ -48,7 +49,7 @@
         // Clients of shared files can seal at anytime via syscall, leading to
         // TOC/TOU issues if additional seals prevent access from the creating
         // process. Alternatively, seccomp fcntl().
-        MEMFD_ALLOW_SEALING = 0x00000800
+        MEMFD_ALLOW_SEALING = FORCE_MEMFD | MEMFD_ALLOW_SEALING_FLAG
     };
 
     /*
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index e2b2c51..5469239 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -20,6 +20,7 @@
 #include <map> // for legacy reasons
 #include <string>
 #include <type_traits>
+#include <variant>
 #include <vector>
 
 #include <android-base/unique_fd.h>
@@ -76,6 +77,11 @@
     size_t              dataCapacity() const;
 
     status_t            setDataSize(size_t size);
+
+    // this must only be used to set a data position that was previously returned from
+    // dataPosition(). If writes are made, the exact same types of writes must be made (e.g.
+    // auto i = p.dataPosition(); p.writeInt32(0); p.setDataPosition(i); p.writeInt32(1);).
+    // Writing over objects, such as file descriptors and binders, is not supported.
     void                setDataPosition(size_t pos) const;
     status_t            setDataCapacity(size_t size);
 
@@ -592,24 +598,33 @@
     void                print(TextOutput& to, uint32_t flags = 0) const;
 
 private:
-    typedef void        (*release_func)(Parcel* parcel,
-                                        const uint8_t* data, size_t dataSize,
-                                        const binder_size_t* objects, size_t objectsSize);
+    // `objects` and `objectsSize` always 0 for RPC Parcels.
+    typedef void (*release_func)(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
+                                 size_t objectsSize);
 
     uintptr_t           ipcData() const;
     size_t              ipcDataSize() const;
     uintptr_t           ipcObjects() const;
     size_t              ipcObjectsCount() const;
-    void                ipcSetDataReference(const uint8_t* data, size_t dataSize,
-                                            const binder_size_t* objects, size_t objectsCount,
-                                            release_func relFunc);
+    void ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
+                             size_t objectsCount, release_func relFunc);
+    // Takes ownership even when an error is returned.
+    status_t rpcSetDataReference(
+            const sp<RpcSession>& session, const uint8_t* data, size_t dataSize,
+            const uint32_t* objectTable, size_t objectTableSize,
+            std::vector<std::variant<base::unique_fd, base::borrowed_fd>>&& ancillaryFds,
+            release_func relFunc);
 
     status_t            finishWrite(size_t len);
     void                releaseObjects();
     void                acquireObjects();
     status_t            growData(size_t len);
+    // Clear the Parcel and set the capacity to `desired`.
+    // Doesn't reset the RPC session association.
     status_t            restartWrite(size_t desired);
+    // Set the capacity to `desired`, truncating the Parcel if necessary.
     status_t            continueWrite(size_t desired);
+    status_t truncateRpcObjects(size_t newObjectsSize);
     status_t            writePointer(uintptr_t val);
     status_t            readPointer(uintptr_t *pArg) const;
     uintptr_t           readPointer() const;
@@ -1169,10 +1184,20 @@
         c->clear(); // must clear before resizing/reserving otherwise move ctors may be called.
         if constexpr (is_pointer_equivalent_array_v<T>) {
             // could consider POD without gaps and alignment of 4.
-            auto data = reinterpret_cast<const T*>(
-                    readInplace(static_cast<size_t>(size) * sizeof(T)));
+            size_t dataLen;
+            if (__builtin_mul_overflow(size, sizeof(T), &dataLen)) {
+                return -EOVERFLOW;
+            }
+            auto data = reinterpret_cast<const T*>(readInplace(dataLen));
             if (data == nullptr) return BAD_VALUE;
-            c->insert(c->begin(), data, data + size); // insert should do a reserve().
+            // std::vector::insert and similar methods will require type-dependent
+            // byte alignment when inserting from a const iterator such as `data`,
+            // e.g. 8 byte alignment for int64_t, and so will not work if `data`
+            // is 4 byte aligned (which is all Parcel guarantees). Copying
+            // the contents into the vector directly, where possible, circumvents
+            // this.
+            c->resize(size);
+            memcpy(c->data(), data, dataLen);
         } else if constexpr (std::is_same_v<T, bool>
                 || std::is_same_v<T, char16_t>) {
             c->reserve(size); // avoids default initialization
@@ -1247,19 +1272,57 @@
     uint8_t*            mData;
     size_t              mDataSize;
     size_t              mDataCapacity;
-    mutable size_t      mDataPos;
-    binder_size_t*      mObjects;
-    size_t              mObjectsSize;
-    size_t              mObjectsCapacity;
-    mutable size_t      mNextObjectHint;
-    mutable bool        mObjectsSorted;
+    mutable size_t mDataPos;
 
-    mutable bool        mRequestHeaderPresent;
+    // Fields only needed when parcelling for "kernel Binder".
+    struct KernelFields {
+        binder_size_t* mObjects = nullptr;
+        size_t mObjectsSize = 0;
+        size_t mObjectsCapacity = 0;
+        mutable size_t mNextObjectHint = 0;
 
-    mutable size_t      mWorkSourceRequestHeaderPosition;
+        mutable size_t mWorkSourceRequestHeaderPosition = 0;
+        mutable bool mRequestHeaderPresent = false;
 
-    mutable bool        mFdsKnown;
-    mutable bool        mHasFds;
+        mutable bool mObjectsSorted = false;
+        mutable bool mFdsKnown = true;
+        mutable bool mHasFds = false;
+    };
+    // Fields only needed when parcelling for RPC Binder.
+    struct RpcFields {
+        RpcFields(const sp<RpcSession>& session);
+
+        // Should always be non-null.
+        const sp<RpcSession> mSession;
+
+        enum ObjectType : int32_t {
+            TYPE_BINDER_NULL = 0,
+            TYPE_BINDER = 1,
+            // FD to be passed via native transport (Trusty IPC or UNIX domain socket).
+            TYPE_NATIVE_FILE_DESCRIPTOR = 2,
+        };
+
+        // Sorted.
+        std::vector<uint32_t> mObjectPositions;
+
+        // File descriptors referenced by the parcel data. Should be indexed
+        // using the offsets in the parcel data. Don't assume the list is in the
+        // same order as `mObjectPositions`.
+        //
+        // Boxed to save space. Lazy allocated.
+        std::unique_ptr<std::vector<std::variant<base::unique_fd, base::borrowed_fd>>> mFds;
+    };
+    std::variant<KernelFields, RpcFields> mVariantFields;
+
+    // Pointer to KernelFields in mVariantFields if present.
+    KernelFields* maybeKernelFields() { return std::get_if<KernelFields>(&mVariantFields); }
+    const KernelFields* maybeKernelFields() const {
+        return std::get_if<KernelFields>(&mVariantFields);
+    }
+    // Pointer to RpcFields in mVariantFields if present.
+    RpcFields* maybeRpcFields() { return std::get_if<RpcFields>(&mVariantFields); }
+    const RpcFields* maybeRpcFields() const { return std::get_if<RpcFields>(&mVariantFields); }
+
     bool                mAllowFds;
 
     // if this parcelable is involved in a secure transaction, force the
@@ -1268,7 +1331,6 @@
 
     release_func        mOwner;
 
-    sp<RpcSession> mSession;
     size_t mReserved;
 
     class Blob {
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 675585e..9679a5f 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -29,6 +29,10 @@
 
 class IPCThreadState;
 
+/**
+ * Kernel binder process state. All operations here refer to kernel binder. This
+ * object is allocated per process.
+ */
 class ProcessState : public virtual RefBase {
 public:
     static sp<ProcessState> self();
@@ -84,14 +88,15 @@
     void setCallRestriction(CallRestriction restriction);
 
     /**
-     * Get the max number of threads that the kernel can start.
-     *
-     * Note: this is the lower bound. Additional threads may be started.
+     * Get the max number of threads that have joined the thread pool.
+     * This includes kernel started threads, user joined threads and polling
+     * threads if used.
      */
-    size_t getThreadPoolMaxThreadCount() const;
+    size_t getThreadPoolMaxTotalThreadCount() const;
 
     enum class DriverFeature {
         ONEWAY_SPAM_DETECTION,
+        EXTENDED_ERROR,
     };
     // Determine whether a feature is supported by the binder driver.
     static bool isDriverFeatureEnabled(const DriverFeature feature);
@@ -125,15 +130,19 @@
     void* mVMStart;
 
     // Protects thread count and wait variables below.
-    pthread_mutex_t mThreadCountLock;
+    mutable pthread_mutex_t mThreadCountLock;
     // Broadcast whenever mWaitingForThreads > 0
     pthread_cond_t mThreadCountDecrement;
     // Number of binder threads current executing a command.
     size_t mExecutingThreadsCount;
     // Number of threads calling IPCThreadState::blockUntilThreadAvailable()
     size_t mWaitingForThreads;
-    // Maximum number for binder threads allowed for this process.
+    // Maximum number of lazy threads to be started in the threadpool by the kernel.
     size_t mMaxThreads;
+    // Current number of threads inside the thread pool.
+    size_t mCurrentThreads;
+    // Current number of pooled threads inside the thread pool.
+    size_t mKernelStartedThreads;
     // Time when thread pool was emptied
     int64_t mStarvationStartTimeMs;
 
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 6b31812..52bda0e 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -18,6 +18,7 @@
 #include <android-base/unique_fd.h>
 #include <binder/IBinder.h>
 #include <binder/RpcSession.h>
+#include <binder/RpcThreads.h>
 #include <binder/RpcTransport.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
@@ -28,6 +29,7 @@
 namespace android {
 
 class FdTrigger;
+class RpcServerTrusty;
 class RpcSocketAddress;
 
 /**
@@ -114,6 +116,15 @@
     void setProtocolVersion(uint32_t version);
 
     /**
+     * Set the supported transports for sending and receiving file descriptors.
+     *
+     * Clients will propose a mode when connecting. If the mode is not in the
+     * provided list, the connection will be rejected.
+     */
+    void setSupportedFileDescriptorTransportModes(
+            const std::vector<RpcSession::FileDescriptorTransportMode>& modes);
+
+    /**
      * The root object can be retrieved by any client, without any
      * authentication. TODO(b/183988761)
      *
@@ -125,9 +136,17 @@
      */
     void setRootObjectWeak(const wp<IBinder>& binder);
     /**
-     * Allows a root object to be created for each session
+     * Allows a root object to be created for each session.
+     *
+     * Takes one argument: a callable that is invoked once per new session.
+     * The callable takes two arguments: a type-erased pointer to an OS- and
+     * transport-specific address structure, e.g., sockaddr_vm for vsock, and
+     * an integer representing the size in bytes of that structure. The
+     * callable should validate the size, then cast the type-erased pointer
+     * to a pointer to the actual type of the address, e.g., const void* to
+     * const sockaddr_vm*.
      */
-    void setPerSessionRootObject(std::function<sp<IBinder>(const sockaddr*, socklen_t)>&& object);
+    void setPerSessionRootObject(std::function<sp<IBinder>(const void*, size_t)>&& object);
     sp<IBinder> getRootObject();
 
     /**
@@ -171,31 +190,39 @@
     ~RpcServer();
 
 private:
+    friend RpcServerTrusty;
     friend sp<RpcServer>;
     explicit RpcServer(std::unique_ptr<RpcTransportCtx> ctx);
 
     void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
     void onSessionIncomingThreadEnded() override;
 
-    static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
-                                    const sockaddr_storage addr, socklen_t addrLen);
+    static constexpr size_t kRpcAddressSize = 128;
+    static void establishConnection(
+            sp<RpcServer>&& server, base::unique_fd clientFd,
+            std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen,
+            std::function<void(sp<RpcSession>&&, RpcSession::PreJoinSetupResult&&)>&& joinFn);
     [[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address);
 
     const std::unique_ptr<RpcTransportCtx> mCtx;
     size_t mMaxThreads = 1;
     std::optional<uint32_t> mProtocolVersion;
+    // A mode is supported if the N'th bit is on, where N is the mode enum's value.
+    std::bitset<8> mSupportedFileDescriptorTransportModes = std::bitset<8>().set(
+            static_cast<size_t>(RpcSession::FileDescriptorTransportMode::NONE));
     base::unique_fd mServer; // socket we are accepting sessions on
 
-    std::mutex mLock; // for below
-    std::unique_ptr<std::thread> mJoinThread;
+    RpcMutex mLock; // for below
+    std::unique_ptr<RpcMaybeThread> mJoinThread;
     bool mJoinThreadRunning = false;
-    std::map<std::thread::id, std::thread> mConnectingThreads;
+    std::map<RpcMaybeThread::id, RpcMaybeThread> mConnectingThreads;
+
     sp<IBinder> mRootObject;
     wp<IBinder> mRootObjectWeak;
-    std::function<sp<IBinder>(const sockaddr*, socklen_t)> mRootObjectFactory;
+    std::function<sp<IBinder>(const void*, size_t)> mRootObjectFactory;
     std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions;
     std::unique_ptr<FdTrigger> mShutdownTrigger;
-    std::condition_variable mShutdownCv;
+    RpcConditionVariable mShutdownCv;
 };
 
 } // namespace android
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 1bc8464..428e272 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -15,30 +15,38 @@
  */
 #pragma once
 
+#include <android-base/threads.h>
 #include <android-base/unique_fd.h>
 #include <binder/IBinder.h>
+#include <binder/RpcThreads.h>
 #include <binder/RpcTransport.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
 #include <map>
 #include <optional>
-#include <thread>
 #include <vector>
 
 namespace android {
 
 class Parcel;
 class RpcServer;
+class RpcServerTrusty;
 class RpcSocketAddress;
 class RpcState;
 class RpcTransport;
 class FdTrigger;
 
-constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 0;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 1;
 constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL = 0xF0000000;
 constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL;
 
+// Starting with this version:
+//
+// * RpcWireReply is larger (4 bytes -> 20).
+// * RpcWireTransaction and RpcWireReplyV1 include the parcel data size.
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE = 1;
+
 /**
  * This represents a session (group of connections) between a client
  * and a server. Multiple connections are needed for multiple parallel "binder"
@@ -88,6 +96,18 @@
     [[nodiscard]] bool setProtocolVersion(uint32_t version);
     std::optional<uint32_t> getProtocolVersion();
 
+    enum class FileDescriptorTransportMode : uint8_t {
+        NONE = 0,
+        // Send file descriptors via unix domain socket ancillary data.
+        UNIX = 1,
+    };
+
+    /**
+     * Set the transport for sending and receiving file descriptors.
+     */
+    void setFileDescriptorTransportMode(FileDescriptorTransportMode mode);
+    FileDescriptorTransportMode getFileDescriptorTransportMode();
+
     /**
      * This should be called once per thread, matching 'join' in the remote
      * process.
@@ -183,9 +203,14 @@
 private:
     friend sp<RpcSession>;
     friend RpcServer;
+    friend RpcServerTrusty;
     friend RpcState;
     explicit RpcSession(std::unique_ptr<RpcTransportCtx> ctx);
 
+    // internal version of setProtocolVersion that
+    // optionally skips the mStartedSetup check
+    [[nodiscard]] bool setProtocolVersionInternal(uint32_t version, bool checkStarted);
+
     // for 'target', see RpcState::sendDecStrongToTarget
     [[nodiscard]] status_t sendDecStrongToTarget(uint64_t address, size_t target);
 
@@ -199,10 +224,10 @@
     public:
         void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
         void onSessionIncomingThreadEnded() override;
-        void waitForShutdown(std::unique_lock<std::mutex>& lock, const sp<RpcSession>& session);
+        void waitForShutdown(RpcMutexUniqueLock& lock, const sp<RpcSession>& session);
 
     private:
-        std::condition_variable mCv;
+        RpcConditionVariable mCv;
     };
     friend WaitForShutdownListener;
 
@@ -211,7 +236,7 @@
 
         // whether this or another thread is currently using this fd to make
         // or receive transactions.
-        std::optional<pid_t> exclusiveTid;
+        std::optional<uint64_t> exclusiveTid;
 
         bool allowNested = false;
     };
@@ -225,7 +250,7 @@
     //
     // transfer ownership of thread (usually done while a lock is taken on the
     // structure which originally owns the thread)
-    void preJoinThreadOwnership(std::thread thread);
+    void preJoinThreadOwnership(RpcMaybeThread thread);
     // pass FD to thread and read initial connection information
     struct PreJoinSetupResult {
         // Server connection object associated with this
@@ -257,6 +282,7 @@
     sp<RpcConnection> assignIncomingConnectionToThisThread(
             std::unique_ptr<RpcTransport> rpcTransport);
     [[nodiscard]] bool removeIncomingConnection(const sp<RpcConnection>& connection);
+    void clearConnectionTid(const sp<RpcConnection>& connection);
 
     [[nodiscard]] status_t initShutdownTrigger();
 
@@ -276,7 +302,7 @@
         const sp<RpcConnection>& get() { return mConnection; }
 
     private:
-        static void findConnection(pid_t tid, sp<RpcConnection>* exclusive,
+        static void findConnection(uint64_t tid, sp<RpcConnection>* exclusive,
                                    sp<RpcConnection>* available,
                                    std::vector<sp<RpcConnection>>& sockets,
                                    size_t socketsIndexHint);
@@ -306,7 +332,7 @@
     // For a more complicated case, the client might itself open up a thread to
     // serve calls to the server at all times (e.g. if it hosts a callback)
 
-    wp<RpcServer> mForServer; // maybe null, for client sessions
+    wp<RpcServer> mForServer;                      // maybe null, for client sessions
     sp<WaitForShutdownListener> mShutdownListener; // used for client sessions
     wp<EventListener> mEventListener; // mForServer if server, mShutdownListener if client
 
@@ -320,13 +346,15 @@
 
     std::unique_ptr<RpcState> mRpcBinderState;
 
-    std::mutex mMutex; // for all below
+    RpcMutex mMutex; // for all below
 
+    bool mStartedSetup = false;
     size_t mMaxIncomingThreads = 0;
     size_t mMaxOutgoingThreads = kDefaultMaxOutgoingThreads;
     std::optional<uint32_t> mProtocolVersion;
+    FileDescriptorTransportMode mFileDescriptorTransportMode = FileDescriptorTransportMode::NONE;
 
-    std::condition_variable mAvailableConnectionCv; // for mWaitingThreads
+    RpcConditionVariable mAvailableConnectionCv; // for mWaitingThreads
 
     struct ThreadState {
         size_t mWaitingThreads = 0;
@@ -335,7 +363,7 @@
         std::vector<sp<RpcConnection>> mOutgoing;
         size_t mMaxIncoming = 0;
         std::vector<sp<RpcConnection>> mIncoming;
-        std::map<std::thread::id, std::thread> mThreads;
+        std::map<RpcMaybeThread::id, RpcMaybeThread> mThreads;
     } mConnections;
 };
 
diff --git a/libs/binder/include/binder/RpcThreads.h b/libs/binder/include/binder/RpcThreads.h
new file mode 100644
index 0000000..8abf04e
--- /dev/null
+++ b/libs/binder/include/binder/RpcThreads.h
@@ -0,0 +1,145 @@
+/*
+ * 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 <pthread.h>
+
+#include <android-base/threads.h>
+
+#include <functional>
+#include <memory>
+#include <thread>
+
+namespace android {
+
+#ifdef BINDER_RPC_SINGLE_THREADED
+class RpcMutex {
+public:
+    void lock() {}
+    void unlock() {}
+};
+
+class RpcMutexUniqueLock {
+public:
+    RpcMutexUniqueLock(RpcMutex&) {}
+    void unlock() {}
+};
+
+class RpcMutexLockGuard {
+public:
+    RpcMutexLockGuard(RpcMutex&) {}
+};
+
+class RpcConditionVariable {
+public:
+    void notify_one() {}
+    void notify_all() {}
+
+    void wait(RpcMutexUniqueLock&) {}
+
+    template <typename Predicate>
+    void wait(RpcMutexUniqueLock&, Predicate stop_waiting) {
+        LOG_ALWAYS_FATAL_IF(!stop_waiting(), "RpcConditionVariable::wait condition not met");
+    }
+
+    template <typename Duration>
+    std::cv_status wait_for(RpcMutexUniqueLock&, const Duration&) {
+        return std::cv_status::no_timeout;
+    }
+
+    template <typename Duration, typename Predicate>
+    bool wait_for(RpcMutexUniqueLock&, const Duration&, Predicate stop_waiting) {
+        return stop_waiting();
+    }
+};
+
+class RpcMaybeThread {
+public:
+    RpcMaybeThread() = default;
+
+    template <typename Function, typename... Args>
+    RpcMaybeThread(Function&& f, Args&&... args) {
+        // std::function requires a copy-constructible closure,
+        // so we need to wrap both the function and its arguments
+        // in a shared pointer that std::function can copy internally
+        struct Vars {
+            std::decay_t<Function> f;
+            std::tuple<std::decay_t<Args>...> args;
+
+            explicit Vars(Function&& f, Args&&... args)
+                  : f(std::move(f)), args(std::move(args)...) {}
+        };
+        auto vars = std::make_shared<Vars>(std::forward<Function>(f), std::forward<Args>(args)...);
+        mFunc = [vars]() { std::apply(std::move(vars->f), std::move(vars->args)); };
+    }
+
+    void join() {
+        if (mFunc) {
+            // Move mFunc into a temporary so we can clear mFunc before
+            // executing the callback. This avoids infinite recursion if
+            // the callee then calls join() again directly or indirectly.
+            decltype(mFunc) func = nullptr;
+            mFunc.swap(func);
+            func();
+        }
+    }
+    void detach() { join(); }
+
+    class id {
+    public:
+        bool operator==(const id&) const { return true; }
+        bool operator!=(const id&) const { return false; }
+        bool operator<(const id&) const { return false; }
+        bool operator<=(const id&) const { return true; }
+        bool operator>(const id&) const { return false; }
+        bool operator>=(const id&) const { return true; }
+    };
+
+    id get_id() const { return id(); }
+
+private:
+    std::function<void(void)> mFunc;
+};
+
+namespace rpc_this_thread {
+static inline RpcMaybeThread::id get_id() {
+    return RpcMaybeThread::id();
+}
+} // namespace rpc_this_thread
+
+static inline uint64_t rpcGetThreadId() {
+    return 0;
+}
+
+static inline void rpcJoinIfSingleThreaded(RpcMaybeThread& t) {
+    t.join();
+}
+#else  // BINDER_RPC_SINGLE_THREADED
+using RpcMutex = std::mutex;
+using RpcMutexUniqueLock = std::unique_lock<std::mutex>;
+using RpcMutexLockGuard = std::lock_guard<std::mutex>;
+using RpcConditionVariable = std::condition_variable;
+using RpcMaybeThread = std::thread;
+namespace rpc_this_thread = std::this_thread;
+
+static inline uint64_t rpcGetThreadId() {
+    return base::GetThreadId();
+}
+
+static inline void rpcJoinIfSingleThreaded(RpcMaybeThread&) {}
+#endif // BINDER_RPC_SINGLE_THREADED
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index 751c4f9..5197ef9 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -20,8 +20,12 @@
 
 #include <functional>
 #include <memory>
+#include <optional>
 #include <string>
+#include <variant>
+#include <vector>
 
+#include <android-base/function_ref.h>
 #include <android-base/unique_fd.h>
 #include <utils/Errors.h>
 
@@ -39,8 +43,15 @@
 public:
     virtual ~RpcTransport() = default;
 
-    // replacement of ::recv(MSG_PEEK). Error code may not be set if TLS is enabled.
-    [[nodiscard]] virtual status_t peek(void *buf, size_t size, size_t *out_size) = 0;
+    /**
+     * Poll the transport to check whether there is any data ready to read.
+     *
+     * Return:
+     *   OK - There is data available on this transport
+     *   WOULDBLOCK - No data is available
+     *   error - any other error
+     */
+    [[nodiscard]] virtual status_t pollRead(void) = 0;
 
     /**
      * Read (or write), but allow to be interrupted by a trigger.
@@ -52,16 +63,23 @@
      * to read/write data. If this returns an error, that error is returned from
      * this function.
      *
+     * ancillaryFds - FDs to be sent via UNIX domain dockets or Trusty IPC. When
+     * reading, if `ancillaryFds` is null, any received FDs will be silently
+     * dropped and closed (by the OS). Appended values will always be unique_fd,
+     * the variant type is used to avoid extra copies elsewhere.
+     *
      * Return:
      *   OK - succeeded in completely processing 'size'
      *   error - interrupted (failure or trigger)
      */
     [[nodiscard]] virtual status_t interruptableWriteFully(
             FdTrigger *fdTrigger, iovec *iovs, int niovs,
-            const std::function<status_t()> &altPoll) = 0;
+            const std::optional<android::base::function_ref<status_t()>> &altPoll,
+            const std::vector<std::variant<base::unique_fd, base::borrowed_fd>> *ancillaryFds) = 0;
     [[nodiscard]] virtual status_t interruptableReadFully(
             FdTrigger *fdTrigger, iovec *iovs, int niovs,
-            const std::function<status_t()> &altPoll) = 0;
+            const std::optional<android::base::function_ref<status_t()>> &altPoll,
+            std::vector<std::variant<base::unique_fd, base::borrowed_fd>> *ancillaryFds) = 0;
 
 protected:
     RpcTransport() = default;
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index bf2b25b..a3d42b7 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -38,10 +38,10 @@
                    << " error: " << statusToString(status).c_str();
         return false;
     }
-    server->setPerSessionRootObject([=](const sockaddr* addr, socklen_t addrlen) {
-        LOG_ALWAYS_FATAL_IF(addr->sa_family != AF_VSOCK, "address is not a vsock");
+    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));
     });
 
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 79c8c8f..32e018d 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -113,6 +113,7 @@
         "abseil-*",
         "android-*",
         "bugprone-*",
+        "-bugprone-branch-clone", // b/155034972
         "cert-*",
         "clang-analyzer-*",
         "-clang-analyzer-core.CallAndMessage",
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 28e3ff4..9778ec0 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -36,6 +36,7 @@
 using ::android::Parcel;
 using ::android::sp;
 using ::android::status_t;
+using ::android::statusToString;
 using ::android::String16;
 using ::android::String8;
 using ::android::wp;
@@ -63,6 +64,9 @@
     wp<ABpBinder> binder;
 };
 void clean(const void* id, void* obj, void* cookie) {
+    // be weary of leaks!
+    // LOG(INFO) << "Deleting an ABpBinder";
+
     CHECK(id == kId) << id << " " << obj << " " << cookie;
 
     delete static_cast<Value*>(obj);
@@ -133,7 +137,8 @@
         } else {
             // b/155793159
             LOG(ERROR) << __func__ << ": Cannot associate class '" << newDescriptor
-                       << "' to dead binder.";
+                       << "' to dead binder with cached descriptor '" << SanitizeString(descriptor)
+                       << "'.";
         }
         return false;
     }
@@ -237,26 +242,11 @@
 }
 
 ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder)
-    : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
+    : AIBinder(nullptr /*clazz*/), mRemote(binder) {
     CHECK(binder != nullptr);
 }
 ABpBinder::~ABpBinder() {}
 
-void ABpBinder::onLastStrongRef(const void* id) {
-    // Since ABpBinder is OBJECT_LIFETIME_WEAK, we must remove this weak reference in order for
-    // the ABpBinder to be deleted. Even though we have no more references on the ABpBinder
-    // (BpRefBase), the remote object may still exist (for instance, if we
-    // receive it from another process, before the ABpBinder is attached).
-
-    ABpBinderTag::Value* value =
-            static_cast<ABpBinderTag::Value*>(remote()->findObject(ABpBinderTag::kId));
-    CHECK_NE(nullptr, value) << "ABpBinder must always be attached";
-
-    remote()->withLock([&]() { value->binder = nullptr; });
-
-    BpRefBase::onLastStrongRef(id);
-}
-
 sp<AIBinder> ABpBinder::lookupOrCreateFromBinder(const ::android::sp<::android::IBinder>& binder) {
     if (binder == nullptr) {
         return nullptr;
@@ -458,7 +448,8 @@
             status_t status = binder->unlinkToDeath(recipient, cookie, 0 /*flags*/);
             if (status != ::android::OK) {
                 LOG(ERROR) << __func__
-                           << ": removed reference to death recipient but unlink failed.";
+                           << ": removed reference to death recipient but unlink failed: "
+                           << statusToString(status);
             }
             return PruneStatusT(status);
         }
@@ -539,7 +530,8 @@
 binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                      void* cookie) {
     if (binder == nullptr || recipient == nullptr) {
-        LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
+        LOG(ERROR) << __func__ << ": Must provide binder (" << binder << ") and recipient ("
+                   << recipient << ")";
         return STATUS_UNEXPECTED_NULL;
     }
 
@@ -550,7 +542,8 @@
 binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                        void* cookie) {
     if (binder == nullptr || recipient == nullptr) {
-        LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
+        LOG(ERROR) << __func__ << ": Must provide binder (" << binder << ") and recipient ("
+                   << recipient << ")";
         return STATUS_UNEXPECTED_NULL;
     }
 
@@ -625,7 +618,8 @@
 
 binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) {
     if (binder == nullptr || in == nullptr) {
-        LOG(ERROR) << __func__ << ": requires non-null parameters.";
+        LOG(ERROR) << __func__ << ": requires non-null parameters binder (" << binder
+                   << ") and in (" << in << ").";
         return STATUS_UNEXPECTED_NULL;
     }
     const AIBinder_Class* clazz = binder->getClass();
@@ -671,7 +665,9 @@
     AutoParcelDestroyer forIn(in, DestroyParcel);
 
     if (!isUserCommand(code)) {
-        LOG(ERROR) << __func__ << ": Only user-defined transactions can be made from the NDK.";
+        LOG(ERROR) << __func__
+                   << ": Only user-defined transactions can be made from the NDK, but requested: "
+                   << code;
         return STATUS_UNKNOWN_TRANSACTION;
     }
 
@@ -682,7 +678,8 @@
     }
 
     if (binder == nullptr || *in == nullptr || out == nullptr) {
-        LOG(ERROR) << __func__ << ": requires non-null parameters.";
+        LOG(ERROR) << __func__ << ": requires non-null parameters binder (" << binder << "), in ("
+                   << in << "), and out (" << out << ").";
         return STATUS_UNEXPECTED_NULL;
     }
 
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 730e51b..d7098e8 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -91,7 +91,7 @@
 
 // This binder object may be remote or local (even though it is 'Bp'). The implication if it is
 // local is that it is an IBinder object created outside of the domain of libbinder_ndk.
-struct ABpBinder : public AIBinder, public ::android::BpRefBase {
+struct ABpBinder : public AIBinder {
     // Looks up to see if this object has or is an existing ABBinder or ABpBinder object, otherwise
     // it creates an ABpBinder object.
     static ::android::sp<AIBinder> lookupOrCreateFromBinder(
@@ -99,14 +99,13 @@
 
     virtual ~ABpBinder();
 
-    void onLastStrongRef(const void* id) override;
-
-    ::android::sp<::android::IBinder> getBinder() override { return remote(); }
+    ::android::sp<::android::IBinder> getBinder() override { return mRemote; }
     ABpBinder* asABpBinder() override { return this; }
 
    private:
     friend android::sp<ABpBinder>;
     explicit ABpBinder(const ::android::sp<::android::IBinder>& binder);
+    ::android::sp<::android::IBinder> mRemote;
 };
 
 struct AIBinder_Class {
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 c8e78fc..78bcb43 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -43,10 +43,12 @@
 namespace ndk {
 
 /**
- * analog using std::shared_ptr for internally held refcount
+ * Binder analog to using std::shared_ptr for an internally held refcount.
  *
  * ref must be called at least one time during the lifetime of this object. The recommended way to
  * construct this object is with SharedRefBase::make.
+ *
+ * If you need a "this" shared reference analogous to shared_from_this, use this->ref().
  */
 class SharedRefBase {
    public:
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
index 6880d86..8e288b3 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -56,6 +56,12 @@
  * If the binder is null, null is returned. If this binder object was originally an IBinder object,
  * the original java object will be returned.
  *
+ * WARNING: this function returns global and local references. This can be
+ * figured out using GetObjectRefType. Though, when this function is called
+ * from within a Java context, the local ref will automatically be cleaned
+ * up. If this is called outside of a Java frame,
+ * PushObjectFrame/PopObjectFrame can simulate this automatic cleanup.
+ *
  * Available since API level 29.
  *
  * \param env Java environment. Must not be null.
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 8457581..f68612c 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -59,6 +59,11 @@
 /**
  * Sets the position within the parcel.
  *
+ * This must be called with a position that has been previously returned from
+ * AParcel_getDataPosition. If writes are made after setting the data position, they must
+ * be made in the exact same sequence used before resetting data position. Writing over
+ * objects such as binders or file descriptors is not supported.
+ *
  * Available since API level 29.
  *
  * \param parcel The parcel of which to set the position.
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index d0cd11f..683a433 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -98,9 +98,9 @@
  * This interface has system<->vendor stability
  */
 // b/227835797 - can't use __INTRODUCED_IN(30) because old targets load this code
-#if __ANDROID_MIN_SDK_VERSION__ < 30
+#if defined(__ANDROID_MIN_SDK_VERSION__) && __ANDROID_MIN_SDK_VERSION__ < 30
 __attribute__((weak))
-#endif  // __ANDROID_MIN_SDK_VERSION__ < 30
+#endif  // defined(__ANDROID_MIN_SDK_VERSION__) && __ANDROID_MIN_SDK_VERSION__ < 30
 void AIBinder_markVintfStability(AIBinder* binder);
 
 __END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 3824a1b..6bc9814 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -89,12 +89,12 @@
     AStatus_getStatus;
     AStatus_isOk;
     AStatus_newOk;
-    ABinderProcess_joinThreadPool; # apex llndk
-    ABinderProcess_setThreadPoolMaxThreadCount; # apex llndk
-    ABinderProcess_startThreadPool; # apex llndk
-    AServiceManager_addService; # apex llndk
-    AServiceManager_checkService; # apex llndk
-    AServiceManager_getService; # apex llndk
+    ABinderProcess_joinThreadPool; # systemapi llndk
+    ABinderProcess_setThreadPoolMaxThreadCount; # systemapi llndk
+    ABinderProcess_startThreadPool; # systemapi llndk
+    AServiceManager_addService; # systemapi llndk
+    AServiceManager_checkService; # systemapi llndk
+    AServiceManager_getService; # systemapi llndk
 };
 
 LIBBINDER_NDK30 { # introduced=30
@@ -105,30 +105,30 @@
     AStatus_deleteDescription;
     AParcel_fromJavaParcel;
 
-    AIBinder_markSystemStability; # apex
+    AIBinder_markSystemStability; # systemapi
     AIBinder_markVendorStability; # llndk
-    AIBinder_markVintfStability; # apex llndk
-    AIBinder_Class_setHandleShellCommand; # apex llndk
+    AIBinder_markVintfStability; # systemapi llndk
+    AIBinder_Class_setHandleShellCommand; # systemapi llndk
 };
 
 LIBBINDER_NDK31 { # introduced=31
   global:
-    ABinderProcess_handlePolledCommands; # apex
-    ABinderProcess_setupPolling; # apex
-    AIBinder_getCallingSid; # apex
-    AIBinder_setRequestingSid; # apex
+    ABinderProcess_handlePolledCommands; # systemapi
+    ABinderProcess_setupPolling; # systemapi
+    AIBinder_getCallingSid; # systemapi
+    AIBinder_setRequestingSid; # systemapi
     AParcel_markSensitive; # systemapi llndk
-    AServiceManager_forEachDeclaredInstance; # apex llndk
-    AServiceManager_forceLazyServicesPersist; # apex llndk
-    AServiceManager_isDeclared; # apex llndk
-    AServiceManager_isUpdatableViaApex; # apex
+    AServiceManager_forEachDeclaredInstance; # systemapi llndk
+    AServiceManager_forceLazyServicesPersist; # systemapi llndk
+    AServiceManager_isDeclared; # systemapi llndk
+    AServiceManager_isUpdatableViaApex; # systemapi
     AServiceManager_reRegister; # llndk
-    AServiceManager_registerLazyService; # apex llndk
+    AServiceManager_registerLazyService; # systemapi llndk
     AServiceManager_setActiveServicesCallback; # llndk
     AServiceManager_tryUnregister; # llndk
-    AServiceManager_waitForService; # apex llndk
+    AServiceManager_waitForService; # systemapi llndk
 
-    AIBinder_forceDowngradeToSystemStability; # apex
+    AIBinder_forceDowngradeToSystemStability; # systemapi
     AIBinder_forceDowngradeToVendorStability; # llndk
 
     AIBinder_Class_getDescriptor;
@@ -146,8 +146,8 @@
     AIBinder_Class_disableInterfaceTokenHeader;
     AIBinder_DeathRecipient_setOnUnlinked;
     AIBinder_isHandlingTransaction;
-    AIBinder_setInheritRt; # llndk
-    AIBinder_setMinSchedulerPolicy; # llndk
+    AIBinder_setInheritRt; # systemapi llndk
+    AIBinder_setMinSchedulerPolicy; # systemapi llndk
     AParcel_marshal;
     AParcel_unmarshal;
 };
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 355b3b4..c0d4487 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -15,9 +15,10 @@
         "libutils",
     ],
     rustlibs: [
-        "liblibc",
         "libbinder_ndk_sys",
         "libdowncast_rs",
+        "liblazy_static",
+        "liblibc",
     ],
     host_supported: true,
     vendor_available: true,
@@ -148,6 +149,7 @@
     name: "libbinder_rpc_unstable_bindgen",
     wrapper_src: ":libbinder_rpc_unstable_header",
     crate_name: "binder_rpc_unstable_bindgen",
+    visibility: ["//packages/modules/Virtualization:__subpackages__"],
     source_stem: "bindings",
     shared_libs: [
         "libutils",
@@ -170,9 +172,10 @@
         "libbinder_ndk",
     ],
     rustlibs: [
-        "liblibc",
         "libbinder_ndk_sys",
         "libdowncast_rs",
+        "liblazy_static",
+        "liblibc",
     ],
 }
 
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs
index 9dcef42..2d2bf7c 100644
--- a/libs/binder/rust/binder_tokio/lib.rs
+++ b/libs/binder/rust/binder_tokio/lib.rs
@@ -28,22 +28,22 @@
 //!
 //! [`Tokio`]: crate::Tokio
 
-use binder::{BinderAsyncPool, BoxFuture, FromIBinder, StatusCode, Strong};
 use binder::binder_impl::BinderAsyncRuntime;
+use binder::{BinderAsyncPool, BoxFuture, FromIBinder, StatusCode, Strong};
 use std::future::Future;
 
 /// Retrieve an existing service for a particular interface, sleeping for a few
 /// seconds if it doesn't yet exist.
-pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(
+    name: &str,
+) -> Result<Strong<T>, StatusCode> {
     if binder::is_handling_transaction() {
         // See comment in the BinderAsyncPool impl.
         return binder::get_interface::<T>(name);
     }
 
     let name = name.to_string();
-    let res = tokio::task::spawn_blocking(move || {
-        binder::get_interface::<T>(&name)
-    }).await;
+    let res = tokio::task::spawn_blocking(move || binder::get_interface::<T>(&name)).await;
 
     // The `is_panic` branch is not actually reachable in Android as we compile
     // with `panic = abort`.
@@ -58,16 +58,16 @@
 
 /// Retrieve an existing service for a particular interface, or start it if it
 /// is configured as a dynamic service and isn't yet started.
-pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(
+    name: &str,
+) -> Result<Strong<T>, StatusCode> {
     if binder::is_handling_transaction() {
         // See comment in the BinderAsyncPool impl.
         return binder::wait_for_interface::<T>(name);
     }
 
     let name = name.to_string();
-    let res = tokio::task::spawn_blocking(move || {
-        binder::wait_for_interface::<T>(&name)
-    }).await;
+    let res = tokio::task::spawn_blocking(move || binder::wait_for_interface::<T>(&name)).await;
 
     // The `is_panic` branch is not actually reachable in Android as we compile
     // with `panic = abort`.
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 5d6206d..63c8684 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -17,7 +17,7 @@
 //! Trait definitions for binder objects
 
 use crate::error::{status_t, Result, StatusCode};
-use crate::parcel::{Parcel, BorrowedParcel};
+use crate::parcel::{BorrowedParcel, Parcel};
 use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
 use crate::sys;
 
@@ -133,7 +133,7 @@
         match stability {
             0 => Ok(Local),
             1 => Ok(Vintf),
-            _ => Err(StatusCode::BAD_VALUE)
+            _ => Err(StatusCode::BAD_VALUE),
         }
     }
 }
@@ -158,7 +158,12 @@
     /// Handle and reply to a request to invoke a transaction on this object.
     ///
     /// `reply` may be [`None`] if the sender does not expect a reply.
-    fn on_transact(&self, code: TransactionCode, data: &BorrowedParcel<'_>, reply: &mut BorrowedParcel<'_>) -> Result<()>;
+    fn on_transact(
+        &self,
+        code: TransactionCode,
+        data: &BorrowedParcel<'_>,
+        reply: &mut BorrowedParcel<'_>,
+    ) -> Result<()>;
 
     /// Handle a request to invoke the dump transaction on this
     /// object.
@@ -454,28 +459,19 @@
     /// Construct a new weak reference from a strong reference
     fn new(binder: &Strong<I>) -> Self {
         let weak_binder = binder.as_binder().downgrade();
-        Weak {
-            weak_binder,
-            interface_type: PhantomData,
-        }
+        Weak { weak_binder, interface_type: PhantomData }
     }
 
     /// Upgrade this weak reference to a strong reference if the binder object
     /// is still alive
     pub fn upgrade(&self) -> Result<Strong<I>> {
-        self.weak_binder
-            .promote()
-            .ok_or(StatusCode::DEAD_OBJECT)
-            .and_then(FromIBinder::try_from)
+        self.weak_binder.promote().ok_or(StatusCode::DEAD_OBJECT).and_then(FromIBinder::try_from)
     }
 }
 
 impl<I: FromIBinder + ?Sized> Clone for Weak<I> {
     fn clone(&self) -> Self {
-        Self {
-            weak_binder: self.weak_binder.clone(),
-            interface_type: PhantomData,
-        }
+        Self { weak_binder: self.weak_binder.clone(), interface_type: PhantomData }
     }
 }
 
@@ -614,7 +610,12 @@
     /// contains a `T` pointer in its user data. fd should be a non-owned file
     /// descriptor, and args must be an array of null-terminated string
     /// poiinters with length num_args.
-    unsafe extern "C" fn on_dump(binder: *mut sys::AIBinder, fd: i32, args: *mut *const c_char, num_args: u32) -> status_t;
+    unsafe extern "C" fn on_dump(
+        binder: *mut sys::AIBinder,
+        fd: i32,
+        args: *mut *const c_char,
+        num_args: u32,
+    ) -> status_t;
 }
 
 /// Interface for transforming a generic SpIBinder into a specific remote
diff --git a/libs/binder/rust/src/binder_async.rs b/libs/binder/rust/src/binder_async.rs
index 579f9f9..d90acaf 100644
--- a/libs/binder/rust/src/binder_async.rs
+++ b/libs/binder/rust/src/binder_async.rs
@@ -41,7 +41,10 @@
     /// boxed `Future` trait object, and including `after_spawn` in the trait function
     /// allows the caller to avoid double-boxing if they want to do anything to the value
     /// returned from the spawned thread.
-    fn spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>>
+    fn spawn<'a, F1, F2, Fut, A, B, E>(
+        spawn_me: F1,
+        after_spawn: F2,
+    ) -> BoxFuture<'a, Result<B, E>>
     where
         F1: FnOnce() -> A,
         F2: FnOnce(A) -> Fut,
diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs
index 2598ebc..f6b09ed 100644
--- a/libs/binder/rust/src/error.rs
+++ b/libs/binder/rust/src/error.rs
@@ -18,7 +18,7 @@
 use crate::sys;
 
 use std::error;
-use std::ffi::CStr;
+use std::ffi::{CStr, CString};
 use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
 use std::result;
 
@@ -104,6 +104,10 @@
 // A thread-local `AStatus` would not be valid.
 unsafe impl Send for Status {}
 
+fn to_cstring<T: AsRef<str>>(message: T) -> Option<CString> {
+    CString::new(message.as_ref()).ok()
+}
+
 impl Status {
     /// Create a status object representing a successful transaction.
     pub fn ok() -> Self {
@@ -146,6 +150,11 @@
         Self(ptr)
     }
 
+    /// Creates a status object from a service specific error.
+    pub fn new_service_specific_error_str<T: AsRef<str>>(err: i32, message: Option<T>) -> Status {
+        Self::new_service_specific_error(err, message.and_then(to_cstring).as_deref())
+    }
+
     /// Create a status object from an exception code
     pub fn new_exception(exception: ExceptionCode, message: Option<&CStr>) -> Status {
         if let Some(message) = message {
@@ -158,6 +167,14 @@
         }
     }
 
+    /// Creates a status object from an exception code and message.
+    pub fn new_exception_str<T: AsRef<str>>(
+        exception: ExceptionCode,
+        message: Option<T>,
+    ) -> Status {
+        Self::new_exception(exception, message.and_then(to_cstring).as_deref())
+    }
+
     /// Create a status object from a raw `AStatus` pointer.
     ///
     /// # Safety
@@ -371,3 +388,41 @@
         self.0
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn make_service_specific_error() {
+        let status = Status::new_service_specific_error_str(-42, Some("message"));
+
+        assert!(!status.is_ok());
+        assert_eq!(status.exception_code(), ExceptionCode::SERVICE_SPECIFIC);
+        assert_eq!(status.service_specific_error(), -42);
+        assert_eq!(
+            status.get_description(),
+            "Status(-8, EX_SERVICE_SPECIFIC): '-42: message'".to_string()
+        );
+    }
+
+    #[test]
+    fn make_exception() {
+        let status = Status::new_exception_str(ExceptionCode::ILLEGAL_STATE, Some("message"));
+
+        assert!(!status.is_ok());
+        assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE);
+        assert_eq!(status.service_specific_error(), 0);
+        assert_eq!(status.get_description(), "Status(-5, EX_ILLEGAL_STATE): 'message'".to_string());
+    }
+
+    #[test]
+    fn make_exception_null() {
+        let status = Status::new_exception_str(ExceptionCode::ILLEGAL_STATE, Some("one\0two"));
+
+        assert!(!status.is_ok());
+        assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE);
+        assert_eq!(status.service_specific_error(), 0);
+        assert_eq!(status.get_description(), "Status(-5, EX_ILLEGAL_STATE): ''".to_string());
+    }
+}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index dbfb1c2..195d9ac 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -106,11 +106,12 @@
 
 use binder_ndk_sys as sys;
 
-pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
 pub use crate::binder_async::{BinderAsyncPool, BoxFuture};
+pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
 pub use error::{ExceptionCode, Status, StatusCode};
 pub use native::{
     add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service,
+    LazyServiceGuard,
 };
 pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
 pub use proxy::{
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index b7c7ae4..3a6dadd 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -22,6 +22,7 @@
 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;
@@ -30,6 +31,7 @@
 use std::os::raw::c_char;
 use std::os::unix::io::FromRawFd;
 use std::slice;
+use std::sync::Mutex;
 
 /// Rust wrapper around Binder remotable objects.
 ///
@@ -97,10 +99,7 @@
             // ends.
             sys::AIBinder_new(class.into(), rust_object as *mut c_void)
         };
-        let mut binder = Binder {
-            ibinder,
-            rust_object,
-        };
+        let mut binder = Binder { ibinder, rust_object };
         binder.mark_stability(stability);
         binder
     }
@@ -335,11 +334,18 @@
         // We don't own this file, so we need to be careful not to drop it.
         let file = ManuallyDrop::new(File::from_raw_fd(fd));
 
-        if args.is_null() {
+        if args.is_null() && num_args != 0 {
             return StatusCode::UNEXPECTED_NULL as status_t;
         }
-        let args = slice::from_raw_parts(args, num_args as usize);
-        let args: Vec<_> = args.iter().map(|s| CStr::from_ptr(*s)).collect();
+
+        let args = if args.is_null() || num_args == 0 {
+            vec![]
+        } else {
+            slice::from_raw_parts(args, num_args as usize)
+                .iter()
+                .map(|s| CStr::from_ptr(*s))
+                .collect()
+        };
 
         let object = sys::AIBinder_getUserData(binder);
         let binder: &T = &*(object as *const T);
@@ -413,10 +419,7 @@
         // We are transferring the ownership of the AIBinder into the new Binder
         // object.
         let mut ibinder = ManuallyDrop::new(ibinder);
-        Ok(Binder {
-            ibinder: ibinder.as_native_mut(),
-            rust_object: userdata as *mut B,
-        })
+        Ok(Binder { ibinder: ibinder.as_native_mut(), rust_object: userdata as *mut B })
     }
 }
 
@@ -486,6 +489,8 @@
 /// If persist is true then shut down will be blocked until this function is called again with
 /// persist false. If this is to be the initial state, call this function before calling
 /// register_lazy_service.
+///
+/// Consider using [`LazyServiceGuard`] rather than calling this directly.
 pub fn force_lazy_services_persist(persist: bool) {
     unsafe {
         // Safety: No borrowing or transfer of ownership occurs here.
@@ -493,6 +498,59 @@
     }
 }
 
+/// An RAII object to ensure a process which registers lazy services is not killed. During the
+/// lifetime of any of these objects the service manager will not not kill the process even if none
+/// of its lazy services are in use.
+#[must_use]
+#[derive(Debug)]
+pub struct LazyServiceGuard {
+    // Prevent construction outside this module.
+    _private: (),
+}
+
+lazy_static! {
+    // Count of how many LazyServiceGuard objects are in existence.
+    static ref GUARD_COUNT: Mutex<u64> = Mutex::new(0);
+}
+
+impl LazyServiceGuard {
+    /// Create a new LazyServiceGuard to prevent the service manager prematurely killing this
+    /// process.
+    pub fn new() -> Self {
+        let mut count = GUARD_COUNT.lock().unwrap();
+        *count += 1;
+        if *count == 1 {
+            // It's important that we make this call with the mutex held, to make sure
+            // that multiple calls (e.g. if the count goes 1 -> 0 -> 1) are correctly
+            // sequenced. (That also means we can't just use an AtomicU64.)
+            force_lazy_services_persist(true);
+        }
+        Self { _private: () }
+    }
+}
+
+impl Drop for LazyServiceGuard {
+    fn drop(&mut self) {
+        let mut count = GUARD_COUNT.lock().unwrap();
+        *count -= 1;
+        if *count == 0 {
+            force_lazy_services_persist(false);
+        }
+    }
+}
+
+impl Clone for LazyServiceGuard {
+    fn clone(&self) -> Self {
+        Self::new()
+    }
+}
+
+impl Default for LazyServiceGuard {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
 /// Tests often create a base BBinder instance; so allowing the unit
 /// type to be remotable translates nicely to Binder::new(()).
 impl Remotable for () {
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index 256fa8b..53a24af 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -22,10 +22,10 @@
 use crate::sys;
 
 use std::convert::TryInto;
+use std::fmt;
 use std::marker::PhantomData;
 use std::mem::ManuallyDrop;
 use std::ptr::{self, NonNull};
-use std::fmt;
 
 mod file_descriptor;
 mod parcelable;
@@ -33,8 +33,8 @@
 
 pub use self::file_descriptor::ParcelFileDescriptor;
 pub use self::parcelable::{
-    Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
-    Parcelable, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
+    Deserialize, DeserializeArray, DeserializeOption, Parcelable, Serialize, SerializeArray,
+    SerializeOption, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
 };
 pub use self::parcelable_holder::{ParcelableHolder, ParcelableMetadata};
 
@@ -78,9 +78,7 @@
             // a valid pointer. If it fails, the process will crash.
             sys::AParcel_create()
         };
-        Self {
-            ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer")
-        }
+        Self { ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer") }
     }
 
     /// Create an owned reference to a parcel object from a raw pointer.
@@ -116,10 +114,7 @@
         // lifetime of the returned `BorrowedParcel` is tied to `self`, so the
         // borrow checker will ensure that the `AParcel` can only be accessed
         // via the `BorrowParcel` until it goes out of scope.
-        BorrowedParcel {
-            ptr: self.ptr,
-            _lifetime: PhantomData,
-        }
+        BorrowedParcel { ptr: self.ptr, _lifetime: PhantomData }
     }
 
     /// Get an immutable borrowed view into the contents of this `Parcel`.
@@ -127,9 +122,7 @@
         // Safety: Parcel and BorrowedParcel are both represented in the same
         // way as a NonNull<sys::AParcel> due to their use of repr(transparent),
         // so casting references as done here is valid.
-        unsafe {
-            &*(self as *const Parcel as *const BorrowedParcel<'_>)
-        }
+        unsafe { &*(self as *const Parcel as *const BorrowedParcel<'_>) }
     }
 }
 
@@ -165,10 +158,7 @@
     /// since this is a mutable borrow, it must have exclusive access to the
     /// AParcel for the duration of the borrow.
     pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<BorrowedParcel<'a>> {
-        Some(Self {
-            ptr: NonNull::new(ptr)?,
-            _lifetime: PhantomData,
-        })
+        Some(Self { ptr: NonNull::new(ptr)?, _lifetime: PhantomData })
     }
 
     /// Get a sub-reference to this reference to the parcel.
@@ -177,10 +167,7 @@
         // lifetime of the returned `BorrowedParcel` is tied to `self`, so the
         // borrow checker will ensure that the `AParcel` can only be accessed
         // via the `BorrowParcel` until it goes out of scope.
-        BorrowedParcel {
-            ptr: self.ptr,
-            _lifetime: PhantomData,
-        }
+        BorrowedParcel { ptr: self.ptr, _lifetime: PhantomData }
     }
 }
 
@@ -269,7 +256,7 @@
     /// ```
     pub fn sized_write<F>(&mut self, f: F) -> Result<()>
     where
-        for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
+        for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>,
     {
         let start = self.get_data_position();
         self.write(&0i32)?;
@@ -324,17 +311,17 @@
     ///
     /// This appends `size` bytes of data from `other` starting at offset
     /// `start` to the current parcel, or returns an error if not possible.
-    pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+    pub fn append_from(
+        &mut self,
+        other: &impl AsNative<sys::AParcel>,
+        start: i32,
+        size: i32,
+    ) -> Result<()> {
         let status = unsafe {
             // Safety: `Parcel::appendFrom` from C++ checks that `start`
             // and `size` are in bounds, and returns an error otherwise.
             // Both `self` and `other` always contain valid pointers.
-            sys::AParcel_appendFrom(
-                other.as_native(),
-                self.as_native_mut(),
-                start,
-                size,
-            )
+            sys::AParcel_appendFrom(other.as_native(), self.as_native_mut(), start, size)
         };
         status_result(status)
     }
@@ -406,7 +393,7 @@
     /// ```
     pub fn sized_write<F>(&mut self, f: F) -> Result<()>
     where
-        for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
+        for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>,
     {
         self.borrowed().sized_write(f)
     }
@@ -438,7 +425,12 @@
     ///
     /// This appends `size` bytes of data from `other` starting at offset
     /// `start` to the current parcel, or returns an error if not possible.
-    pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+    pub fn append_from(
+        &mut self,
+        other: &impl AsNative<sys::AParcel>,
+        start: i32,
+        size: i32,
+    ) -> Result<()> {
         self.borrowed().append_from(other, start, size)
     }
 
@@ -492,7 +484,7 @@
     ///
     pub fn sized_read<F>(&self, f: F) -> Result<()>
     where
-        for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
+        for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>,
     {
         let start = self.get_data_position();
         let parcelable_size: i32 = self.read()?;
@@ -500,17 +492,13 @@
             return Err(StatusCode::BAD_VALUE);
         }
 
-        let end = start.checked_add(parcelable_size)
-            .ok_or(StatusCode::BAD_VALUE)?;
+        let end = start.checked_add(parcelable_size).ok_or(StatusCode::BAD_VALUE)?;
         if end > self.get_data_size() {
             return Err(StatusCode::NOT_ENOUGH_DATA);
         }
 
         let subparcel = ReadableSubParcel {
-            parcel: BorrowedParcel {
-                ptr: self.ptr,
-                _lifetime: PhantomData,
-            },
+            parcel: BorrowedParcel { ptr: self.ptr, _lifetime: PhantomData },
             end_position: end,
         };
         f(subparcel)?;
@@ -633,7 +621,7 @@
     ///
     pub fn sized_read<F>(&self, f: F) -> Result<()>
     where
-        for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
+        for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>,
     {
         self.borrowed_ref().sized_read(f)
     }
@@ -716,15 +704,13 @@
 
 impl fmt::Debug for Parcel {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("Parcel")
-            .finish()
+        f.debug_struct("Parcel").finish()
     }
 }
 
 impl<'a> fmt::Debug for BorrowedParcel<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("BorrowedParcel")
-            .finish()
+        f.debug_struct("BorrowedParcel").finish()
     }
 }
 
@@ -813,10 +799,7 @@
         assert!(parcel.set_data_position(start).is_ok());
     }
 
-    assert_eq!(
-        parcel.read::<f32>().unwrap(),
-        1143139100000000000000000000.0
-    );
+    assert_eq!(parcel.read::<f32>().unwrap(), 1143139100000000000000000000.0);
     assert_eq!(parcel.read::<f32>().unwrap(), 40.043392);
 
     unsafe {
@@ -842,10 +825,7 @@
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
-    assert_eq!(
-        parcel.read::<Option<String>>().unwrap().unwrap(),
-        "Hello, Binder!",
-    );
+    assert_eq!(parcel.read::<Option<String>>().unwrap().unwrap(), "Hello, Binder!",);
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
@@ -864,13 +844,7 @@
 
     assert!(parcel.write(&["str1", "str2", "str3"][..]).is_ok());
     assert!(parcel
-        .write(
-            &[
-                String::from("str4"),
-                String::from("str5"),
-                String::from("str6"),
-            ][..]
-        )
+        .write(&[String::from("str4"), String::from("str5"), String::from("str6"),][..])
         .is_ok());
 
     let s1 = "Hello, Binder!";
@@ -882,14 +856,8 @@
         assert!(parcel.set_data_position(start).is_ok());
     }
 
-    assert_eq!(
-        parcel.read::<Vec<String>>().unwrap(),
-        ["str1", "str2", "str3"]
-    );
-    assert_eq!(
-        parcel.read::<Vec<String>>().unwrap(),
-        ["str4", "str5", "str6"]
-    );
+    assert_eq!(parcel.read::<Vec<String>>().unwrap(), ["str1", "str2", "str3"]);
+    assert_eq!(parcel.read::<Vec<String>>().unwrap(), ["str4", "str5", "str6"]);
     assert_eq!(parcel.read::<Vec<String>>().unwrap(), [s1, s2, s3]);
 }
 
@@ -900,9 +868,9 @@
 
     let arr = [1i32, 2i32, 3i32];
 
-    parcel.sized_write(|subparcel| {
-        subparcel.write(&arr[..])
-    }).expect("Could not perform sized write");
+    parcel
+        .sized_write(|subparcel| subparcel.write(&arr[..]))
+        .expect("Could not perform sized write");
 
     // i32 sub-parcel length + i32 array length + 3 i32 elements
     let expected_len = 20i32;
@@ -913,15 +881,9 @@
         parcel.set_data_position(start).unwrap();
     }
 
-    assert_eq!(
-        expected_len,
-        parcel.read().unwrap(),
-    );
+    assert_eq!(expected_len, parcel.read().unwrap(),);
 
-    assert_eq!(
-        parcel.read::<Vec<i32>>().unwrap(),
-        &arr,
-    );
+    assert_eq!(parcel.read::<Vec<i32>>().unwrap(), &arr,);
 }
 
 #[test]
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 4d3d59a..de6d649 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -15,7 +15,7 @@
  */
 
 use super::{
-    Deserialize, DeserializeArray, DeserializeOption, BorrowedParcel, Serialize, SerializeArray,
+    BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray,
     SerializeOption,
 };
 use crate::binder::AsNative;
@@ -115,10 +115,7 @@
             // descriptor. The read function passes ownership of the file
             // descriptor to its caller if it was non-null, so we must take
             // ownership of the file and ensure that it is eventually closed.
-            status_result(sys::AParcel_readParcelFileDescriptor(
-                parcel.as_native(),
-                &mut fd,
-            ))?;
+            status_result(sys::AParcel_readParcelFileDescriptor(parcel.as_native(), &mut fd))?;
         }
         if fd < 0 {
             Ok(None)
@@ -136,9 +133,7 @@
 
 impl Deserialize for ParcelFileDescriptor {
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
-        Deserialize::deserialize(parcel)
-            .transpose()
-            .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+        Deserialize::deserialize(parcel).transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
     }
 }
 
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 0c7e48d..c241e4d 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -22,8 +22,8 @@
 
 use std::convert::{TryFrom, TryInto};
 use std::ffi::c_void;
+use std::mem::{self, ManuallyDrop, MaybeUninit};
 use std::os::raw::{c_char, c_ulong};
-use std::mem::{self, MaybeUninit, ManuallyDrop};
 use std::ptr;
 use std::slice;
 
@@ -109,17 +109,14 @@
     // so the function signature matches what bindgen generates.
     let index = index as usize;
 
-    let slice: &[T] = slice::from_raw_parts(array.cast(), index+1);
+    let slice: &[T] = slice::from_raw_parts(array.cast(), index + 1);
 
     let mut parcel = match BorrowedParcel::from_raw(parcel) {
         None => return StatusCode::UNEXPECTED_NULL as status_t,
         Some(p) => p,
     };
 
-    slice[index].serialize(&mut parcel)
-                .err()
-                .unwrap_or(StatusCode::OK)
-        as status_t
+    slice[index].serialize(&mut parcel).err().unwrap_or(StatusCode::OK) as status_t
 }
 
 /// Helper trait for types that can be deserialized as arrays.
@@ -265,10 +262,7 @@
 ///
 /// The opaque data pointer passed to the array read function must be a mutable
 /// pointer to an `Option<Vec<MaybeUninit<T>>>`.
-unsafe extern "C" fn allocate_vec<T>(
-    data: *mut c_void,
-    len: i32,
-) -> bool {
+unsafe extern "C" fn allocate_vec<T>(data: *mut c_void, len: i32) -> bool {
     let vec = &mut *(data as *mut Option<Vec<MaybeUninit<T>>>);
     if len < 0 {
         *vec = None;
@@ -286,7 +280,6 @@
     true
 }
 
-
 macro_rules! parcelable_primitives {
     {
         $(
@@ -303,11 +296,7 @@
     // has the same alignment and size as T, so the pointer to the vector
     // allocation will be compatible.
     let mut vec = ManuallyDrop::new(vec);
-    Vec::from_raw_parts(
-        vec.as_mut_ptr().cast(),
-        vec.len(),
-        vec.capacity(),
-    )
+    Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity())
 }
 
 macro_rules! impl_parcelable {
@@ -522,11 +511,7 @@
                 // `AParcel`. If the string pointer is null,
                 // `AParcel_writeString` requires that the length is -1 to
                 // indicate that we want to serialize a null string.
-                status_result(sys::AParcel_writeString(
-                    parcel.as_native_mut(),
-                    ptr::null(),
-                    -1,
-                ))
+                status_result(sys::AParcel_writeString(parcel.as_native_mut(), ptr::null(), -1))
             },
             Some(s) => unsafe {
                 // Safety: `Parcel` always contains a valid pointer to an
@@ -540,10 +525,7 @@
                 status_result(sys::AParcel_writeString(
                     parcel.as_native_mut(),
                     s.as_ptr() as *const c_char,
-                    s.as_bytes()
-                        .len()
-                        .try_into()
-                        .or(Err(StatusCode::BAD_VALUE))?,
+                    s.as_bytes().len().try_into().or(Err(StatusCode::BAD_VALUE))?,
                 ))
             },
         }
@@ -602,9 +584,7 @@
 
 impl Deserialize for String {
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
-        Deserialize::deserialize(parcel)
-            .transpose()
-            .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+        Deserialize::deserialize(parcel).transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
     }
 }
 
@@ -704,10 +684,7 @@
             // and `Status` always contains a valid pointer to an `AStatus`, so
             // both parameters are valid and safe. This call does not take
             // ownership of either of its parameters.
-            status_result(sys::AParcel_writeStatusHeader(
-                parcel.as_native_mut(),
-                self.as_native(),
-            ))
+            status_result(sys::AParcel_writeStatusHeader(parcel.as_native_mut(), self.as_native()))
         }
     }
 }
@@ -881,8 +858,7 @@
                     Ok(())
                 } else {
                     use $crate::Parcelable;
-                    this.get_or_insert_with(Self::default)
-                        .read_from_parcel(parcel)
+                    this.get_or_insert_with(Self::default).read_from_parcel(parcel)
                 }
             }
         }
@@ -915,8 +891,8 @@
 
 #[cfg(test)]
 mod tests {
-    use crate::parcel::Parcel;
     use super::*;
+    use crate::parcel::Parcel;
 
     #[test]
     fn test_custom_parcelable() {
@@ -934,11 +910,11 @@
         impl Deserialize for Custom {
             fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
                 Ok(Custom(
-                        parcel.read()?,
-                        parcel.read()?,
-                        parcel.read()?,
-                        parcel.read::<Option<Vec<String>>>()?.unwrap(),
-                        ))
+                    parcel.read()?,
+                    parcel.read()?,
+                    parcel.read()?,
+                    parcel.read::<Option<Vec<String>>>()?.unwrap(),
+                ))
             }
         }
 
@@ -1157,12 +1133,7 @@
 
         assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
 
-        let f32s = [
-            std::f32::NAN,
-            std::f32::INFINITY,
-            1.23456789,
-            std::f32::EPSILON,
-        ];
+        let f32s = [std::f32::NAN, std::f32::INFINITY, 1.23456789, std::f32::EPSILON];
 
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
@@ -1178,12 +1149,7 @@
         assert!(vec[0].is_nan());
         assert_eq!(vec[1..], f32s[1..]);
 
-        let f64s = [
-            std::f64::NAN,
-            std::f64::INFINITY,
-            1.234567890123456789,
-            std::f64::EPSILON,
-        ];
+        let f64s = [std::f64::NAN, std::f64::INFINITY, 1.234567890123456789, std::f64::EPSILON];
 
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index 432da5d..c829d37 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -48,10 +48,7 @@
 #[derive(Debug, Clone)]
 enum ParcelableHolderData {
     Empty,
-    Parcelable {
-        parcelable: Arc<dyn AnyParcelable>,
-        name: String,
-    },
+    Parcelable { parcelable: Arc<dyn AnyParcelable>, name: String },
     Parcel(Parcel),
 }
 
@@ -77,10 +74,7 @@
 impl ParcelableHolder {
     /// Construct a new `ParcelableHolder` with the given stability.
     pub fn new(stability: Stability) -> Self {
-        Self {
-            data: Mutex::new(ParcelableHolderData::Empty),
-            stability,
-        }
+        Self { data: Mutex::new(ParcelableHolderData::Empty), stability }
     }
 
     /// Reset the contents of this `ParcelableHolder`.
@@ -101,10 +95,8 @@
             return Err(StatusCode::BAD_VALUE);
         }
 
-        *self.data.get_mut().unwrap() = ParcelableHolderData::Parcelable {
-            parcelable: p,
-            name: T::get_descriptor().into(),
-        };
+        *self.data.get_mut().unwrap() =
+            ParcelableHolderData::Parcelable { parcelable: p, name: T::get_descriptor().into() };
 
         Ok(())
     }
@@ -130,10 +122,7 @@
         let mut data = self.data.lock().unwrap();
         match *data {
             ParcelableHolderData::Empty => Ok(None),
-            ParcelableHolderData::Parcelable {
-                ref parcelable,
-                ref name,
-            } => {
+            ParcelableHolderData::Parcelable { ref parcelable, ref name } => {
                 if name != parcelable_desc {
                     return Err(StatusCode::BAD_VALUE);
                 }
@@ -199,10 +188,7 @@
         let mut data = self.data.lock().unwrap();
         match *data {
             ParcelableHolderData::Empty => parcel.write(&0i32),
-            ParcelableHolderData::Parcelable {
-                ref parcelable,
-                ref name,
-            } => {
+            ParcelableHolderData::Parcelable { ref parcelable, ref name } => {
                 let length_start = parcel.get_data_position();
                 parcel.write(&0i32)?;
 
@@ -251,9 +237,7 @@
         // TODO: C++ ParcelableHolder accepts sizes up to SIZE_MAX here, but we
         // only go up to i32::MAX because that's what our API uses everywhere
         let data_start = parcel.get_data_position();
-        let data_end = data_start
-            .checked_add(data_size)
-            .ok_or(StatusCode::BAD_VALUE)?;
+        let data_end = data_start.checked_add(data_size).ok_or(StatusCode::BAD_VALUE)?;
 
         let mut new_parcel = Parcel::new();
         new_parcel.append_from(parcel, data_start, data_size)?;
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 4df557b..254efae 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -22,7 +22,8 @@
 };
 use crate::error::{status_result, Result, StatusCode};
 use crate::parcel::{
-    Parcel, BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
+    BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize,
+    SerializeArray, SerializeOption,
 };
 use crate::sys;
 
@@ -132,6 +133,14 @@
     }
 }
 
+fn interface_cast<T: FromIBinder + ?Sized>(service: Option<SpIBinder>) -> Result<Strong<T>> {
+    if let Some(service) = service {
+        FromIBinder::try_from(service)
+    } else {
+        Err(StatusCode::NAME_NOT_FOUND)
+    }
+}
+
 pub mod unstable_api {
     use super::{sys, SpIBinder};
 
@@ -431,10 +440,7 @@
 
 impl Deserialize for SpIBinder {
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<SpIBinder> {
-        parcel
-            .read_binder()
-            .transpose()
-            .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+        parcel.read_binder().transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
     }
 }
 
@@ -563,6 +569,9 @@
 /// The cookie in this struct represents an Arc<F> for the owned callback.
 /// This struct owns a ref-count of it, and so does every binder that we
 /// have been linked with.
+///
+/// Dropping the `DeathRecipient` will `unlink_to_death` any binders it is
+/// currently linked to.
 #[repr(C)]
 pub struct DeathRecipient {
     recipient: *mut sys::AIBinder_DeathRecipient,
@@ -610,7 +619,10 @@
             //
             // All uses of linkToDeath in this file correctly increment the
             // ref-count that this onUnlinked callback will decrement.
-            sys::AIBinder_DeathRecipient_setOnUnlinked(recipient, Some(Self::cookie_decr_refcount::<F>));
+            sys::AIBinder_DeathRecipient_setOnUnlinked(
+                recipient,
+                Some(Self::cookie_decr_refcount::<F>),
+            );
         }
         DeathRecipient {
             recipient,
@@ -776,21 +788,13 @@
 /// Retrieve an existing service for a particular interface, blocking for a few
 /// seconds if it doesn't yet exist.
 pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
-    let service = get_service(name);
-    match service {
-        Some(service) => FromIBinder::try_from(service),
-        None => Err(StatusCode::NAME_NOT_FOUND),
-    }
+    interface_cast(get_service(name))
 }
 
 /// Retrieve an existing service for a particular interface, or start it if it
 /// is configured as a dynamic service and isn't yet started.
 pub fn wait_for_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
-    let service = wait_for_service(name);
-    match service {
-        Some(service) => FromIBinder::try_from(service),
-        None => Err(StatusCode::NAME_NOT_FOUND),
-    }
+    interface_cast(wait_for_service(name))
 }
 
 /// Check if a service is declared (e.g. in a VINTF manifest)
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index 0aef744..cc18741 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -124,7 +124,8 @@
     /// kernel is too old to support this feature.
     pub fn with_calling_sid<T, F>(check_permission: F) -> T
     where
-        for<'a> F: FnOnce(Option<&'a std::ffi::CStr>) -> T {
+        for<'a> F: FnOnce(Option<&'a std::ffi::CStr>) -> T,
+    {
         // Safety: AIBinder_getCallingSid returns a c-string pointer
         // that is valid for a transaction. Also, the string returned
         // is thread local. By restricting the lifetime of the CStr
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index c9d6af0..4e10fa9 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -60,9 +60,7 @@
         if let Some(extension_name) = extension_name {
             let extension =
                 BnTest::new_binder(TestService::new(&extension_name), BinderFeatures::default());
-            service
-                .set_extension(&mut extension.as_binder())
-                .expect("Could not add extension");
+            service.set_extension(&mut extension.as_binder()).expect("Could not add extension");
         }
         binder::add_service(&service_name, service.as_binder())
             .expect("Could not register service");
@@ -73,10 +71,7 @@
 }
 
 fn print_usage() {
-    eprintln!(
-        "Usage: {} SERVICE_NAME [EXTENSION_NAME]",
-        RUST_SERVICE_BINARY
-    );
+    eprintln!("Usage: {} SERVICE_NAME [EXTENSION_NAME]", RUST_SERVICE_BINARY);
     eprintln!(concat!(
         "Spawn a Binder test service identified by SERVICE_NAME,",
         " optionally with an extesion named EXTENSION_NAME",
@@ -90,10 +85,7 @@
 
 impl TestService {
     fn new(s: &str) -> Self {
-        Self {
-            s: s.to_string(),
-            dump_args: Mutex::new(Vec::new()),
-        }
+        Self { s: s.to_string(), dump_args: Mutex::new(Vec::new()) }
     }
 }
 
@@ -111,11 +103,15 @@
     fn try_from(c: u32) -> Result<Self, Self::Error> {
         match c {
             _ if c == TestTransactionCode::Test as u32 => Ok(TestTransactionCode::Test),
-            _ if c == TestTransactionCode::GetDumpArgs as u32 => Ok(TestTransactionCode::GetDumpArgs),
+            _ if c == TestTransactionCode::GetDumpArgs as u32 => {
+                Ok(TestTransactionCode::GetDumpArgs)
+            }
             _ if c == TestTransactionCode::GetSelinuxContext as u32 => {
                 Ok(TestTransactionCode::GetSelinuxContext)
             }
-            _ if c == TestTransactionCode::GetIsHandlingTransaction as u32 => Ok(TestTransactionCode::GetIsHandlingTransaction),
+            _ if c == TestTransactionCode::GetIsHandlingTransaction as u32 => {
+                Ok(TestTransactionCode::GetIsHandlingTransaction)
+            }
             _ => Err(StatusCode::UNKNOWN_TRANSACTION),
         }
     }
@@ -200,15 +196,16 @@
         TestTransactionCode::Test => reply.write(&service.test()?),
         TestTransactionCode::GetDumpArgs => reply.write(&service.get_dump_args()?),
         TestTransactionCode::GetSelinuxContext => reply.write(&service.get_selinux_context()?),
-        TestTransactionCode::GetIsHandlingTransaction => reply.write(&service.get_is_handling_transaction()?),
+        TestTransactionCode::GetIsHandlingTransaction => {
+            reply.write(&service.get_is_handling_transaction()?)
+        }
     }
 }
 
 impl ITest for BpTest {
     fn test(&self) -> Result<String, StatusCode> {
         let reply =
-            self.binder
-                .transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
+            self.binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
         reply.read()
     }
 
@@ -243,31 +240,45 @@
         let binder = self.binder.clone();
         P::spawn(
             move || binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(())),
-            |reply| async move { reply?.read() }
+            |reply| async move { reply?.read() },
         )
     }
 
     fn get_dump_args(&self) -> binder::BoxFuture<'static, Result<Vec<String>, StatusCode>> {
         let binder = self.binder.clone();
         P::spawn(
-            move || binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(())),
-            |reply| async move { reply?.read() }
+            move || {
+                binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(()))
+            },
+            |reply| async move { reply?.read() },
         )
     }
 
     fn get_selinux_context(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>> {
         let binder = self.binder.clone();
         P::spawn(
-            move || binder.transact(TestTransactionCode::GetSelinuxContext as TransactionCode, 0, |_| Ok(())),
-            |reply| async move { reply?.read() }
+            move || {
+                binder.transact(
+                    TestTransactionCode::GetSelinuxContext as TransactionCode,
+                    0,
+                    |_| Ok(()),
+                )
+            },
+            |reply| async move { reply?.read() },
         )
     }
 
     fn get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>> {
         let binder = self.binder.clone();
         P::spawn(
-            move || binder.transact(TestTransactionCode::GetIsHandlingTransaction as TransactionCode, 0, |_| Ok(())),
-            |reply| async move { reply?.read() }
+            move || {
+                binder.transact(
+                    TestTransactionCode::GetIsHandlingTransaction as TransactionCode,
+                    0,
+                    |_| Ok(()),
+                )
+            },
+            |reply| async move { reply?.read() },
         )
     }
 }
@@ -374,7 +385,7 @@
 
     use binder_tokio::Tokio;
 
-    use super::{BnTest, ITest, IATest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
+    use super::{BnTest, IATest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
 
     pub struct ScopedServiceProcess(Child);
 
@@ -405,9 +416,7 @@
     impl Drop for ScopedServiceProcess {
         fn drop(&mut self) {
             self.0.kill().expect("Could not kill child process");
-            self.0
-                .wait()
-                .expect("Could not wait for child process to die");
+            self.0.wait().expect("Could not wait for child process to die");
         }
     }
 
@@ -428,10 +437,7 @@
         );
 
         // The service manager service isn't an ITest, so this must fail.
-        assert_eq!(
-            binder::get_interface::<dyn ITest>("manager").err(),
-            Some(StatusCode::BAD_TYPE)
-        );
+        assert_eq!(binder::get_interface::<dyn ITest>("manager").err(), Some(StatusCode::BAD_TYPE));
         assert_eq!(
             binder::get_interface::<dyn IATest<Tokio>>("manager").err(),
             Some(StatusCode::BAD_TYPE)
@@ -450,7 +456,9 @@
             Some(StatusCode::NAME_NOT_FOUND)
         );
         assert_eq!(
-            binder_tokio::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").await.err(),
+            binder_tokio::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist")
+                .await
+                .err(),
             Some(StatusCode::NAME_NOT_FOUND)
         );
 
@@ -511,8 +519,9 @@
     async fn trivial_client_async() {
         let service_name = "trivial_client_test";
         let _process = ScopedServiceProcess::new(service_name);
-        let test_client: Strong<dyn IATest<Tokio>> =
-            binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+        let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+            .await
+            .expect("Did not get manager binder service");
         assert_eq!(test_client.test().await.unwrap(), "trivial_client_test");
     }
 
@@ -529,8 +538,9 @@
     async fn wait_for_trivial_client_async() {
         let service_name = "wait_for_trivial_client_test";
         let _process = ScopedServiceProcess::new(service_name);
-        let test_client: Strong<dyn IATest<Tokio>> =
-            binder_tokio::wait_for_interface(service_name).await.expect("Did not get manager binder service");
+        let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::wait_for_interface(service_name)
+            .await
+            .expect("Did not get manager binder service");
         assert_eq!(test_client.test().await.unwrap(), "wait_for_trivial_client_test");
     }
 
@@ -539,9 +549,7 @@
             let mut out_ptr = ptr::null_mut();
             assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
             assert!(!out_ptr.is_null());
-            CStr::from_ptr(out_ptr)
-                .to_str()
-                .expect("context was invalid UTF-8")
+            CStr::from_ptr(out_ptr).to_str().expect("context was invalid UTF-8")
         }
     }
 
@@ -551,18 +559,16 @@
         let _process = ScopedServiceProcess::new(service_name);
         let test_client: Strong<dyn ITest> =
             binder::get_interface(service_name).expect("Did not get manager binder service");
-        assert_eq!(
-            test_client.get_selinux_context().unwrap(),
-            get_expected_selinux_context()
-        );
+        assert_eq!(test_client.get_selinux_context().unwrap(), get_expected_selinux_context());
     }
 
     #[tokio::test]
     async fn get_selinux_context_async() {
         let service_name = "get_selinux_context_async";
         let _process = ScopedServiceProcess::new(service_name);
-        let test_client: Strong<dyn IATest<Tokio>> =
-            binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+        let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+            .await
+            .expect("Did not get manager binder service");
         assert_eq!(
             test_client.get_selinux_context().await.unwrap(),
             get_expected_selinux_context()
@@ -586,13 +592,11 @@
     async fn get_selinux_context_async_to_sync() {
         let service_name = "get_selinux_context";
         let _process = ScopedServiceProcess::new(service_name);
-        let test_client: Strong<dyn IATest<Tokio>> =
-            binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+        let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+            .await
+            .expect("Did not get manager binder service");
         let test_client = test_client.into_sync();
-        assert_eq!(
-            test_client.get_selinux_context().unwrap(),
-            get_expected_selinux_context()
-        );
+        assert_eq!(test_client.get_selinux_context().unwrap(), get_expected_selinux_context());
     }
 
     struct Bools {
@@ -605,10 +609,7 @@
             self.binder_died.load(Ordering::Relaxed)
         }
         fn assert_died(&self) {
-            assert!(
-                self.is_dead(),
-                "Did not receive death notification"
-            );
+            assert!(self.is_dead(), "Did not receive death notification");
         }
         fn assert_dropped(&self) {
             assert!(
@@ -639,9 +640,7 @@
 
         let mut death_recipient = {
             let flag = binder_died.clone();
-            let set_on_drop = SetOnDrop {
-                binder_dealloc: binder_dealloc.clone(),
-            };
+            let set_on_drop = SetOnDrop { binder_dealloc: binder_dealloc.clone() };
             DeathRecipient::new(move || {
                 flag.store(true, Ordering::Relaxed);
                 // Force the closure to take ownership of set_on_drop. When the closure is
@@ -650,14 +649,9 @@
             })
         };
 
-        binder
-            .link_to_death(&mut death_recipient)
-            .expect("link_to_death failed");
+        binder.link_to_death(&mut death_recipient).expect("link_to_death failed");
 
-        let bools = Bools {
-            binder_died,
-            binder_dealloc,
-        };
+        let bools = Bools { binder_died, binder_dealloc };
 
         (bools, death_recipient)
     }
@@ -675,9 +669,7 @@
         let (bools, recipient) = register_death_notification(&mut remote);
 
         drop(service_process);
-        remote
-            .ping_binder()
-            .expect_err("Service should have died already");
+        remote.ping_binder().expect_err("Service should have died already");
 
         // Pause to ensure any death notifications get delivered
         thread::sleep(Duration::from_secs(1));
@@ -701,22 +693,15 @@
 
         let (bools, mut recipient) = register_death_notification(&mut remote);
 
-        remote
-            .unlink_to_death(&mut recipient)
-            .expect("Could not unlink death notifications");
+        remote.unlink_to_death(&mut recipient).expect("Could not unlink death notifications");
 
         drop(service_process);
-        remote
-            .ping_binder()
-            .expect_err("Service should have died already");
+        remote.ping_binder().expect_err("Service should have died already");
 
         // Pause to ensure any death notifications get delivered
         thread::sleep(Duration::from_secs(1));
 
-        assert!(
-            !bools.is_dead(),
-            "Received unexpected death notification after unlinking",
-        );
+        assert!(!bools.is_dead(), "Received unexpected death notification after unlinking",);
 
         bools.assert_not_dropped();
         drop(recipient);
@@ -771,9 +756,7 @@
             let dump_args = ["dump", "args", "for", "testing"];
 
             let null_out = File::open("/dev/null").expect("Could not open /dev/null");
-            remote
-                .dump(&null_out, &dump_args)
-                .expect("Could not dump remote service");
+            remote.dump(&null_out, &dump_args).expect("Could not dump remote service");
 
             let remote_args = test_client.get_dump_args().expect("Could not fetched dumped args");
             assert_eq!(dump_args, remote_args[..], "Remote args don't match call to dump");
@@ -799,9 +782,7 @@
             let mut remote = binder::get_service(service_name);
             assert!(remote.is_binder_alive());
 
-            let extension = remote
-                .get_extension()
-                .expect("Could not check for an extension");
+            let extension = remote.get_extension().expect("Could not check for an extension");
             assert!(extension.is_none());
         }
 
@@ -811,9 +792,7 @@
             let mut remote = binder::get_service(service_name);
             assert!(remote.is_binder_alive());
 
-            let maybe_extension = remote
-                .get_extension()
-                .expect("Could not check for an extension");
+            let maybe_extension = remote.get_extension().expect("Could not check for an extension");
 
             let extension = maybe_extension.expect("Remote binder did not have an extension");
 
@@ -850,15 +829,12 @@
     #[test]
     fn reassociate_rust_binder() {
         let service_name = "testing_service";
-        let service_ibinder = BnTest::new_binder(
-            TestService::new(service_name),
-            BinderFeatures::default(),
-        )
-        .as_binder();
+        let service_ibinder =
+            BnTest::new_binder(TestService::new(service_name), BinderFeatures::default())
+                .as_binder();
 
-        let service: Strong<dyn ITest> = service_ibinder
-            .into_interface()
-            .expect("Could not reassociate the generic ibinder");
+        let service: Strong<dyn ITest> =
+            service_ibinder.into_interface().expect("Could not reassociate the generic ibinder");
 
         assert_eq!(service.test().unwrap(), service_name);
     }
@@ -866,10 +842,7 @@
     #[test]
     fn weak_binder_upgrade() {
         let service_name = "testing_service";
-        let service = BnTest::new_binder(
-            TestService::new(service_name),
-            BinderFeatures::default(),
-        );
+        let service = BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
 
         let weak = Strong::downgrade(&service);
 
@@ -882,10 +855,8 @@
     fn weak_binder_upgrade_dead() {
         let service_name = "testing_service";
         let weak = {
-            let service = BnTest::new_binder(
-                TestService::new(service_name),
-                BinderFeatures::default(),
-            );
+            let service =
+                BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
 
             Strong::downgrade(&service)
         };
@@ -896,10 +867,7 @@
     #[test]
     fn weak_binder_clone() {
         let service_name = "testing_service";
-        let service = BnTest::new_binder(
-            TestService::new(service_name),
-            BinderFeatures::default(),
-        );
+        let service = BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
 
         let weak = Strong::downgrade(&service);
         let cloned = weak.clone();
@@ -915,14 +883,10 @@
     #[test]
     #[allow(clippy::eq_op)]
     fn binder_ord() {
-        let service1 = BnTest::new_binder(
-            TestService::new("testing_service1"),
-            BinderFeatures::default(),
-        );
-        let service2 = BnTest::new_binder(
-            TestService::new("testing_service2"),
-            BinderFeatures::default(),
-        );
+        let service1 =
+            BnTest::new_binder(TestService::new("testing_service1"), BinderFeatures::default());
+        let service2 =
+            BnTest::new_binder(TestService::new("testing_service2"), BinderFeatures::default());
 
         assert!((service1 >= service1));
         assert!((service1 <= service1));
@@ -931,20 +895,20 @@
 
     #[test]
     fn binder_parcel_mixup() {
-        let service1 = BnTest::new_binder(
-            TestService::new("testing_service1"),
-            BinderFeatures::default(),
-        );
-        let service2 = BnTest::new_binder(
-            TestService::new("testing_service2"),
-            BinderFeatures::default(),
-        );
+        let service1 =
+            BnTest::new_binder(TestService::new("testing_service1"), BinderFeatures::default());
+        let service2 =
+            BnTest::new_binder(TestService::new("testing_service2"), BinderFeatures::default());
 
         let service1 = service1.as_binder();
         let service2 = service2.as_binder();
 
         let parcel = service1.prepare_transact().unwrap();
-        let res = service2.submit_transact(super::TestTransactionCode::Test as TransactionCode, parcel, 0);
+        let res = service2.submit_transact(
+            super::TestTransactionCode::Test as TransactionCode,
+            parcel,
+            0,
+        );
 
         match res {
             Ok(_) => panic!("submit_transact should fail"),
@@ -967,15 +931,18 @@
         // Should also be false in spawned thread.
         std::thread::spawn(|| {
             assert!(!binder::is_handling_transaction());
-        }).join().unwrap();
+        })
+        .join()
+        .unwrap();
     }
 
     #[tokio::test]
     async fn get_is_handling_transaction_async() {
         let service_name = "get_is_handling_transaction_async";
         let _process = ScopedServiceProcess::new(service_name);
-        let test_client: Strong<dyn IATest<Tokio>> =
-            binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+        let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+            .await
+            .expect("Did not get manager binder service");
         // Should be true externally.
         assert!(test_client.get_is_handling_transaction().await.unwrap());
 
@@ -985,11 +952,15 @@
         // Should also be false in spawned task.
         tokio::spawn(async {
             assert!(!binder::is_handling_transaction());
-        }).await.unwrap();
+        })
+        .await
+        .unwrap();
 
         // And in spawn_blocking task.
         tokio::task::spawn_blocking(|| {
             assert!(!binder::is_handling_transaction());
-        }).await.unwrap();
+        })
+        .await
+        .unwrap();
     }
 }
diff --git a/libs/binder/rust/tests/serialization.cpp b/libs/binder/rust/tests/serialization.cpp
index ec780f2..3f59dab 100644
--- a/libs/binder/rust/tests/serialization.cpp
+++ b/libs/binder/rust/tests/serialization.cpp
@@ -381,7 +381,7 @@
     string expected = "TestingFileDescriptors";
     vector<char> buf(expected.length());
     base::ReadFully(file_descriptors[0].release(), buf.data(), buf.size());
-    ASSERT_EQ(expected, string(buf.data()));
+    ASSERT_EQ(expected, string(buf.data(), expected.length()));
 }
 
 TEST_F(SerializationTest, SerializeIBinder) {
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index b62da7b..6220db4 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -23,7 +23,7 @@
 };
 // Import from impl API for testing only, should not be necessary as long as you
 // are using AIDL.
-use binder::binder_impl::{BorrowedParcel, Binder, TransactionCode};
+use binder::binder_impl::{Binder, BorrowedParcel, TransactionCode};
 
 use std::ffi::{c_void, CStr, CString};
 use std::sync::Once;
@@ -64,13 +64,7 @@
 macro_rules! assert {
     ($expr:expr) => {
         if !$expr {
-            eprintln!(
-                "assertion failed: `{:?}`, {}:{}:{}",
-                $expr,
-                file!(),
-                line!(),
-                column!()
-            );
+            eprintln!("assertion failed: `{:?}`, {}:{}:{}", $expr, file!(), line!(), column!());
             return Err(StatusCode::FAILED_TRANSACTION);
         }
     };
@@ -117,11 +111,9 @@
 ) -> Result<(), StatusCode> {
     match code {
         bindings::Transaction_TEST_BOOL => {
-            assert_eq!(parcel.read::<bool>()?, true);
-            assert_eq!(parcel.read::<bool>()?, false);
-            assert_eq!(parcel.read::<Vec<bool>>()?, unsafe {
-                bindings::TESTDATA_BOOL
-            });
+            assert!(parcel.read::<bool>()?);
+            assert!(!parcel.read::<bool>()?);
+            assert_eq!(parcel.read::<Vec<bool>>()?, unsafe { bindings::TESTDATA_BOOL });
             assert_eq!(parcel.read::<Option<Vec<bool>>>()?, None);
 
             reply.write(&true)?;
@@ -148,9 +140,7 @@
             assert_eq!(parcel.read::<u16>()?, 0);
             assert_eq!(parcel.read::<u16>()?, 1);
             assert_eq!(parcel.read::<u16>()?, u16::max_value());
-            assert_eq!(parcel.read::<Vec<u16>>()?, unsafe {
-                bindings::TESTDATA_CHARS
-            });
+            assert_eq!(parcel.read::<Vec<u16>>()?, unsafe { bindings::TESTDATA_CHARS });
             assert_eq!(parcel.read::<Option<Vec<u16>>>()?, None);
 
             reply.write(&0u16)?;
@@ -163,9 +153,7 @@
             assert_eq!(parcel.read::<i32>()?, 0);
             assert_eq!(parcel.read::<i32>()?, 1);
             assert_eq!(parcel.read::<i32>()?, i32::max_value());
-            assert_eq!(parcel.read::<Vec<i32>>()?, unsafe {
-                bindings::TESTDATA_I32
-            });
+            assert_eq!(parcel.read::<Vec<i32>>()?, unsafe { bindings::TESTDATA_I32 });
             assert_eq!(parcel.read::<Option<Vec<i32>>>()?, None);
 
             reply.write(&0i32)?;
@@ -178,9 +166,7 @@
             assert_eq!(parcel.read::<i64>()?, 0);
             assert_eq!(parcel.read::<i64>()?, 1);
             assert_eq!(parcel.read::<i64>()?, i64::max_value());
-            assert_eq!(parcel.read::<Vec<i64>>()?, unsafe {
-                bindings::TESTDATA_I64
-            });
+            assert_eq!(parcel.read::<Vec<i64>>()?, unsafe { bindings::TESTDATA_I64 });
             assert_eq!(parcel.read::<Option<Vec<i64>>>()?, None);
 
             reply.write(&0i64)?;
@@ -193,9 +179,7 @@
             assert_eq!(parcel.read::<u64>()?, 0);
             assert_eq!(parcel.read::<u64>()?, 1);
             assert_eq!(parcel.read::<u64>()?, u64::max_value());
-            assert_eq!(parcel.read::<Vec<u64>>()?, unsafe {
-                bindings::TESTDATA_U64
-            });
+            assert_eq!(parcel.read::<Vec<u64>>()?, unsafe { bindings::TESTDATA_U64 });
             assert_eq!(parcel.read::<Option<Vec<u64>>>()?, None);
 
             reply.write(&0u64)?;
@@ -232,16 +216,9 @@
             let s: Option<String> = parcel.read()?;
             assert_eq!(s, None);
             let s: Option<Vec<Option<String>>> = parcel.read()?;
-            for (s, expected) in s
-                .unwrap()
-                .iter()
-                .zip(unsafe { bindings::TESTDATA_STRS }.iter())
-            {
-                let expected = unsafe {
-                    expected
-                        .as_ref()
-                        .and_then(|e| CStr::from_ptr(e).to_str().ok())
-                };
+            for (s, expected) in s.unwrap().iter().zip(unsafe { bindings::TESTDATA_STRS }.iter()) {
+                let expected =
+                    unsafe { expected.as_ref().and_then(|e| CStr::from_ptr(e).to_str().ok()) };
                 assert_eq!(s.as_deref(), expected);
             }
             let s: Option<Vec<Option<String>>> = parcel.read()?;
@@ -252,10 +229,7 @@
                     .iter()
                     .map(|s| {
                         s.as_ref().map(|s| {
-                            CStr::from_ptr(s)
-                                .to_str()
-                                .expect("String was not UTF-8")
-                                .to_owned()
+                            CStr::from_ptr(s).to_str().expect("String was not UTF-8").to_owned()
                         })
                     })
                     .collect()
@@ -284,12 +258,8 @@
             assert!(ibinders[1].is_none());
             assert!(parcel.read::<Option<Vec<Option<SpIBinder>>>>()?.is_none());
 
-            let service = unsafe {
-                SERVICE
-                    .as_ref()
-                    .expect("Global binder service not initialized")
-                    .clone()
-            };
+            let service =
+                unsafe { SERVICE.as_ref().expect("Global binder service not initialized").clone() };
             reply.write(&service)?;
             reply.write(&(None as Option<&SpIBinder>))?;
             reply.write(&[Some(&service), None][..])?;
@@ -300,10 +270,7 @@
             assert!(status.is_ok());
             let status: Status = parcel.read()?;
             assert_eq!(status.exception_code(), ExceptionCode::NULL_POINTER);
-            assert_eq!(
-                status.get_description(),
-                "Status(-4, EX_NULL_POINTER): 'a status message'"
-            );
+            assert_eq!(status.get_description(), "Status(-4, EX_NULL_POINTER): 'a status message'");
             let status: Status = parcel.read()?;
             assert_eq!(status.service_specific_error(), 42);
             assert_eq!(
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index a3533d8..d7c6d49 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -141,6 +141,7 @@
     unstable: true,
     srcs: [
         "BinderRpcTestClientInfo.aidl",
+        "BinderRpcTestServerConfig.aidl",
         "BinderRpcTestServerInfo.aidl",
         "IBinderRpcCallback.aidl",
         "IBinderRpcSession.aidl",
@@ -167,7 +168,6 @@
         "libbinder_tls_shared_deps",
     ],
     shared_libs: [
-        "libbinder",
         "libbase",
         "liblog",
     ],
@@ -185,25 +185,72 @@
     ],
 }
 
-cc_test {
-    name: "binderRpcTest",
+cc_defaults {
+    name: "binderRpcTest_common_defaults",
     host_supported: true,
     target: {
         darwin: {
             enabled: false,
         },
+    },
+    defaults: [
+        "binder_test_defaults",
+    ],
+
+    static_libs: [
+        "libbinder_tls_static",
+        "libbinder_tls_test_utils",
+        "binderRpcTestIface-cpp",
+        "binderRpcTestIface-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "binderRpcTest_service_defaults",
+    defaults: [
+        "binderRpcTest_common_defaults",
+    ],
+    gtest: false,
+    auto_gen_config: false,
+    srcs: [
+        "binderRpcTestCommon.cpp",
+        "binderRpcTestService.cpp",
+    ],
+}
+
+cc_defaults {
+    name: "binderRpcTest_defaults",
+    target: {
         android: {
             test_suites: ["vts"],
         },
     },
     defaults: [
-        "binder_test_defaults",
-        "libbinder_tls_shared_deps",
+        "binderRpcTest_common_defaults",
     ],
 
     srcs: [
         "binderRpcTest.cpp",
+        "binderRpcTestCommon.cpp",
     ],
+
+    test_suites: ["general-tests"],
+    require_root: true,
+
+    data_bins: [
+        "binder_rpc_test_service",
+        "binder_rpc_test_service_no_kernel",
+        "binder_rpc_test_service_single_threaded",
+        "binder_rpc_test_service_single_threaded_no_kernel",
+    ],
+}
+
+cc_defaults {
+    name: "binderRpcTest_shared_defaults",
+    cflags: [
+        "-DBINDER_WITH_KERNEL_IPC",
+    ],
+
     shared_libs: [
         "libbinder",
         "libbinder_ndk",
@@ -212,14 +259,128 @@
         "libcutils",
         "liblog",
     ],
-    static_libs: [
-        "libbinder_tls_static",
-        "libbinder_tls_test_utils",
-        "binderRpcTestIface-cpp",
-        "binderRpcTestIface-ndk",
+}
+
+cc_defaults {
+    name: "binderRpcTest_static_defaults",
+
+    shared_libs: [
+        "libutils",
+        // libcrypto_static is not visible to this module
+        "libcrypto",
     ],
-    test_suites: ["general-tests"],
-    require_root: true,
+    static_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libssl",
+    ],
+
+    cflags: [
+        // Disable tests that require shared libraries,
+        // e.g., libbinder.so or libbinder_ndk.so
+        "-DBINDER_TEST_NO_SHARED_LIBS",
+    ],
+}
+
+cc_test {
+    // The module name cannot start with "binderRpcTest" because
+    // then atest tries to execute it as part of binderRpcTest
+    name: "binder_rpc_test_service",
+    defaults: [
+        "binderRpcTest_service_defaults",
+        "binderRpcTest_shared_defaults",
+        "libbinder_tls_shared_deps",
+    ],
+}
+
+cc_test {
+    name: "binder_rpc_test_service_no_kernel",
+    defaults: [
+        "binderRpcTest_service_defaults",
+        "binderRpcTest_static_defaults",
+    ],
+    static_libs: [
+        "libbinder_rpc_no_kernel",
+    ],
+}
+
+cc_test {
+    name: "binder_rpc_test_service_single_threaded",
+    defaults: [
+        "binderRpcTest_service_defaults",
+        "binderRpcTest_static_defaults",
+    ],
+    cflags: [
+        "-DBINDER_RPC_SINGLE_THREADED",
+        "-DBINDER_WITH_KERNEL_IPC",
+    ],
+    static_libs: [
+        "libbinder_rpc_single_threaded",
+    ],
+}
+
+cc_test {
+    name: "binder_rpc_test_service_single_threaded_no_kernel",
+    defaults: [
+        "binderRpcTest_service_defaults",
+        "binderRpcTest_static_defaults",
+    ],
+    cflags: [
+        "-DBINDER_RPC_SINGLE_THREADED",
+    ],
+    static_libs: [
+        "libbinder_rpc_single_threaded_no_kernel",
+    ],
+}
+
+cc_test {
+    name: "binderRpcTest",
+    defaults: [
+        "binderRpcTest_defaults",
+        "binderRpcTest_shared_defaults",
+        "libbinder_tls_shared_deps",
+    ],
+}
+
+cc_test {
+    name: "binderRpcTestNoKernel",
+    defaults: [
+        "binderRpcTest_defaults",
+        "binderRpcTest_static_defaults",
+    ],
+    static_libs: [
+        "libbinder_rpc_no_kernel",
+    ],
+}
+
+cc_test {
+    name: "binderRpcTestSingleThreaded",
+    defaults: [
+        "binderRpcTest_defaults",
+        "binderRpcTest_static_defaults",
+    ],
+    cflags: [
+        "-DBINDER_RPC_SINGLE_THREADED",
+        "-DBINDER_WITH_KERNEL_IPC",
+    ],
+    static_libs: [
+        "libbinder_rpc_single_threaded",
+    ],
+}
+
+cc_test {
+    name: "binderRpcTestSingleThreadedNoKernel",
+    defaults: [
+        "binderRpcTest_defaults",
+        "binderRpcTest_static_defaults",
+    ],
+    cflags: [
+        "-DBINDER_RPC_SINGLE_THREADED",
+    ],
+    static_libs: [
+        "libbinder_rpc_single_threaded_no_kernel",
+    ],
 }
 
 cc_test {
@@ -319,7 +480,6 @@
         "libbinder",
         "libutils",
     ],
-    clang: true,
     cflags: [
         "-g",
         "-Wno-missing-field-initializers",
diff --git a/libs/binder/tests/BinderRpcTestServerConfig.aidl b/libs/binder/tests/BinderRpcTestServerConfig.aidl
new file mode 100644
index 0000000..34d74be
--- /dev/null
+++ b/libs/binder/tests/BinderRpcTestServerConfig.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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 BinderRpcTestServerConfig {
+    int numThreads;
+    int[] serverSupportedFileDescriptorTransportModes;
+    int socketType;
+    int rpcSecurity;
+    int serverVersion;
+    int vsockPort;
+    @utf8InCpp String addr;
+}
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index fdd02a4..b15a225 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -24,6 +24,9 @@
     // number of known RPC binders to process, RpcState::countBinders by session
     int[] countBinders();
 
+    // Return a null binder with a non-nullable return type.
+    IBinder getNullBinder();
+
     // Caller sends server, callee pings caller's server and returns error code.
     int pingMe(IBinder binder);
     @nullable IBinder repeatBinder(@nullable IBinder binder);
@@ -64,4 +67,8 @@
     void scheduleShutdown();
 
     void useKernelBinderCallingId();
+
+    ParcelFileDescriptor echoAsFile(@utf8InCpp String content);
+
+    ParcelFileDescriptor concatFiles(in List<ParcelFileDescriptor> files);
 }
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
index e1f5ed5..60b3c94 100644
--- a/libs/binder/tests/binderAllocationLimits.cpp
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -15,8 +15,11 @@
  */
 
 #include <android-base/logging.h>
-#include <binder/Parcel.h>
+#include <binder/Binder.h>
 #include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
 #include <gtest/gtest.h>
 #include <utils/CallStack.h>
 
@@ -124,12 +127,18 @@
     });
 }
 
-using android::IBinder;
-using android::Parcel;
-using android::String16;
+using android::BBinder;
 using android::defaultServiceManager;
-using android::sp;
+using android::IBinder;
 using android::IServiceManager;
+using android::OK;
+using android::Parcel;
+using android::RpcServer;
+using android::RpcSession;
+using android::sp;
+using android::status_t;
+using android::statusToString;
+using android::String16;
 
 static sp<IBinder> GetRemoteBinder() {
     // This gets binder representing the service manager
@@ -175,6 +184,36 @@
     EXPECT_EQ(mallocs, 1);
 }
 
+TEST(RpcBinderAllocation, SetupRpcServer) {
+    std::string tmp = getenv("TMPDIR") ?: "/tmp";
+    std::string addr = tmp + "/binderRpcBenchmark";
+    (void)unlink(addr.c_str());
+    auto server = RpcServer::make();
+    server->setRootObject(sp<BBinder>::make());
+
+    CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
+
+    std::thread([server]() { server->join(); }).detach();
+
+    status_t status;
+    auto session = RpcSession::make();
+    status = session->setupUnixDomainClient(addr.c_str());
+    CHECK_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str();
+
+    auto remoteBinder = session->getRootObject();
+
+    size_t mallocs = 0, totalBytes = 0;
+    {
+        const auto on_malloc = OnMalloc([&](size_t bytes) {
+            mallocs++;
+            totalBytes += bytes;
+        });
+        CHECK_EQ(OK, remoteBinder->pingBinder());
+    }
+    EXPECT_EQ(mallocs, 1);
+    EXPECT_EQ(totalBytes, 40);
+}
+
 int main(int argc, char** argv) {
     if (getenv("LIBC_HOOKS_ENABLE") == nullptr) {
         CHECK(0 == setenv("LIBC_HOOKS_ENABLE", "1", true /*overwrite*/));
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index b1e17b7..e72f39c 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -30,6 +30,7 @@
 #include <android-base/properties.h>
 #include <android-base/result-gmock.h>
 #include <android-base/result.h>
+#include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <binder/Binder.h>
@@ -82,6 +83,7 @@
 static constexpr int kSchedPolicy = SCHED_RR;
 static constexpr int kSchedPriority = 7;
 static constexpr int kSchedPriorityMore = 8;
+static constexpr int kKernelThreads = 15;
 
 static String16 binderLibTestServiceName = String16("test.binderLib");
 
@@ -115,6 +117,12 @@
     BINDER_LIB_TEST_ECHO_VECTOR,
     BINDER_LIB_TEST_REJECT_OBJECTS,
     BINDER_LIB_TEST_CAN_GET_SID,
+    BINDER_LIB_TEST_GET_MAX_THREAD_COUNT,
+    BINDER_LIB_TEST_SET_MAX_THREAD_COUNT,
+    BINDER_LIB_TEST_LOCK_UNLOCK,
+    BINDER_LIB_TEST_PROCESS_LOCK,
+    BINDER_LIB_TEST_UNLOCK_AFTER_MS,
+    BINDER_LIB_TEST_PROCESS_TEMPORARY_LOCK
 };
 
 pid_t start_server_process(int arg2, bool usePoll = false)
@@ -247,13 +255,11 @@
         {
             int32_t id;
             Parcel data, reply;
-            sp<IBinder> binder;
 
             EXPECT_THAT(m_server->transact(code, data, &reply), StatusEq(NO_ERROR));
 
-            EXPECT_FALSE(binder != nullptr);
-            binder = reply.readStrongBinder();
-            EXPECT_TRUE(binder != nullptr);
+            sp<IBinder> binder = reply.readStrongBinder();
+            EXPECT_NE(nullptr, binder);
             EXPECT_THAT(reply.readInt32(&id), StatusEq(NO_ERROR));
             if (idPtr)
                 *idPtr = id;
@@ -442,6 +448,12 @@
     EXPECT_DEATH({ ProcessState::self(); }, "libbinder ProcessState can not be used after fork");
 }
 
+TEST_F(BinderLibTest, AddManagerToManager) {
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = IInterface::asBinder(sm);
+    EXPECT_EQ(NO_ERROR, sm->addService(String16("binderLibTest-manager"), binder));
+}
+
 TEST_F(BinderLibTest, WasParceled) {
     auto binder = sp<BBinder>::make();
     EXPECT_FALSE(binder->wasParceled());
@@ -1221,6 +1233,53 @@
     EXPECT_THAT(server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr), StatusEq(OK));
 }
 
+struct TooManyFdsFlattenable : Flattenable<TooManyFdsFlattenable> {
+    TooManyFdsFlattenable(size_t fdCount) : mFdCount(fdCount) {}
+
+    // Flattenable protocol
+    size_t getFlattenedSize() const {
+        // Return a valid non-zero size here so we don't get an unintended
+        // BAD_VALUE from Parcel::write
+        return 16;
+    }
+    size_t getFdCount() const { return mFdCount; }
+    status_t flatten(void *& /*buffer*/, size_t & /*size*/, int *&fds, size_t &count) const {
+        for (size_t i = 0; i < count; i++) {
+            fds[i] = STDIN_FILENO;
+        }
+        return NO_ERROR;
+    }
+    status_t unflatten(void const *& /*buffer*/, size_t & /*size*/, int const *& /*fds*/,
+                       size_t & /*count*/) {
+        /* This doesn't get called */
+        return NO_ERROR;
+    }
+
+    size_t mFdCount;
+};
+
+TEST_F(BinderLibTest, TooManyFdsFlattenable) {
+    rlimit origNofile;
+    int ret = getrlimit(RLIMIT_NOFILE, &origNofile);
+    ASSERT_EQ(0, ret);
+
+    // Restore the original file limits when the test finishes
+    base::ScopeGuard guardUnguard([&]() { setrlimit(RLIMIT_NOFILE, &origNofile); });
+
+    rlimit testNofile = {1024, 1024};
+    ret = setrlimit(RLIMIT_NOFILE, &testNofile);
+    ASSERT_EQ(0, ret);
+
+    Parcel parcel;
+    // Try to write more file descriptors than supported by the OS
+    TooManyFdsFlattenable tooManyFds1(1024);
+    EXPECT_THAT(parcel.write(tooManyFds1), StatusEq(-EMFILE));
+
+    // Try to write more file descriptors than the internal limit
+    TooManyFdsFlattenable tooManyFds2(1025);
+    EXPECT_THAT(parcel.write(tooManyFds2), StatusEq(BAD_VALUE));
+}
+
 TEST(ServiceNotifications, Unregister) {
     auto sm = defaultServiceManager();
     using LocalRegistrationCallback = IServiceManager::LocalRegistrationCallback;
@@ -1234,6 +1293,79 @@
     EXPECT_EQ(sm->unregisterForNotifications(String16("RogerRafa"), cb), OK);
 }
 
+TEST_F(BinderLibTest, ThreadPoolAvailableThreads) {
+    Parcel data, reply;
+    sp<IBinder> server = addServer();
+    ASSERT_TRUE(server != nullptr);
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_MAX_THREAD_COUNT, data, &reply),
+                StatusEq(NO_ERROR));
+    int32_t replyi = reply.readInt32();
+    // Expect 16 threads: kKernelThreads = 15 + Pool thread == 16
+    EXPECT_TRUE(replyi == kKernelThreads || replyi == kKernelThreads + 1);
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_PROCESS_LOCK, data, &reply), NO_ERROR);
+
+    /*
+     * This will use all threads in the pool expect the main pool thread.
+     * The service should run fine without locking, and the thread count should
+     * not exceed 16 (15 Max + pool thread).
+     */
+    std::vector<std::thread> ts;
+    for (size_t i = 0; i < kKernelThreads; i++) {
+        ts.push_back(std::thread([&] {
+            Parcel local_reply;
+            EXPECT_THAT(server->transact(BINDER_LIB_TEST_LOCK_UNLOCK, data, &local_reply),
+                        NO_ERROR);
+        }));
+    }
+
+    data.writeInt32(100);
+    // Give a chance for all threads to be used
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_UNLOCK_AFTER_MS, data, &reply), NO_ERROR);
+
+    for (auto &t : ts) {
+        t.join();
+    }
+
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_MAX_THREAD_COUNT, data, &reply),
+                StatusEq(NO_ERROR));
+    replyi = reply.readInt32();
+    EXPECT_EQ(replyi, kKernelThreads + 1);
+}
+
+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();
+}
+
+TEST_F(BinderLibTest, HangingServices) {
+    Parcel data, reply;
+    sp<IBinder> server = addServer();
+    ASSERT_TRUE(server != nullptr);
+    int32_t delay = 1000; // ms
+    data.writeInt32(delay);
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_PROCESS_TEMPORARY_LOCK, data, &reply), NO_ERROR);
+    std::vector<std::thread> ts;
+    size_t epochMsBefore = epochMillis();
+    for (size_t i = 0; i < kKernelThreads + 1; i++) {
+        ts.push_back(std::thread([&] {
+            Parcel local_reply;
+            EXPECT_THAT(server->transact(BINDER_LIB_TEST_LOCK_UNLOCK, data, &local_reply),
+                        NO_ERROR);
+        }));
+    }
+
+    for (auto &t : ts) {
+        t.join();
+    }
+    size_t epochMsAfter = epochMillis();
+
+    // deadlock occurred and threads only finished after 1s passed.
+    EXPECT_GE(epochMsAfter, epochMsBefore + delay);
+}
+
 class BinderLibRpcTestBase : public BinderLibTest {
 public:
     void SetUp() override {
@@ -1640,11 +1772,42 @@
             case BINDER_LIB_TEST_CAN_GET_SID: {
                 return IPCThreadState::self()->getCallingSid() == nullptr ? BAD_VALUE : NO_ERROR;
             }
+            case BINDER_LIB_TEST_GET_MAX_THREAD_COUNT: {
+                reply->writeInt32(ProcessState::self()->getThreadPoolMaxTotalThreadCount());
+                return NO_ERROR;
+            }
+            case BINDER_LIB_TEST_PROCESS_LOCK: {
+                m_blockMutex.lock();
+                return NO_ERROR;
+            }
+            case BINDER_LIB_TEST_LOCK_UNLOCK: {
+                std::lock_guard<std::mutex> _l(m_blockMutex);
+                return NO_ERROR;
+            }
+            case BINDER_LIB_TEST_UNLOCK_AFTER_MS: {
+                int32_t ms = data.readInt32();
+                return unlockInMs(ms);
+            }
+            case BINDER_LIB_TEST_PROCESS_TEMPORARY_LOCK: {
+                m_blockMutex.lock();
+                sp<BinderLibTestService> thisService = this;
+                int32_t value = data.readInt32();
+                // start local thread to unlock in 1s
+                std::thread t([=] { thisService->unlockInMs(value); });
+                t.detach();
+                return NO_ERROR;
+            }
             default:
                 return UNKNOWN_TRANSACTION;
         };
     }
 
+    status_t unlockInMs(int32_t ms) {
+        usleep(ms * 1000);
+        m_blockMutex.unlock();
+        return NO_ERROR;
+    }
+
 private:
     int32_t m_id;
     int32_t m_nextServerId;
@@ -1655,6 +1818,7 @@
     sp<IBinder> m_strongRef;
     sp<IBinder> m_callback;
     bool m_exitOnDestroy;
+    std::mutex m_blockMutex;
 };
 
 int run_server(int index, int readypipefd, bool usePoll)
@@ -1756,6 +1920,7 @@
              }
         }
     } else {
+        ProcessState::self()->setThreadPoolMaxThreadCount(kKernelThreads);
         ProcessState::self()->startThreadPool();
         IPCThreadState::self()->joinThreadPool();
     }
diff --git a/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp
index 21cb70b..278dd2b 100644
--- a/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp
+++ b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp
@@ -23,6 +23,7 @@
 #ifdef __BIONIC__
 TEST(MemoryHeapBase, ForceMemfdRespected) {
     auto mHeap = sp<MemoryHeapBase>::make(10, MemoryHeapBase::FORCE_MEMFD, "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
     int fd = mHeap->getHeapID();
     EXPECT_NE(fd, -1);
     EXPECT_FALSE(ashmem_valid(fd));
@@ -33,6 +34,7 @@
     auto mHeap = sp<MemoryHeapBase>::make(8192,
                                           MemoryHeapBase::FORCE_MEMFD,
                                           "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
     int fd = mHeap->getHeapID();
     EXPECT_NE(fd, -1);
     EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL);
@@ -43,6 +45,7 @@
                                           MemoryHeapBase::FORCE_MEMFD |
                                           MemoryHeapBase::MEMFD_ALLOW_SEALING,
                                           "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
     int fd = mHeap->getHeapID();
     EXPECT_NE(fd, -1);
     EXPECT_EQ(fcntl(fd, F_GET_SEALS), 0);
@@ -53,6 +56,7 @@
                                           MemoryHeapBase::FORCE_MEMFD |
                                           MemoryHeapBase::READ_ONLY,
                                           "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
     int fd = mHeap->getHeapID();
     EXPECT_NE(fd, -1);
     EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL | F_SEAL_FUTURE_WRITE);
@@ -64,6 +68,7 @@
                                           MemoryHeapBase::READ_ONLY |
                                           MemoryHeapBase::MEMFD_ALLOW_SEALING,
                                           "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
     int fd = mHeap->getHeapID();
     EXPECT_NE(fd, -1);
     EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_FUTURE_WRITE);
@@ -74,6 +79,7 @@
     auto mHeap = sp<MemoryHeapBase>::make(8192,
                                           MemoryHeapBase::READ_ONLY,
                                           "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
     int fd = mHeap->getHeapID();
     void* ptr = mHeap->getBase();
     EXPECT_NE(ptr, MAP_FAILED);
@@ -87,6 +93,7 @@
                                           MemoryHeapBase::READ_ONLY |
                                           MemoryHeapBase::MEMFD_ALLOW_SEALING,
                                           "Test mapping");
+    ASSERT_NE(mHeap.get(), nullptr);
     int fd = mHeap->getHeapID();
     void* ptr = mHeap->getBase();
     EXPECT_EQ(mHeap->getFlags(), MemoryHeapBase::READ_ONLY);
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index c2639e7..501a604 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -14,29 +14,7 @@
  * limitations under the License.
  */
 
-#include <BinderRpcTestClientInfo.h>
-#include <BinderRpcTestServerInfo.h>
-#include <BnBinderRpcCallback.h>
-#include <BnBinderRpcSession.h>
-#include <BnBinderRpcTest.h>
-#include <aidl/IBinderRpcTest.h>
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android/binder_auto_utils.h>
-#include <android/binder_libbinder.h>
-#include <binder/Binder.h>
-#include <binder/BpBinder.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <binder/RpcServer.h>
-#include <binder/RpcSession.h>
-#include <binder/RpcTlsTestUtils.h>
-#include <binder/RpcTlsUtils.h>
-#include <binder/RpcTransport.h>
-#include <binder/RpcTransportRaw.h>
-#include <binder/RpcTransportTls.h>
+#include <android-base/stringprintf.h>
 #include <gtest/gtest.h>
 
 #include <chrono>
@@ -45,14 +23,12 @@
 #include <thread>
 #include <type_traits>
 
+#include <dlfcn.h>
 #include <poll.h>
 #include <sys/prctl.h>
-#include <unistd.h>
+#include <sys/socket.h>
 
-#include "../FdTrigger.h"
-#include "../RpcSocketAddress.h" // for testing preconnected clients
-#include "../RpcState.h"         // for debugging
-#include "../vm_sockets.h"       // for VMADDR_*
+#include "binderRpcTestCommon.h"
 
 using namespace std::chrono_literals;
 using namespace std::placeholders;
@@ -62,54 +38,35 @@
 
 namespace android {
 
+#ifdef BINDER_TEST_NO_SHARED_LIBS
+constexpr bool kEnableSharedLibs = false;
+#else
+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);
-const char* kLocalInetAddress = "127.0.0.1";
-
-enum class RpcSecurity { RAW, TLS };
-
-static inline std::vector<RpcSecurity> RpcSecurityValues() {
-    return {RpcSecurity::RAW, RpcSecurity::TLS};
-}
-
-static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(
-        RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr,
-        std::unique_ptr<RpcAuth> auth = nullptr) {
-    switch (rpcSecurity) {
-        case RpcSecurity::RAW:
-            return RpcTransportCtxFactoryRaw::make();
-        case RpcSecurity::TLS: {
-            if (verifier == nullptr) {
-                verifier = std::make_shared<RpcCertificateVerifierSimple>();
-            }
-            if (auth == nullptr) {
-                auth = std::make_unique<RpcAuthSelfSigned>();
-            }
-            return RpcTransportCtxFactoryTls::make(std::move(verifier), std::move(auth));
-        }
-        default:
-            LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
-    }
-}
 
 TEST(BinderRpcParcel, EntireParcelFormatted) {
     Parcel p;
     p.writeInt32(3);
 
-    EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
+    EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "format must be set before data is written");
 }
 
-class BinderRpcSimple : public ::testing::TestWithParam<RpcSecurity> {
+class BinderRpcServerOnly : public ::testing::TestWithParam<std::tuple<RpcSecurity, uint32_t>> {
 public:
     static std::string PrintTestParam(const ::testing::TestParamInfo<ParamType>& info) {
-        return newFactory(info.param)->toCString();
+        return std::string(newFactory(std::get<0>(info.param))->toCString()) + "_serverV" +
+                std::to_string(std::get<1>(info.param));
     }
 };
 
-TEST_P(BinderRpcSimple, SetExternalServerTest) {
+TEST_P(BinderRpcServerOnly, SetExternalServerTest) {
     base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
     int sinkFd = sink.get();
-    auto server = RpcServer::make(newFactory(GetParam()));
+    auto server = RpcServer::make(newFactory(std::get<0>(GetParam())));
+    server->setProtocolVersion(std::get<1>(GetParam()));
     ASSERT_FALSE(server->hasServer());
     ASSERT_EQ(OK, server->setupExternalServer(std::move(sink)));
     ASSERT_TRUE(server->hasServer());
@@ -139,191 +96,15 @@
         EXPECT_TRUE(stat.isOk()) << stat; \
     } while (false)
 
-class MyBinderRpcSession : public BnBinderRpcSession {
-public:
-    static std::atomic<int32_t> gNum;
-
-    MyBinderRpcSession(const std::string& name) : mName(name) { gNum++; }
-    Status getName(std::string* name) override {
-        *name = mName;
-        return Status::ok();
+static std::string WaitStatusToString(int wstatus) {
+    if (WIFEXITED(wstatus)) {
+        return base::StringPrintf("exit status %d", WEXITSTATUS(wstatus));
     }
-    ~MyBinderRpcSession() { gNum--; }
-
-private:
-    std::string mName;
-};
-std::atomic<int32_t> MyBinderRpcSession::gNum;
-
-class MyBinderRpcCallback : public BnBinderRpcCallback {
-    Status sendCallback(const std::string& value) {
-        std::unique_lock _l(mMutex);
-        mValues.push_back(value);
-        _l.unlock();
-        mCv.notify_one();
-        return Status::ok();
+    if (WIFSIGNALED(wstatus)) {
+        return base::StringPrintf("term signal %d", WTERMSIG(wstatus));
     }
-    Status sendOnewayCallback(const std::string& value) { return sendCallback(value); }
-
-public:
-    std::mutex mMutex;
-    std::condition_variable mCv;
-    std::vector<std::string> mValues;
-};
-
-class MyBinderRpcTest : public BnBinderRpcTest {
-public:
-    wp<RpcServer> server;
-    int port = 0;
-
-    Status sendString(const std::string& str) override {
-        (void)str;
-        return Status::ok();
-    }
-    Status doubleString(const std::string& str, std::string* strstr) override {
-        *strstr = str + str;
-        return Status::ok();
-    }
-    Status getClientPort(int* out) override {
-        *out = port;
-        return Status::ok();
-    }
-    Status countBinders(std::vector<int32_t>* out) override {
-        sp<RpcServer> spServer = server.promote();
-        if (spServer == nullptr) {
-            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
-        }
-        out->clear();
-        for (auto session : spServer->listSessions()) {
-            size_t count = session->state()->countBinders();
-            out->push_back(count);
-        }
-        return Status::ok();
-    }
-    Status pingMe(const sp<IBinder>& binder, int32_t* out) override {
-        if (binder == nullptr) {
-            std::cout << "Received null binder!" << std::endl;
-            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
-        }
-        *out = binder->pingBinder();
-        return Status::ok();
-    }
-    Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
-        *out = binder;
-        return Status::ok();
-    }
-    static sp<IBinder> mHeldBinder;
-    Status holdBinder(const sp<IBinder>& binder) override {
-        mHeldBinder = binder;
-        return Status::ok();
-    }
-    Status getHeldBinder(sp<IBinder>* held) override {
-        *held = mHeldBinder;
-        return Status::ok();
-    }
-    Status nestMe(const sp<IBinderRpcTest>& binder, int count) override {
-        if (count <= 0) return Status::ok();
-        return binder->nestMe(this, count - 1);
-    }
-    Status alwaysGiveMeTheSameBinder(sp<IBinder>* out) override {
-        static sp<IBinder> binder = new BBinder;
-        *out = binder;
-        return Status::ok();
-    }
-    Status openSession(const std::string& name, sp<IBinderRpcSession>* out) override {
-        *out = new MyBinderRpcSession(name);
-        return Status::ok();
-    }
-    Status getNumOpenSessions(int32_t* out) override {
-        *out = MyBinderRpcSession::gNum;
-        return Status::ok();
-    }
-
-    std::mutex blockMutex;
-    Status lock() override {
-        blockMutex.lock();
-        return Status::ok();
-    }
-    Status unlockInMsAsync(int32_t ms) override {
-        usleep(ms * 1000);
-        blockMutex.unlock();
-        return Status::ok();
-    }
-    Status lockUnlock() override {
-        std::lock_guard<std::mutex> _l(blockMutex);
-        return Status::ok();
-    }
-
-    Status sleepMs(int32_t ms) override {
-        usleep(ms * 1000);
-        return Status::ok();
-    }
-
-    Status sleepMsAsync(int32_t ms) override {
-        // In-process binder calls are asynchronous, but the call to this method
-        // is synchronous wrt its client. This in/out-process threading model
-        // diffentiation is a classic binder leaky abstraction (for better or
-        // worse) and is preserved here the way binder sockets plugs itself
-        // into BpBinder, as nothing is changed at the higher levels
-        // (IInterface) which result in this behavior.
-        return sleepMs(ms);
-    }
-
-    Status doCallback(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
-                      const std::string& value) override {
-        if (callback == nullptr) {
-            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
-        }
-
-        if (delayed) {
-            std::thread([=]() {
-                ALOGE("Executing delayed callback: '%s'", value.c_str());
-                Status status = doCallback(callback, oneway, false, value);
-                ALOGE("Delayed callback status: '%s'", status.toString8().c_str());
-            }).detach();
-            return Status::ok();
-        }
-
-        if (oneway) {
-            return callback->sendOnewayCallback(value);
-        }
-
-        return callback->sendCallback(value);
-    }
-
-    Status doCallbackAsync(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
-                           const std::string& value) override {
-        return doCallback(callback, oneway, delayed, value);
-    }
-
-    Status die(bool cleanup) override {
-        if (cleanup) {
-            exit(1);
-        } else {
-            _exit(1);
-        }
-    }
-
-    Status scheduleShutdown() override {
-        sp<RpcServer> strongServer = server.promote();
-        if (strongServer == nullptr) {
-            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
-        }
-        std::thread([=] {
-            LOG_ALWAYS_FATAL_IF(!strongServer->shutdown(), "Could not shutdown");
-        }).detach();
-        return Status::ok();
-    }
-
-    Status useKernelBinderCallingId() override {
-        // this is WRONG! It does not make sense when using RPC binder, and
-        // because it is SO wrong, and so much code calls this, it should abort!
-
-        (void)IPCThreadState::self()->getCallingPid();
-        return Status::ok();
-    }
-};
-sp<IBinder> MyBinderRpcTest::mHeldBinder;
+    return base::StringPrintf("unexpected state %d", wstatus);
+}
 
 class Process {
 public:
@@ -332,8 +113,8 @@
                                      android::base::borrowed_fd /* readEnd */)>& f) {
         android::base::unique_fd childWriteEnd;
         android::base::unique_fd childReadEnd;
-        CHECK(android::base::Pipe(&mReadEnd, &childWriteEnd)) << strerror(errno);
-        CHECK(android::base::Pipe(&childReadEnd, &mWriteEnd)) << strerror(errno);
+        CHECK(android::base::Pipe(&mReadEnd, &childWriteEnd, 0)) << strerror(errno);
+        CHECK(android::base::Pipe(&childReadEnd, &mWriteEnd, 0)) << strerror(errno);
         if (0 == (mPid = fork())) {
             // racey: assume parent doesn't crash before this is set
             prctl(PR_SET_PDEATHSIG, SIGHUP);
@@ -345,13 +126,28 @@
     }
     ~Process() {
         if (mPid != 0) {
-            waitpid(mPid, nullptr, 0);
+            int wstatus;
+            waitpid(mPid, &wstatus, 0);
+            if (mCustomExitStatusCheck) {
+                mCustomExitStatusCheck(wstatus);
+            } else {
+                EXPECT_TRUE(WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0)
+                        << "server process failed: " << WaitStatusToString(wstatus);
+            }
         }
     }
     android::base::borrowed_fd readEnd() { return mReadEnd; }
     android::base::borrowed_fd writeEnd() { return mWriteEnd; }
 
+    void setCustomExitStatusCheck(std::function<void(int wstatus)> f) {
+        mCustomExitStatusCheck = std::move(f);
+    }
+
+    // Kill the process. Avoid if possible. Shutdown gracefully via an RPC instead.
+    void terminate() { kill(mPid, SIGTERM); }
+
 private:
+    std::function<void(int wstatus)> mCustomExitStatusCheck;
     pid_t mPid = 0;
     android::base::unique_fd mReadEnd;
     android::base::unique_fd mWriteEnd;
@@ -366,7 +162,7 @@
 };
 
 static unsigned int allocateVsockPort() {
-    static unsigned int vsockPort = 3456;
+    static unsigned int vsockPort = 34567;
     return vsockPort++;
 }
 
@@ -419,10 +215,10 @@
 
     BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default;
     ~BinderRpcTestProcessSession() {
-        EXPECT_NE(nullptr, rootIface);
-        if (rootIface == nullptr) return;
-
         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));
@@ -443,28 +239,6 @@
     }
 };
 
-enum class SocketType {
-    PRECONNECTED,
-    UNIX,
-    VSOCK,
-    INET,
-};
-static inline std::string PrintToString(SocketType socketType) {
-    switch (socketType) {
-        case SocketType::PRECONNECTED:
-            return "preconnected_uds";
-        case SocketType::UNIX:
-            return "unix_domain_socket";
-        case SocketType::VSOCK:
-            return "vm_socket";
-        case SocketType::INET:
-            return "inet_socket";
-        default:
-            LOG_ALWAYS_FATAL("Unknown socket type");
-            return "";
-    }
-}
-
 static base::unique_fd connectTo(const RpcSocketAddress& addr) {
     base::unique_fd serverFd(
             TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
@@ -480,115 +254,79 @@
     return serverFd;
 }
 
-class BinderRpc : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity>> {
+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:
-    struct Options {
-        size_t numThreads = 1;
-        size_t numSessions = 1;
-        size_t numIncomingConnections = 0;
-        size_t numOutgoingConnections = SIZE_MAX;
-    };
+    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 singleThreaded() const { return std::get<4>(GetParam()); }
+    bool noKernel() const { return std::get<5>(GetParam()); }
+
+    // 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);
+    }
 
     static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
-        auto [type, security] = info.param;
-        return PrintToString(type) + "_" + newFactory(security)->toCString();
-    }
-
-    static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
-        uint64_t length = str.length();
-        CHECK(android::base::WriteFully(fd, &length, sizeof(length)));
-        CHECK(android::base::WriteFully(fd, str.data(), str.length()));
-    }
-
-    static inline std::string readString(android::base::borrowed_fd fd) {
-        uint64_t length;
-        CHECK(android::base::ReadFully(fd, &length, sizeof(length)));
-        std::string ret(length, '\0');
-        CHECK(android::base::ReadFully(fd, ret.data(), length));
+        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;
     }
 
-    static inline void writeToFd(android::base::borrowed_fd fd, const Parcelable& parcelable) {
-        Parcel parcel;
-        CHECK_EQ(OK, parcelable.writeToParcel(&parcel));
-        writeString(fd,
-                    std::string(reinterpret_cast<const char*>(parcel.data()), parcel.dataSize()));
-    }
-
-    template <typename T>
-    static inline T readFromFd(android::base::borrowed_fd fd) {
-        std::string data = readString(fd);
-        Parcel parcel;
-        CHECK_EQ(OK, parcel.setData(reinterpret_cast<const uint8_t*>(data.data()), data.size()));
-        T object;
-        CHECK_EQ(OK, object.readFromParcel(&parcel));
-        return object;
-    }
-
     // This creates a new process serving an interface on a certain number of
     // threads.
-    ProcessSession createRpcTestSocketServerProcess(
-            const Options& options, const std::function<void(const sp<RpcServer>&)>& configure) {
+    ProcessSession createRpcTestSocketServerProcessEtc(const BinderRpcOptions& options) {
         CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
 
         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());
 
-        unsigned int vsockPort = allocateVsockPort();
-        std::string addr = allocateSocketAddress();
+        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" : "");
 
         auto ret = ProcessSession{
-                .host = Process([&](android::base::borrowed_fd writeEnd,
+                .host = Process([=](android::base::borrowed_fd writeEnd,
                                     android::base::borrowed_fd readEnd) {
-                    auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
-                    sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
-
-                    server->setMaxThreads(options.numThreads);
-
-                    unsigned int outPort = 0;
-
-                    switch (socketType) {
-                        case SocketType::PRECONNECTED:
-                            [[fallthrough]];
-                        case SocketType::UNIX:
-                            CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str())) << addr;
-                            break;
-                        case SocketType::VSOCK:
-                            CHECK_EQ(OK, server->setupVsockServer(vsockPort));
-                            break;
-                        case SocketType::INET: {
-                            CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
-                            CHECK_NE(0, outPort);
-                            break;
-                        }
-                        default:
-                            LOG_ALWAYS_FATAL("Unknown socket type");
-                    }
-
-                    BinderRpcTestServerInfo serverInfo;
-                    serverInfo.port = static_cast<int64_t>(outPort);
-                    serverInfo.cert.data = server->getCertificate(RpcCertificateFormat::PEM);
-                    writeToFd(writeEnd, serverInfo);
-                    auto clientInfo = readFromFd<BinderRpcTestClientInfo>(readEnd);
-
-                    if (rpcSecurity == RpcSecurity::TLS) {
-                        for (const auto& clientCert : clientInfo.certs) {
-                            CHECK_EQ(OK,
-                                     certVerifier
-                                             ->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
-                                                                         clientCert.data));
-                        }
-                    }
-
-                    configure(server);
-
-                    server->join();
-
-                    // Another thread calls shutdown. Wait for it to complete.
-                    (void)server->shutdown();
+                    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();
+        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++) {
@@ -618,20 +356,22 @@
         status_t status;
 
         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(addr.c_str()));
+                        return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
                     });
                     break;
                 case SocketType::UNIX:
-                    status = session->setupUnixDomainClient(addr.c_str());
+                    status = session->setupUnixDomainClient(serverConfig.addr.c_str());
                     break;
                 case SocketType::VSOCK:
-                    status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
+                    status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort);
                     break;
                 case SocketType::INET:
                     status = session->setupInetClient("127.0.0.1", serverInfo.port);
@@ -639,52 +379,22 @@
                 default:
                     LOG_ALWAYS_FATAL("Unknown socket type");
             }
+            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()});
         }
         return ret;
     }
 
-    BinderRpcTestProcessSession createRpcTestSocketServerProcess(const Options& options) {
+    BinderRpcTestProcessSession createRpcTestSocketServerProcess(const BinderRpcOptions& options) {
         BinderRpcTestProcessSession ret{
-                .proc = createRpcTestSocketServerProcess(
-                        options,
-                        [&](const sp<RpcServer>& server) {
-                            server->setPerSessionRootObject([&](const sockaddr* addr,
-                                                                socklen_t len) {
-                                sp<MyBinderRpcTest> service = sp<MyBinderRpcTest>::make();
-                                switch (addr->sa_family) {
-                                    case AF_UNIX:
-                                        // nothing to save
-                                        break;
-                                    case AF_VSOCK:
-                                        CHECK_EQ(len, sizeof(sockaddr_vm));
-                                        service->port = reinterpret_cast<const sockaddr_vm*>(addr)
-                                                                ->svm_port;
-                                        break;
-                                    case AF_INET:
-                                        CHECK_EQ(len, sizeof(sockaddr_in));
-                                        service->port =
-                                                ntohs(reinterpret_cast<const sockaddr_in*>(addr)
-                                                              ->sin_port);
-                                        break;
-                                    case AF_INET6:
-                                        CHECK_EQ(len, sizeof(sockaddr_in));
-                                        service->port =
-                                                ntohs(reinterpret_cast<const sockaddr_in6*>(addr)
-                                                              ->sin6_port);
-                                        break;
-                                    default:
-                                        LOG_ALWAYS_FATAL("Unrecognized address family %d",
-                                                         addr->sa_family);
-                                }
-                                service->server = server;
-                                return service;
-                            });
-                        }),
+                .proc = createRpcTestSocketServerProcessEtc(options),
         };
 
-        ret.rootBinder = ret.proc.sessions.at(0).root;
+        ret.rootBinder = ret.proc.sessions.empty() ? nullptr : ret.proc.sessions.at(0).root;
         ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
 
         return ret;
@@ -694,6 +404,18 @@
                                      size_t sleepMs = 500);
 };
 
+// Test fixture for tests that start multiple threads.
+// This includes tests with one thread but multiple sessions,
+// since a server uses one thread per session.
+class BinderRpcThreads : public BinderRpc {
+public:
+    void SetUp() override {
+        if constexpr (!kEnableRpcThreads) {
+            GTEST_SKIP() << "Test skipped because threads were disabled at build time";
+        }
+    }
+};
+
 TEST_P(BinderRpc, Ping) {
     auto proc = createRpcTestSocketServerProcess({});
     ASSERT_NE(proc.rootBinder, nullptr);
@@ -706,7 +428,7 @@
     EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
 }
 
-TEST_P(BinderRpc, MultipleSessions) {
+TEST_P(BinderRpcThreads, MultipleSessions) {
     auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5});
     for (auto session : proc.proc.sessions) {
         ASSERT_NE(nullptr, session.root);
@@ -714,7 +436,7 @@
     }
 }
 
-TEST_P(BinderRpc, SeparateRootObject) {
+TEST_P(BinderRpcThreads, SeparateRootObject) {
     SocketType type = std::get<0>(GetParam());
     if (type == SocketType::PRECONNECTED || type == SocketType::UNIX) {
         // we can't get port numbers for unix sockets
@@ -752,7 +474,7 @@
     p1.markForBinder(proc1.rootBinder);
     p1.writeInt32(3);
 
-    EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, p1.dataSize()));
+    EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, pRaw.dataSize()));
     EXPECT_EQ(BAD_TYPE, pRaw.appendFrom(&p1, 0, p1.dataSize()));
 
     Parcel p2;
@@ -791,6 +513,13 @@
     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({});
 
@@ -890,7 +619,7 @@
               proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
 }
 
-TEST_P(BinderRpc, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
+TEST_P(BinderRpcThreads, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
     auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 2});
 
     sp<IBinder> outBinder;
@@ -900,6 +629,11 @@
 }
 
 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());
@@ -909,6 +643,11 @@
 }
 
 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
@@ -928,7 +667,13 @@
 }
 
 TEST_P(BinderRpc, NestedTransactions) {
-    auto proc = createRpcTestSocketServerProcess({});
+    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));
@@ -1030,7 +775,7 @@
     return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
 }
 
-TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
+TEST_P(BinderRpcThreads, ThreadPoolGreaterThanEqualRequested) {
     constexpr size_t kNumThreads = 10;
 
     auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
@@ -1081,14 +826,14 @@
     EXPECT_LE(epochMsAfter, epochMsBefore + 3 * sleepMs);
 }
 
-TEST_P(BinderRpc, ThreadPoolOverSaturated) {
+TEST_P(BinderRpcThreads, ThreadPoolOverSaturated) {
     constexpr size_t kNumThreads = 10;
     constexpr size_t kNumCalls = kNumThreads + 3;
     auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
     testThreadPoolOverSaturated(proc.rootIface, kNumCalls);
 }
 
-TEST_P(BinderRpc, ThreadPoolLimitOutgoing) {
+TEST_P(BinderRpcThreads, ThreadPoolLimitOutgoing) {
     constexpr size_t kNumThreads = 20;
     constexpr size_t kNumOutgoingConnections = 10;
     constexpr size_t kNumCalls = kNumOutgoingConnections + 3;
@@ -1097,7 +842,7 @@
     testThreadPoolOverSaturated(proc.rootIface, kNumCalls);
 }
 
-TEST_P(BinderRpc, ThreadingStressTest) {
+TEST_P(BinderRpcThreads, ThreadingStressTest) {
     constexpr size_t kNumClientThreads = 10;
     constexpr size_t kNumServerThreads = 10;
     constexpr size_t kNumCalls = 100;
@@ -1126,7 +871,7 @@
     for (auto& t : threads) t.join();
 }
 
-TEST_P(BinderRpc, OnewayStressTest) {
+TEST_P(BinderRpcThreads, OnewayStressTest) {
     constexpr size_t kNumClientThreads = 10;
     constexpr size_t kNumServerThreads = 10;
     constexpr size_t kNumCalls = 1000;
@@ -1161,7 +906,7 @@
     EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
 }
 
-TEST_P(BinderRpc, OnewayCallQueueing) {
+TEST_P(BinderRpcThreads, OnewayCallQueueing) {
     constexpr size_t kNumSleeps = 10;
     constexpr size_t kNumExtraServerThreads = 4;
     constexpr size_t kSleepMs = 50;
@@ -1185,12 +930,12 @@
 
     size_t epochMsAfter = epochMillis();
 
-    EXPECT_GT(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
+    EXPECT_GE(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
 
     saturateThreadPool(1 + kNumExtraServerThreads, proc.rootIface);
 }
 
-TEST_P(BinderRpc, OnewayCallExhaustion) {
+TEST_P(BinderRpcThreads, OnewayCallExhaustion) {
     constexpr size_t kNumClients = 2;
     constexpr size_t kTooLongMs = 1000;
 
@@ -1233,11 +978,21 @@
 TEST_P(BinderRpc, Callbacks) {
     const static std::string kTestString = "good afternoon!";
 
+    bool bothSingleThreaded = !kEnableRpcThreads || singleThreaded();
+
     for (bool callIsOneway : {true, false}) {
         for (bool callbackIsOneway : {true, false}) {
             for (bool delayed : {true, false}) {
+                if (bothSingleThreaded && (callIsOneway || callbackIsOneway || delayed)) {
+                    // we have no incoming connections to receive the callback
+                    continue;
+                }
+
+                size_t numIncomingConnections = bothSingleThreaded ? 0 : 1;
                 auto proc = createRpcTestSocketServerProcess(
-                        {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
+                        {.numThreads = 1,
+                         .numSessions = 1,
+                         .numIncomingConnections = numIncomingConnections});
                 auto cb = sp<MyBinderRpcCallback>::make();
 
                 if (callIsOneway) {
@@ -1248,9 +1003,14 @@
                             proc.rootIface->doCallback(cb, callbackIsOneway, delayed, kTestString));
                 }
 
-                using std::literals::chrono_literals::operator""s;
-                std::unique_lock<std::mutex> _l(cb->mMutex);
-                cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
+                // 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
@@ -1269,13 +1029,131 @@
                 // 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, SingleDeathRecipient) {
+    if (singleThreaded() || !kEnableRpcThreads) {
+        GTEST_SKIP() << "This test requires multiple threads";
+    }
+    class MyDeathRec : public IBinder::DeathRecipient {
+    public:
+        void binderDied(const wp<IBinder>& /* who */) override {
+            dead = true;
+            mCv.notify_one();
+        }
+        std::mutex mMtx;
+        std::condition_variable mCv;
+        bool dead = false;
+    };
+
+    // Death recipient needs to have an incoming connection to be called
+    auto proc = createRpcTestSocketServerProcess(
+            {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
+
+    auto dr = sp<MyDeathRec>::make();
+    ASSERT_EQ(OK, proc.rootBinder->linkToDeath(dr, (void*)1, 0));
+
+    if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
+        EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+    }
+
+    std::unique_lock<std::mutex> lock(dr->mMtx);
+    if (!dr->dead) {
+        EXPECT_EQ(std::cv_status::no_timeout, dr->mCv.wait_for(lock, 1000ms));
+    }
+    EXPECT_TRUE(dr->dead) << "Failed to receive the death notification.";
+
+    // need to wait for the session to shutdown so we don't "Leak session"
+    EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+    proc.expectAlreadyShutdown = true;
+}
+
+TEST_P(BinderRpc, SingleDeathRecipientOnShutdown) {
+    if (singleThreaded() || !kEnableRpcThreads) {
+        GTEST_SKIP() << "This test requires multiple threads";
+    }
+    class MyDeathRec : public IBinder::DeathRecipient {
+    public:
+        void binderDied(const wp<IBinder>& /* who */) override {
+            dead = true;
+            mCv.notify_one();
+        }
+        std::mutex mMtx;
+        std::condition_variable mCv;
+        bool dead = false;
+    };
+
+    // Death recipient needs to have an incoming connection to be called
+    auto proc = createRpcTestSocketServerProcess(
+            {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
+
+    auto dr = sp<MyDeathRec>::make();
+    EXPECT_EQ(OK, proc.rootBinder->linkToDeath(dr, (void*)1, 0));
+
+    // Explicitly calling shutDownAndWait will cause the death recipients
+    // to be called.
+    EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+
+    std::unique_lock<std::mutex> lock(dr->mMtx);
+    if (!dr->dead) {
+        EXPECT_EQ(std::cv_status::no_timeout, dr->mCv.wait_for(lock, 1000ms));
+    }
+    EXPECT_TRUE(dr->dead) << "Failed to receive the death notification.";
+
+    proc.proc.host.terminate();
+    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+        EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
+                << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+    });
+    proc.expectAlreadyShutdown = true;
+}
+
+TEST_P(BinderRpc, DeathRecipientFatalWithoutIncoming) {
+    class MyDeathRec : public IBinder::DeathRecipient {
+    public:
+        void binderDied(const wp<IBinder>& /* who */) override {}
+    };
+
+    auto proc = createRpcTestSocketServerProcess(
+            {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 0});
+
+    auto dr = sp<MyDeathRec>::make();
+    EXPECT_DEATH(proc.rootBinder->linkToDeath(dr, (void*)1, 0),
+                 "Cannot register a DeathRecipient without any incoming connections.");
+}
+
+TEST_P(BinderRpc, UnlinkDeathRecipient) {
+    if (singleThreaded() || !kEnableRpcThreads) {
+        GTEST_SKIP() << "This test requires multiple threads";
+    }
+    class MyDeathRec : public IBinder::DeathRecipient {
+    public:
+        void binderDied(const wp<IBinder>& /* who */) override {
+            GTEST_FAIL() << "This should not be called after unlinkToDeath";
+        }
+    };
+
+    // Death recipient needs to have an incoming connection to be called
+    auto proc = createRpcTestSocketServerProcess(
+            {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
+
+    auto dr = sp<MyDeathRec>::make();
+    ASSERT_EQ(OK, proc.rootBinder->linkToDeath(dr, (void*)1, 0));
+    ASSERT_EQ(OK, proc.rootBinder->unlinkToDeath(dr, (void*)1, 0, nullptr));
+
+    if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
+        EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+    }
+
+    // need to wait for the session to shutdown so we don't "Leak session"
+    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();
@@ -1299,33 +1177,185 @@
         EXPECT_EQ(DEAD_OBJECT, proc.rootIface->die(doDeathCleanup).transactionError())
                 << "Do death cleanup: " << doDeathCleanup;
 
+        proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+            EXPECT_TRUE(WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 1)
+                    << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+        });
         proc.expectAlreadyShutdown = true;
     }
 }
 
 TEST_P(BinderRpc, UseKernelBinderCallingId) {
-    bool okToFork = ProcessState::selfOrNull() == nullptr;
+    // This test only works if the current process shared the internal state of
+    // ProcessState with the service across the call to fork(). Both the static
+    // libraries and libbinder.so have their own separate copies of all the
+    // globals, so the test only works when the test client and service both use
+    // libbinder.so (when using static libraries, even a client and service
+    // using the same kind of static library should have separate copies of the
+    // variables).
+    if (!kEnableSharedLibs || singleThreaded() || noKernel()) {
+        GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+                        "at build time.";
+    }
 
     auto proc = createRpcTestSocketServerProcess({});
 
-    // If this process has used ProcessState already, then the forked process
-    // cannot use it at all. If this process hasn't used it (depending on the
-    // order tests are run), then the forked process can use it, and we'll only
-    // catch the invalid usage the second time. Such is the burden of global
-    // state!
-    if (okToFork) {
-        // we can't allocate IPCThreadState so actually the first time should
-        // succeed :(
-        EXPECT_OK(proc.rootIface->useKernelBinderCallingId());
-    }
+    // we can't allocate IPCThreadState so actually the first time should
+    // succeed :(
+    EXPECT_OK(proc.rootIface->useKernelBinderCallingId());
 
     // second time! we catch the error :)
     EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError());
 
+    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+        EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT)
+                << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+    });
     proc.expectAlreadyShutdown = true;
 }
 
+TEST_P(BinderRpc, FileDescriptorTransportRejectNone) {
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::NONE,
+            .serverSupportedFileDescriptorTransportModes =
+                    {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(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
+                << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+    });
+    proc.expectAlreadyShutdown = true;
+}
+
+TEST_P(BinderRpc, FileDescriptorTransportRejectUnix) {
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+            .serverSupportedFileDescriptorTransportModes =
+                    {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(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
+                << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+    });
+    proc.expectAlreadyShutdown = true;
+}
+
+TEST_P(BinderRpc, FileDescriptorTransportOptionalUnix) {
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::NONE,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::NONE,
+                     RpcSession::FileDescriptorTransportMode::UNIX},
+    });
+
+    android::os::ParcelFileDescriptor out;
+    auto status = proc.rootIface->echoAsFile("hello", &out);
+    EXPECT_EQ(status.transactionError(), FDS_NOT_ALLOWED) << status;
+}
+
+TEST_P(BinderRpc, ReceiveFile) {
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::UNIX},
+    });
+
+    android::os::ParcelFileDescriptor out;
+    auto status = proc.rootIface->echoAsFile("hello", &out);
+    if (!supportsFdTransport()) {
+        EXPECT_EQ(status.transactionError(), BAD_VALUE) << status;
+        return;
+    }
+    ASSERT_TRUE(status.isOk()) << status;
+
+    std::string result;
+    CHECK(android::base::ReadFdToString(out.get(), &result));
+    EXPECT_EQ(result, "hello");
+}
+
+TEST_P(BinderRpc, SendFiles) {
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::UNIX},
+    });
+
+    std::vector<android::os::ParcelFileDescriptor> files;
+    files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("123")));
+    files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("a")));
+    files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("b")));
+    files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("cd")));
+
+    android::os::ParcelFileDescriptor out;
+    auto status = proc.rootIface->concatFiles(files, &out);
+    if (!supportsFdTransport()) {
+        EXPECT_EQ(status.transactionError(), BAD_VALUE) << status;
+        return;
+    }
+    ASSERT_TRUE(status.isOk()) << status;
+
+    std::string result;
+    CHECK(android::base::ReadFdToString(out.get(), &result));
+    EXPECT_EQ(result, "123abcd");
+}
+
+TEST_P(BinderRpc, SendMaxFiles) {
+    if (!supportsFdTransport()) {
+        GTEST_SKIP() << "Would fail trivially (which is tested by BinderRpc::SendFiles)";
+    }
+
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::UNIX},
+    });
+
+    std::vector<android::os::ParcelFileDescriptor> files;
+    for (int i = 0; i < 253; i++) {
+        files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("a")));
+    }
+
+    android::os::ParcelFileDescriptor out;
+    auto status = proc.rootIface->concatFiles(files, &out);
+    ASSERT_TRUE(status.isOk()) << status;
+
+    std::string result;
+    CHECK(android::base::ReadFdToString(out.get(), &result));
+    EXPECT_EQ(result, std::string(253, 'a'));
+}
+
+TEST_P(BinderRpc, SendTooManyFiles) {
+    if (!supportsFdTransport()) {
+        GTEST_SKIP() << "Would fail trivially (which is tested by BinderRpc::SendFiles)";
+    }
+
+    auto proc = createRpcTestSocketServerProcess({
+            .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+            .serverSupportedFileDescriptorTransportModes =
+                    {RpcSession::FileDescriptorTransportMode::UNIX},
+    });
+
+    std::vector<android::os::ParcelFileDescriptor> files;
+    for (int i = 0; i < 254; i++) {
+        files.emplace_back(android::os::ParcelFileDescriptor(mockFileDescriptor("a")));
+    }
+
+    android::os::ParcelFileDescriptor out;
+    auto status = proc.rootIface->concatFiles(files, &out);
+    EXPECT_EQ(status.transactionError(), BAD_VALUE) << status;
+}
+
 TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
+    if constexpr (!kEnableSharedLibs) {
+        GTEST_SKIP() << "Test disabled because Binder was built as a static library";
+    }
+
     auto proc = createRpcTestSocketServerProcess({});
 
     ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
@@ -1335,6 +1365,10 @@
 }
 
 TEST_P(BinderRpc, WorksWithLibbinderNdkUserTransaction) {
+    if constexpr (!kEnableSharedLibs) {
+        GTEST_SKIP() << "Test disabled because Binder was built as a static library";
+    }
+
     auto proc = createRpcTestSocketServerProcess({});
 
     ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
@@ -1359,7 +1393,7 @@
     return ret;
 }
 
-TEST_P(BinderRpc, Fds) {
+TEST_P(BinderRpcThreads, Fds) {
     ssize_t beforeFds = countFds();
     ASSERT_GE(beforeFds, 0);
     {
@@ -1382,20 +1416,90 @@
 static bool testSupportVsockLoopback() {
     // We don't need to enable TLS to know if vsock is supported.
     unsigned int vsockPort = allocateVsockPort();
-    sp<RpcServer> server = RpcServer::make(RpcTransportCtxFactoryRaw::make());
-    if (status_t status = server->setupVsockServer(vsockPort); status != OK) {
-        if (status == -EAFNOSUPPORT) {
-            return false;
-        }
-        LOG_ALWAYS_FATAL("Could not setup vsock server: %s", statusToString(status).c_str());
-    }
-    server->start();
 
-    sp<RpcSession> session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
-    status_t status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
-    while (!server->shutdown()) usleep(10000);
-    ALOGE("Detected vsock loopback supported: %s", statusToString(status).c_str());
-    return status == OK;
+    android::base::unique_fd serverFd(
+            TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
+    LOG_ALWAYS_FATAL_IF(serverFd == -1, "Could not create socket: %s", strerror(errno));
+
+    sockaddr_vm serverAddr{
+            .svm_family = AF_VSOCK,
+            .svm_port = vsockPort,
+            .svm_cid = VMADDR_CID_ANY,
+    };
+    int ret = TEMP_FAILURE_RETRY(
+            bind(serverFd.get(), reinterpret_cast<sockaddr*>(&serverAddr), sizeof(serverAddr)));
+    LOG_ALWAYS_FATAL_IF(0 != ret, "Could not bind socket to port %u: %s", vsockPort,
+                        strerror(errno));
+
+    ret = TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/));
+    LOG_ALWAYS_FATAL_IF(0 != ret, "Could not listen socket on port %u: %s", vsockPort,
+                        strerror(errno));
+
+    // Try to connect to the server using the VMADDR_CID_LOCAL cid
+    // to see if the kernel supports it. It's safe to use a blocking
+    // connect because vsock sockets have a 2 second connection timeout,
+    // and they return ETIMEDOUT after that.
+    android::base::unique_fd connectFd(
+            TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
+    LOG_ALWAYS_FATAL_IF(connectFd == -1, "Could not create socket for port %u: %s", vsockPort,
+                        strerror(errno));
+
+    bool success = false;
+    sockaddr_vm connectAddr{
+            .svm_family = AF_VSOCK,
+            .svm_port = vsockPort,
+            .svm_cid = VMADDR_CID_LOCAL,
+    };
+    ret = TEMP_FAILURE_RETRY(connect(connectFd.get(), reinterpret_cast<sockaddr*>(&connectAddr),
+                                     sizeof(connectAddr)));
+    if (ret != 0 && (errno == EAGAIN || errno == EINPROGRESS)) {
+        android::base::unique_fd acceptFd;
+        while (true) {
+            pollfd pfd[]{
+                    {.fd = serverFd.get(), .events = POLLIN, .revents = 0},
+                    {.fd = connectFd.get(), .events = POLLOUT, .revents = 0},
+            };
+            ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
+            LOG_ALWAYS_FATAL_IF(ret < 0, "Error polling: %s", strerror(errno));
+
+            if (pfd[0].revents & POLLIN) {
+                sockaddr_vm acceptAddr;
+                socklen_t acceptAddrLen = sizeof(acceptAddr);
+                ret = TEMP_FAILURE_RETRY(accept4(serverFd.get(),
+                                                 reinterpret_cast<sockaddr*>(&acceptAddr),
+                                                 &acceptAddrLen, SOCK_CLOEXEC));
+                LOG_ALWAYS_FATAL_IF(ret < 0, "Could not accept4 socket: %s", strerror(errno));
+                LOG_ALWAYS_FATAL_IF(acceptAddrLen != static_cast<socklen_t>(sizeof(acceptAddr)),
+                                    "Truncated address");
+
+                // Store the fd in acceptFd so we keep the connection alive
+                // while polling connectFd
+                acceptFd.reset(ret);
+            }
+
+            if (pfd[1].revents & POLLOUT) {
+                // Connect either succeeded or timed out
+                int connectErrno;
+                socklen_t connectErrnoLen = sizeof(connectErrno);
+                int ret = getsockopt(connectFd.get(), SOL_SOCKET, SO_ERROR, &connectErrno,
+                                     &connectErrnoLen);
+                LOG_ALWAYS_FATAL_IF(ret == -1,
+                                    "Could not getsockopt() after connect() "
+                                    "on non-blocking socket: %s.",
+                                    strerror(errno));
+
+                // We're done, this is all we wanted
+                success = connectErrno == 0;
+                break;
+            }
+        }
+    } else {
+        success = ret == 0;
+    }
+
+    ALOGE("Detected vsock loopback supported: %s", success ? "yes" : "no");
+
+    return success;
 }
 
 static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
@@ -1412,9 +1516,31 @@
     return ret;
 }
 
+static std::vector<uint32_t> testVersions() {
+    std::vector<uint32_t> versions;
+    for (size_t i = 0; i < RPC_WIRE_PROTOCOL_VERSION_NEXT; i++) {
+        versions.push_back(i);
+    }
+    versions.push_back(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
+    return versions;
+}
+
 INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
                         ::testing::Combine(::testing::ValuesIn(testSocketTypes()),
-                                           ::testing::ValuesIn(RpcSecurityValues())),
+                                           ::testing::ValuesIn(RpcSecurityValues()),
+                                           ::testing::ValuesIn(testVersions()),
+                                           ::testing::ValuesIn(testVersions()),
+                                           ::testing::Values(false, true),
+                                           ::testing::Values(false, true)),
+                        BinderRpc::PrintParamInfo);
+
+INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpcThreads,
+                        ::testing::Combine(::testing::ValuesIn(testSocketTypes()),
+                                           ::testing::ValuesIn(RpcSecurityValues()),
+                                           ::testing::ValuesIn(testVersions()),
+                                           ::testing::ValuesIn(testVersions()),
+                                           ::testing::Values(false),
+                                           ::testing::Values(false, true)),
                         BinderRpc::PrintParamInfo);
 
 class BinderRpcServerRootObject
@@ -1468,9 +1594,14 @@
     bool mValue = false;
 };
 
-TEST_P(BinderRpcSimple, Shutdown) {
+TEST_P(BinderRpcServerOnly, Shutdown) {
+    if constexpr (!kEnableRpcThreads) {
+        GTEST_SKIP() << "Test skipped because threads were disabled at build time";
+    }
+
     auto addr = allocateSocketAddress();
-    auto server = RpcServer::make(newFactory(GetParam()));
+    auto server = RpcServer::make(newFactory(std::get<0>(GetParam())));
+    server->setProtocolVersion(std::get<1>(GetParam()));
     ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
     auto joinEnds = std::make_shared<OneOffSignal>();
 
@@ -1499,6 +1630,11 @@
                     "createRpcDelegateServiceManager() with a device attached, such test belongs "
                     "to binderHostDeviceTest. Hence, just disable this test on host.";
 #endif // !__ANDROID__
+    if constexpr (!kEnableKernelIpc) {
+        GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+                        "at build time.";
+    }
+
     sp<IServiceManager> sm = defaultServiceManager();
     ASSERT_NE(nullptr, sm);
     // Any Java service with non-empty getInterfaceDescriptor() would do.
@@ -1540,12 +1676,17 @@
     ASSERT_EQ(OK, rpcBinder->pingBinder());
 }
 
-INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
-                        BinderRpcSimple::PrintTestParam);
+INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcServerOnly,
+                        ::testing::Combine(::testing::ValuesIn(RpcSecurityValues()),
+                                           ::testing::ValuesIn(testVersions())),
+                        BinderRpcServerOnly::PrintTestParam);
 
 class RpcTransportTestUtils {
 public:
-    using Param = std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>>;
+    // Only parameterized only server version because `RpcSession` is bypassed
+    // in the client half of the tests.
+    using Param =
+            std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>, uint32_t>;
     using ConnectToServer = std::function<base::unique_fd()>;
 
     // A server that handles client socket connections.
@@ -1557,8 +1698,9 @@
         [[nodiscard]] AssertionResult setUp(
                 const Param& param,
                 std::unique_ptr<RpcAuth> auth = std::make_unique<RpcAuthSelfSigned>()) {
-            auto [socketType, rpcSecurity, certificateFormat] = param;
+            auto [socketType, rpcSecurity, certificateFormat, serverVersion] = param;
             auto rpcServer = RpcServer::make(newFactory(rpcSecurity));
+            rpcServer->setProtocolVersion(serverVersion);
             switch (socketType) {
                 case SocketType::PRECONNECTED: {
                     return AssertionFailure() << "Not supported by this test";
@@ -1676,7 +1818,8 @@
                                                   FdTrigger* fdTrigger) {
             std::string message(kMessage);
             iovec messageIov{message.data(), message.size()};
-            auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1, {});
+            auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1,
+                                                                   std::nullopt, nullptr);
             if (status != OK) return AssertionFailure() << statusToString(status);
             return AssertionSuccess();
         }
@@ -1687,7 +1830,8 @@
         explicit Client(ConnectToServer connectToServer) : mConnectToServer(connectToServer) {}
         Client(Client&&) = default;
         [[nodiscard]] AssertionResult setUp(const Param& param) {
-            auto [socketType, rpcSecurity, certificateFormat] = param;
+            auto [socketType, rpcSecurity, certificateFormat, serverVersion] = param;
+            (void)serverVersion;
             mFdTrigger = FdTrigger::make();
             mCtx = newFactory(rpcSecurity, mCertVerifier)->newClientCtx();
             if (mCtx == nullptr) return AssertionFailure() << "newClientCtx";
@@ -1708,8 +1852,9 @@
             LOG_ALWAYS_FATAL_IF(mClientTransport == nullptr, "setUpTransport not called or failed");
             std::string readMessage(expectedMessage.size(), '\0');
             iovec readMessageIov{readMessage.data(), readMessage.size()};
-            status_t readStatus = mClientTransport->interruptableReadFully(mFdTrigger.get(),
-                                                                           &readMessageIov, 1, {});
+            status_t readStatus =
+                    mClientTransport->interruptableReadFully(mFdTrigger.get(), &readMessageIov, 1,
+                                                             std::nullopt, nullptr);
             if (readStatus != OK) {
                 return AssertionFailure() << statusToString(readStatus);
             }
@@ -1757,23 +1902,28 @@
     using Server = RpcTransportTestUtils::Server;
     using Client = RpcTransportTestUtils::Client;
     static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
-        auto [socketType, rpcSecurity, certificateFormat] = info.param;
+        auto [socketType, rpcSecurity, certificateFormat, serverVersion] = info.param;
         auto ret = PrintToString(socketType) + "_" + newFactory(rpcSecurity)->toCString();
         if (certificateFormat.has_value()) ret += "_" + PrintToString(*certificateFormat);
+        ret += "_serverV" + std::to_string(serverVersion);
         return ret;
     }
     static std::vector<ParamType> getRpcTranportTestParams() {
         std::vector<ParamType> ret;
-        for (auto socketType : testSocketTypes(false /* hasPreconnected */)) {
-            for (auto rpcSecurity : RpcSecurityValues()) {
-                switch (rpcSecurity) {
-                    case RpcSecurity::RAW: {
-                        ret.emplace_back(socketType, rpcSecurity, std::nullopt);
-                    } break;
-                    case RpcSecurity::TLS: {
-                        ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM);
-                        ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER);
-                    } break;
+        for (auto serverVersion : testVersions()) {
+            for (auto socketType : testSocketTypes(false /* hasPreconnected */)) {
+                for (auto rpcSecurity : RpcSecurityValues()) {
+                    switch (rpcSecurity) {
+                        case RpcSecurity::RAW: {
+                            ret.emplace_back(socketType, rpcSecurity, std::nullopt, serverVersion);
+                        } break;
+                        case RpcSecurity::TLS: {
+                            ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM,
+                                             serverVersion);
+                            ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER,
+                                             serverVersion);
+                        } break;
+                    }
                 }
             }
         }
@@ -1781,9 +1931,15 @@
     }
     template <typename A, typename B>
     status_t trust(const A& a, const B& b) {
-        auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+        auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+        (void)serverVersion;
         return RpcTransportTestUtils::trust(rpcSecurity, certificateFormat, a, b);
     }
+    void SetUp() override {
+        if constexpr (!kEnableRpcThreads) {
+            GTEST_SKIP() << "Test skipped because threads were disabled at build time";
+        }
+    }
 };
 
 TEST_P(RpcTransportTest, GoodCertificate) {
@@ -1817,7 +1973,8 @@
 }
 
 TEST_P(RpcTransportTest, UntrustedServer) {
-    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+    auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+    (void)serverVersion;
 
     auto untrustedServer = std::make_unique<Server>();
     ASSERT_TRUE(untrustedServer->setUp(GetParam()));
@@ -1835,7 +1992,9 @@
     client.run(handshakeOk);
 }
 TEST_P(RpcTransportTest, MaliciousServer) {
-    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+    auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+    (void)serverVersion;
+
     auto validServer = std::make_unique<Server>();
     ASSERT_TRUE(validServer->setUp(GetParam()));
 
@@ -1858,7 +2017,9 @@
 }
 
 TEST_P(RpcTransportTest, UntrustedClient) {
-    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+    auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+    (void)serverVersion;
+
     auto server = std::make_unique<Server>();
     ASSERT_TRUE(server->setUp(GetParam()));
 
@@ -1877,7 +2038,9 @@
 }
 
 TEST_P(RpcTransportTest, MaliciousClient) {
-    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+    auto [socketType, rpcSecurity, certificateFormat, serverVersion] = GetParam();
+    (void)serverVersion;
+
     auto server = std::make_unique<Server>();
     ASSERT_TRUE(server->setUp(GetParam()));
 
@@ -1904,7 +2067,8 @@
     auto serverPostConnect = [&](RpcTransport* serverTransport, FdTrigger* fdTrigger) {
         std::string message(RpcTransportTestUtils::kMessage);
         iovec messageIov{message.data(), message.size()};
-        auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1, {});
+        auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1,
+                                                               std::nullopt, nullptr);
         if (status != OK) return AssertionFailure() << statusToString(status);
 
         {
@@ -1915,7 +2079,8 @@
         }
 
         iovec msg2Iov{msg2.data(), msg2.size()};
-        status = serverTransport->interruptableWriteFully(fdTrigger, &msg2Iov, 1, {});
+        status = serverTransport->interruptableWriteFully(fdTrigger, &msg2Iov, 1, std::nullopt,
+                                                          nullptr);
         if (status != DEAD_OBJECT)
             return AssertionFailure() << "When FdTrigger is shut down, interruptableWriteFully "
                                          "should return DEAD_OBJECT, but it is "
@@ -1962,23 +2127,28 @@
                         RpcTransportTest::PrintParamInfo);
 
 class RpcTransportTlsKeyTest
-      : public testing::TestWithParam<std::tuple<SocketType, RpcCertificateFormat, RpcKeyFormat>> {
+      : public testing::TestWithParam<
+                std::tuple<SocketType, RpcCertificateFormat, RpcKeyFormat, uint32_t>> {
 public:
     template <typename A, typename B>
     status_t trust(const A& a, const B& b) {
-        auto [socketType, certificateFormat, keyFormat] = GetParam();
+        auto [socketType, certificateFormat, keyFormat, serverVersion] = GetParam();
+        (void)serverVersion;
         return RpcTransportTestUtils::trust(RpcSecurity::TLS, certificateFormat, a, b);
     }
     static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
-        auto [socketType, certificateFormat, keyFormat] = info.param;
-        auto ret = PrintToString(socketType) + "_certificate_" + PrintToString(certificateFormat) +
-                "_key_" + PrintToString(keyFormat);
-        return ret;
+        auto [socketType, certificateFormat, keyFormat, serverVersion] = info.param;
+        return PrintToString(socketType) + "_certificate_" + PrintToString(certificateFormat) +
+                "_key_" + PrintToString(keyFormat) + "_serverV" + std::to_string(serverVersion);
     };
 };
 
 TEST_P(RpcTransportTlsKeyTest, PreSignedCertificate) {
-    auto [socketType, certificateFormat, keyFormat] = GetParam();
+    if constexpr (!kEnableRpcThreads) {
+        GTEST_SKIP() << "Test skipped because threads were disabled at build time";
+    }
+
+    auto [socketType, certificateFormat, keyFormat, serverVersion] = GetParam();
 
     std::vector<uint8_t> pkeyData, certData;
     {
@@ -1993,8 +2163,8 @@
     auto desPkey = deserializeUnencryptedPrivatekey(pkeyData, keyFormat);
     auto desCert = deserializeCertificate(certData, certificateFormat);
     auto auth = std::make_unique<RpcAuthPreSigned>(std::move(desPkey), std::move(desCert));
-    auto utilsParam =
-            std::make_tuple(socketType, RpcSecurity::TLS, std::make_optional(certificateFormat));
+    auto utilsParam = std::make_tuple(socketType, RpcSecurity::TLS,
+                                      std::make_optional(certificateFormat), serverVersion);
 
     auto server = std::make_unique<RpcTransportTestUtils::Server>();
     ASSERT_TRUE(server->setUp(utilsParam, std::move(auth)));
@@ -2013,7 +2183,8 @@
         BinderRpc, RpcTransportTlsKeyTest,
         testing::Combine(testing::ValuesIn(testSocketTypes(false /* hasPreconnected*/)),
                          testing::Values(RpcCertificateFormat::PEM, RpcCertificateFormat::DER),
-                         testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER)),
+                         testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER),
+                         testing::ValuesIn(testVersions())),
         RpcTransportTlsKeyTest::PrintParamInfo);
 
 } // namespace android
diff --git a/libs/binder/tests/binderRpcTestCommon.cpp b/libs/binder/tests/binderRpcTestCommon.cpp
new file mode 100644
index 0000000..0d9aa95
--- /dev/null
+++ b/libs/binder/tests/binderRpcTestCommon.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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 "binderRpcTestCommon.h"
+
+namespace android {
+
+std::atomic<int32_t> MyBinderRpcSession::gNum;
+sp<IBinder> MyBinderRpcTest::mHeldBinder;
+
+} // namespace android
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
new file mode 100644
index 0000000..4513d36
--- /dev/null
+++ b/libs/binder/tests/binderRpcTestCommon.h
@@ -0,0 +1,379 @@
+/*
+ * 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 <BinderRpcTestClientInfo.h>
+#include <BinderRpcTestServerConfig.h>
+#include <BinderRpcTestServerInfo.h>
+#include <BnBinderRpcCallback.h>
+#include <BnBinderRpcSession.h>
+#include <BnBinderRpcTest.h>
+#include <aidl/IBinderRpcTest.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_libbinder.h>
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
+#include <binder/RpcThreads.h>
+#include <binder/RpcTlsTestUtils.h>
+#include <binder/RpcTlsUtils.h>
+#include <binder/RpcTransport.h>
+#include <binder/RpcTransportRaw.h>
+#include <binder/RpcTransportTls.h>
+#include <unistd.h>
+#include <string>
+#include <vector>
+
+#include <signal.h>
+
+#include "../BuildFlags.h"
+#include "../FdTrigger.h"
+#include "../RpcSocketAddress.h" // for testing preconnected clients
+#include "../RpcState.h"         // for debugging
+#include "../vm_sockets.h"       // for VMADDR_*
+#include "utils/Errors.h"
+
+namespace android {
+
+constexpr char kLocalInetAddress[] = "127.0.0.1";
+
+enum class RpcSecurity { RAW, TLS };
+
+static inline std::vector<RpcSecurity> RpcSecurityValues() {
+    return {RpcSecurity::RAW, RpcSecurity::TLS};
+}
+
+enum class SocketType {
+    PRECONNECTED,
+    UNIX,
+    VSOCK,
+    INET,
+};
+static inline std::string PrintToString(SocketType socketType) {
+    switch (socketType) {
+        case SocketType::PRECONNECTED:
+            return "preconnected_uds";
+        case SocketType::UNIX:
+            return "unix_domain_socket";
+        case SocketType::VSOCK:
+            return "vm_socket";
+        case SocketType::INET:
+            return "inet_socket";
+        default:
+            LOG_ALWAYS_FATAL("Unknown socket type");
+            return "";
+    }
+}
+
+struct BinderRpcOptions {
+    size_t numThreads = 1;
+    size_t numSessions = 1;
+    size_t numIncomingConnections = 0;
+    size_t numOutgoingConnections = SIZE_MAX;
+    RpcSession::FileDescriptorTransportMode clientFileDescriptorTransportMode =
+            RpcSession::FileDescriptorTransportMode::NONE;
+    std::vector<RpcSession::FileDescriptorTransportMode>
+            serverSupportedFileDescriptorTransportModes = {
+                    RpcSession::FileDescriptorTransportMode::NONE};
+
+    // If true, connection failures will result in `ProcessSession::sessions` being empty
+    // instead of a fatal error.
+    bool allowConnectFailure = false;
+};
+
+static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
+    uint64_t length = str.length();
+    CHECK(android::base::WriteFully(fd, &length, sizeof(length)));
+    CHECK(android::base::WriteFully(fd, str.data(), str.length()));
+}
+
+static inline std::string readString(android::base::borrowed_fd fd) {
+    uint64_t length;
+    CHECK(android::base::ReadFully(fd, &length, sizeof(length)));
+    std::string ret(length, '\0');
+    CHECK(android::base::ReadFully(fd, ret.data(), length));
+    return ret;
+}
+
+static inline void writeToFd(android::base::borrowed_fd fd, const Parcelable& parcelable) {
+    Parcel parcel;
+    CHECK_EQ(OK, parcelable.writeToParcel(&parcel));
+    writeString(fd, std::string(reinterpret_cast<const char*>(parcel.data()), parcel.dataSize()));
+}
+
+template <typename T>
+static inline T readFromFd(android::base::borrowed_fd fd) {
+    std::string data = readString(fd);
+    Parcel parcel;
+    CHECK_EQ(OK, parcel.setData(reinterpret_cast<const uint8_t*>(data.data()), data.size()));
+    T object;
+    CHECK_EQ(OK, object.readFromParcel(&parcel));
+    return object;
+}
+
+static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(
+        RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr,
+        std::unique_ptr<RpcAuth> auth = nullptr) {
+    switch (rpcSecurity) {
+        case RpcSecurity::RAW:
+            return RpcTransportCtxFactoryRaw::make();
+        case RpcSecurity::TLS: {
+            if (verifier == nullptr) {
+                verifier = std::make_shared<RpcCertificateVerifierSimple>();
+            }
+            if (auth == nullptr) {
+                auth = std::make_unique<RpcAuthSelfSigned>();
+            }
+            return RpcTransportCtxFactoryTls::make(std::move(verifier), std::move(auth));
+        }
+        default:
+            LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
+    }
+}
+
+// Create an FD that returns `contents` when read.
+static inline base::unique_fd mockFileDescriptor(std::string contents) {
+    android::base::unique_fd readFd, writeFd;
+    CHECK(android::base::Pipe(&readFd, &writeFd)) << strerror(errno);
+    RpcMaybeThread([writeFd = std::move(writeFd), contents = std::move(contents)]() {
+        signal(SIGPIPE, SIG_IGN); // ignore possible SIGPIPE from the write
+        if (!WriteStringToFd(contents, writeFd)) {
+            int savedErrno = errno;
+            LOG_ALWAYS_FATAL_IF(EPIPE != savedErrno, "mockFileDescriptor write failed: %s",
+                                strerror(savedErrno));
+        }
+    }).detach();
+    return readFd;
+}
+
+using android::binder::Status;
+
+class MyBinderRpcSession : public BnBinderRpcSession {
+public:
+    static std::atomic<int32_t> gNum;
+
+    MyBinderRpcSession(const std::string& name) : mName(name) { gNum++; }
+    Status getName(std::string* name) override {
+        *name = mName;
+        return Status::ok();
+    }
+    ~MyBinderRpcSession() { gNum--; }
+
+private:
+    std::string mName;
+};
+
+class MyBinderRpcCallback : public BnBinderRpcCallback {
+    Status sendCallback(const std::string& value) {
+        RpcMutexUniqueLock _l(mMutex);
+        mValues.push_back(value);
+        _l.unlock();
+        mCv.notify_one();
+        return Status::ok();
+    }
+    Status sendOnewayCallback(const std::string& value) { return sendCallback(value); }
+
+public:
+    RpcMutex mMutex;
+    RpcConditionVariable mCv;
+    std::vector<std::string> mValues;
+};
+
+class MyBinderRpcTest : public BnBinderRpcTest {
+public:
+    wp<RpcServer> server;
+    int port = 0;
+
+    Status sendString(const std::string& str) override {
+        (void)str;
+        return Status::ok();
+    }
+    Status doubleString(const std::string& str, std::string* strstr) override {
+        *strstr = str + str;
+        return Status::ok();
+    }
+    Status getClientPort(int* out) override {
+        *out = port;
+        return Status::ok();
+    }
+    Status countBinders(std::vector<int32_t>* out) override {
+        sp<RpcServer> spServer = server.promote();
+        if (spServer == nullptr) {
+            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+        }
+        out->clear();
+        for (auto session : spServer->listSessions()) {
+            size_t count = session->state()->countBinders();
+            out->push_back(count);
+        }
+        return Status::ok();
+    }
+    Status getNullBinder(sp<IBinder>* out) override {
+        out->clear();
+        return Status::ok();
+    }
+    Status pingMe(const sp<IBinder>& binder, int32_t* out) override {
+        if (binder == nullptr) {
+            std::cout << "Received null binder!" << std::endl;
+            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+        }
+        *out = binder->pingBinder();
+        return Status::ok();
+    }
+    Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
+        *out = binder;
+        return Status::ok();
+    }
+    static sp<IBinder> mHeldBinder;
+    Status holdBinder(const sp<IBinder>& binder) override {
+        mHeldBinder = binder;
+        return Status::ok();
+    }
+    Status getHeldBinder(sp<IBinder>* held) override {
+        *held = mHeldBinder;
+        return Status::ok();
+    }
+    Status nestMe(const sp<IBinderRpcTest>& binder, int count) override {
+        if (count <= 0) return Status::ok();
+        return binder->nestMe(this, count - 1);
+    }
+    Status alwaysGiveMeTheSameBinder(sp<IBinder>* out) override {
+        static sp<IBinder> binder = new BBinder;
+        *out = binder;
+        return Status::ok();
+    }
+    Status openSession(const std::string& name, sp<IBinderRpcSession>* out) override {
+        *out = new MyBinderRpcSession(name);
+        return Status::ok();
+    }
+    Status getNumOpenSessions(int32_t* out) override {
+        *out = MyBinderRpcSession::gNum;
+        return Status::ok();
+    }
+
+    RpcMutex blockMutex;
+    Status lock() override {
+        blockMutex.lock();
+        return Status::ok();
+    }
+    Status unlockInMsAsync(int32_t ms) override {
+        usleep(ms * 1000);
+        blockMutex.unlock();
+        return Status::ok();
+    }
+    Status lockUnlock() override {
+        RpcMutexLockGuard _l(blockMutex);
+        return Status::ok();
+    }
+
+    Status sleepMs(int32_t ms) override {
+        usleep(ms * 1000);
+        return Status::ok();
+    }
+
+    Status sleepMsAsync(int32_t ms) override {
+        // In-process binder calls are asynchronous, but the call to this method
+        // is synchronous wrt its client. This in/out-process threading model
+        // diffentiation is a classic binder leaky abstraction (for better or
+        // worse) and is preserved here the way binder sockets plugs itself
+        // into BpBinder, as nothing is changed at the higher levels
+        // (IInterface) which result in this behavior.
+        return sleepMs(ms);
+    }
+
+    Status doCallback(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
+                      const std::string& value) override {
+        if (callback == nullptr) {
+            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+        }
+
+        if (delayed) {
+            RpcMaybeThread([=]() {
+                ALOGE("Executing delayed callback: '%s'", value.c_str());
+                Status status = doCallback(callback, oneway, false, value);
+                ALOGE("Delayed callback status: '%s'", status.toString8().c_str());
+            }).detach();
+            return Status::ok();
+        }
+
+        if (oneway) {
+            return callback->sendOnewayCallback(value);
+        }
+
+        return callback->sendCallback(value);
+    }
+
+    Status doCallbackAsync(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
+                           const std::string& value) override {
+        return doCallback(callback, oneway, delayed, value);
+    }
+
+    Status die(bool cleanup) override {
+        if (cleanup) {
+            exit(1);
+        } else {
+            _exit(1);
+        }
+    }
+
+    Status scheduleShutdown() override {
+        sp<RpcServer> strongServer = server.promote();
+        if (strongServer == nullptr) {
+            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+        }
+        RpcMaybeThread([=] {
+            LOG_ALWAYS_FATAL_IF(!strongServer->shutdown(), "Could not shutdown");
+        }).detach();
+        return Status::ok();
+    }
+
+    Status useKernelBinderCallingId() override {
+        // this is WRONG! It does not make sense when using RPC binder, and
+        // because it is SO wrong, and so much code calls this, it should abort!
+
+        if constexpr (kEnableKernelIpc) {
+            (void)IPCThreadState::self()->getCallingPid();
+        }
+        return Status::ok();
+    }
+
+    Status echoAsFile(const std::string& content, android::os::ParcelFileDescriptor* out) override {
+        out->reset(mockFileDescriptor(content));
+        return Status::ok();
+    }
+
+    Status concatFiles(const std::vector<android::os::ParcelFileDescriptor>& files,
+                       android::os::ParcelFileDescriptor* out) override {
+        std::string acc;
+        for (const auto& file : files) {
+            std::string result;
+            CHECK(android::base::ReadFdToString(file.get(), &result));
+            acc.append(result);
+        }
+        out->reset(mockFileDescriptor(acc));
+        return Status::ok();
+    }
+};
+
+} // namespace android
diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp
new file mode 100644
index 0000000..31eb5da
--- /dev/null
+++ b/libs/binder/tests/binderRpcTestService.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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 "binderRpcTestCommon.h"
+
+using namespace android;
+
+int main(int argc, const char* argv[]) {
+    LOG_ALWAYS_FATAL_IF(argc != 3, "Invalid number of arguments: %d", argc);
+    base::unique_fd writeEnd(atoi(argv[1]));
+    base::unique_fd readEnd(atoi(argv[2]));
+
+    auto serverConfig = readFromFd<BinderRpcTestServerConfig>(readEnd);
+    auto socketType = static_cast<SocketType>(serverConfig.socketType);
+    auto rpcSecurity = static_cast<RpcSecurity>(serverConfig.rpcSecurity);
+
+    std::vector<RpcSession::FileDescriptorTransportMode>
+            serverSupportedFileDescriptorTransportModes;
+    for (auto mode : serverConfig.serverSupportedFileDescriptorTransportModes) {
+        serverSupportedFileDescriptorTransportModes.push_back(
+                static_cast<RpcSession::FileDescriptorTransportMode>(mode));
+    }
+
+    auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+    sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
+
+    server->setProtocolVersion(serverConfig.serverVersion);
+    server->setMaxThreads(serverConfig.numThreads);
+    server->setSupportedFileDescriptorTransportModes(serverSupportedFileDescriptorTransportModes);
+
+    unsigned int outPort = 0;
+
+    switch (socketType) {
+        case SocketType::PRECONNECTED:
+            [[fallthrough]];
+        case SocketType::UNIX:
+            CHECK_EQ(OK, server->setupUnixDomainServer(serverConfig.addr.c_str()))
+                    << serverConfig.addr;
+            break;
+        case SocketType::VSOCK:
+            CHECK_EQ(OK, server->setupVsockServer(serverConfig.vsockPort));
+            break;
+        case SocketType::INET: {
+            CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
+            CHECK_NE(0, outPort);
+            break;
+        }
+        default:
+            LOG_ALWAYS_FATAL("Unknown socket type");
+    }
+
+    BinderRpcTestServerInfo serverInfo;
+    serverInfo.port = static_cast<int64_t>(outPort);
+    serverInfo.cert.data = server->getCertificate(RpcCertificateFormat::PEM);
+    writeToFd(writeEnd, serverInfo);
+    auto clientInfo = readFromFd<BinderRpcTestClientInfo>(readEnd);
+
+    if (rpcSecurity == RpcSecurity::TLS) {
+        for (const auto& clientCert : clientInfo.certs) {
+            CHECK_EQ(OK,
+                     certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
+                                                             clientCert.data));
+        }
+    }
+
+    server->setPerSessionRootObject([&](const void* addrPtr, size_t len) {
+        // UNIX sockets with abstract addresses return
+        // sizeof(sa_family_t)==2 in addrlen
+        CHECK_GE(len, sizeof(sa_family_t));
+        const sockaddr* addr = reinterpret_cast<const sockaddr*>(addrPtr);
+        sp<MyBinderRpcTest> service = sp<MyBinderRpcTest>::make();
+        switch (addr->sa_family) {
+            case AF_UNIX:
+                // nothing to save
+                break;
+            case AF_VSOCK:
+                CHECK_EQ(len, sizeof(sockaddr_vm));
+                service->port = reinterpret_cast<const sockaddr_vm*>(addr)->svm_port;
+                break;
+            case AF_INET:
+                CHECK_EQ(len, sizeof(sockaddr_in));
+                service->port = ntohs(reinterpret_cast<const sockaddr_in*>(addr)->sin_port);
+                break;
+            case AF_INET6:
+                CHECK_EQ(len, sizeof(sockaddr_in));
+                service->port = ntohs(reinterpret_cast<const sockaddr_in6*>(addr)->sin6_port);
+                break;
+            default:
+                LOG_ALWAYS_FATAL("Unrecognized address family %d", addr->sa_family);
+        }
+        service->server = server;
+        return service;
+    });
+
+    server->join();
+
+    // Another thread calls shutdown. Wait for it to complete.
+    (void)server->shutdown();
+
+    return 0;
+}
diff --git a/libs/binder/tests/binderRpcWireProtocolTest.cpp b/libs/binder/tests/binderRpcWireProtocolTest.cpp
index a807afa..3dab2c7 100644
--- a/libs/binder/tests/binderRpcWireProtocolTest.cpp
+++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp
@@ -233,12 +233,17 @@
         "0100000025000000|03000000|00000000|ffffffff|03000000|00000000|00000000|"
         "07000000020000003a0044000000000000000000|f8ffffff020000003a002f00000000000000000008000000";
 
+TEST(RpcWire, V0) {
+    checkRepr(kCurrentRepr, 0);
+}
+
 TEST(RpcWire, CurrentVersion) {
     checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION);
 }
 
 static_assert(RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL,
-              "you better update this test!");
+              "If the binder wire protocol is updated, this test should test additional versions. "
+              "The binder wire protocol should only be updated on upstream AOSP.");
 
 TEST(RpcWire, ReleaseBranchHasFrozenRpcWireProtocol) {
     if (RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index 3b1faa8..cfaf2a9 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -249,12 +249,13 @@
     pid_t pid = fork();
     if (pid) {
         /* parent */
-        return move(get<0>(pipe_pair));
+        return std::move(get<0>(pipe_pair));
     } else {
         /* child */
-        worker_fx(num, worker_count, iterations, payload_size, cs_pair, move(get<1>(pipe_pair)));
+        worker_fx(num, worker_count, iterations, payload_size, cs_pair,
+                  std::move(get<1>(pipe_pair)));
         /* never get here */
-        return move(get<0>(pipe_pair));
+        return std::move(get<0>(pipe_pair));
     }
 
 }
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index e5d32da..0210237 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -7,6 +7,22 @@
     default_applicable_licenses: ["frameworks_native_license"],
 }
 
+aidl_interface {
+    name: "binderReadParcelIface",
+    host_supported: true,
+    unstable: true,
+    srcs: [
+        "EmptyParcelable.aidl",
+        "SingleDataParcelable.aidl",
+        "GenericDataParcelable.aidl",
+    ],
+    backend: {
+        java: {
+            enabled: false,
+        },
+    },
+}
+
 cc_fuzz {
     name: "binder_parcel_fuzzer",
     host_supported: true,
@@ -29,6 +45,8 @@
         "libcutils",
         "libhidlbase",
         "liblog",
+        "binderReadParcelIface-cpp",
+        "binderReadParcelIface-ndk",
     ],
 
     target: {
@@ -59,6 +77,7 @@
 cc_library_static {
     name: "libbinder_random_parcel",
     host_supported: true,
+    vendor_available: true,
     target: {
         darwin: {
             enabled: false,
diff --git a/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl b/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl
new file mode 100644
index 0000000..96d6223
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl
@@ -0,0 +1,18 @@
+/*
+ * 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/GenericDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
new file mode 100644
index 0000000..fc2542b
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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 GenericDataParcelable {
+    int data;
+    float majorVersion;
+    float minorVersion;
+    IBinder binder;
+    ParcelFileDescriptor fileDescriptor;
+    int[] array;
+}
\ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
new file mode 100644
index 0000000..d62891b
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 SingleDataParcelable{
+   int data;
+}
\ 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 47ec776..9dac2c9 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -16,6 +16,9 @@
 #define FUZZ_LOG_TAG "binder"
 
 #include "binder.h"
+#include "EmptyParcelable.h"
+#include "GenericDataParcelable.h"
+#include "SingleDataParcelable.h"
 #include "util.h"
 
 #include <android-base/hex.h>
@@ -73,20 +76,20 @@
     uint8_t data[1337];
 };
 
-#define PARCEL_READ_WITH_STATUS(T, FUN) \
-    [] (const ::android::Parcel& p, uint8_t /*data*/) {\
-        FUZZ_LOG() << "about to read " #T " using " #FUN " with status";\
-        T t{};\
-        status_t status = p.FUN(&t);\
-        FUZZ_LOG() << #T " status: " << status /* << " value: " << t*/;\
+#define PARCEL_READ_WITH_STATUS(T, FUN)                                  \
+    [](const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {   \
+        FUZZ_LOG() << "about to read " #T " using " #FUN " with status"; \
+        T t{};                                                           \
+        status_t status = p.FUN(&t);                                     \
+        FUZZ_LOG() << #T " status: " << status /* << " value: " << t*/;  \
     }
 
-#define PARCEL_READ_NO_STATUS(T, FUN) \
-    [] (const ::android::Parcel& p, uint8_t /*data*/) {\
-        FUZZ_LOG() << "about to read " #T " using " #FUN " with no status";\
-        T t = p.FUN();\
-        (void) t;\
-        FUZZ_LOG() << #T " done " /* << " value: " << t*/;\
+#define PARCEL_READ_NO_STATUS(T, FUN)                                       \
+    [](const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {      \
+        FUZZ_LOG() << "about to read " #T " using " #FUN " with no status"; \
+        T t = p.FUN();                                                      \
+        (void)t;                                                            \
+        FUZZ_LOG() << #T " done " /* << " value: " << t*/;                  \
     }
 
 #define PARCEL_READ_OPT_STATUS(T, FUN) \
@@ -102,7 +105,9 @@
     PARCEL_READ_NO_STATUS(size_t, dataPosition),
     PARCEL_READ_NO_STATUS(size_t, dataCapacity),
     PARCEL_READ_NO_STATUS(::android::binder::Status, enforceNoDataAvail),
-    [] (const ::android::Parcel& p, uint8_t pos) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
+        // aborts on larger values
+        size_t pos = provider.ConsumeIntegralInRange<size_t>(0, INT32_MAX);
         FUZZ_LOG() << "about to setDataPosition: " << pos;
         p.setDataPosition(pos);
         FUZZ_LOG() << "setDataPosition done";
@@ -111,13 +116,13 @@
     PARCEL_READ_NO_STATUS(size_t, hasFileDescriptors),
     PARCEL_READ_NO_STATUS(std::vector<android::sp<android::IBinder>>, debugReadAllStrongBinders),
     PARCEL_READ_NO_STATUS(std::vector<int>, debugReadAllFileDescriptors),
-    [] (const ::android::Parcel& p, uint8_t len) {
-        std::string interface(len, 'a');
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
+        std::string interface = provider.ConsumeRandomLengthString();
         FUZZ_LOG() << "about to enforceInterface: " << interface;
         bool b = p.enforceInterface(::android::String16(interface.c_str()));
         FUZZ_LOG() << "enforced interface: " << b;
     },
-    [] (const ::android::Parcel& p, uint8_t /*len*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to checkInterface";
         android::sp<android::IBinder> aBinder = new android::BBinder();
         bool b = p.checkInterface(aBinder.get());
@@ -125,13 +130,16 @@
     },
     PARCEL_READ_NO_STATUS(size_t, objectsCount),
     PARCEL_READ_NO_STATUS(status_t, errorCheck),
-    [] (const ::android::Parcel& p, uint8_t len) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
+        // Read at least a bit. Unbounded allocation would OOM.
+        size_t len = provider.ConsumeIntegralInRange<size_t>(0, 1024);
         FUZZ_LOG() << "about to read void*";
         std::vector<uint8_t> data(len);
         status_t status = p.read(data.data(), len);
         FUZZ_LOG() << "read status: " << status;
     },
-    [] (const ::android::Parcel& p, uint8_t len) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
+        size_t len = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to readInplace";
         const void* r = p.readInplace(len);
         FUZZ_LOG() << "readInplace done. pointer: " << r << " bytes: " << (r ? HexString(r, len) : "null");
@@ -149,13 +157,13 @@
     PARCEL_READ_WITH_STATUS(std::string, readUtf8FromUtf16),
     PARCEL_READ_WITH_STATUS(std::unique_ptr<std::string>, readUtf8FromUtf16),
     PARCEL_READ_WITH_STATUS(std::optional<std::string>, readUtf8FromUtf16),
-    [] (const ::android::Parcel& p, uint8_t /*data*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to read c-str";
         const char* str = p.readCString();
         FUZZ_LOG() << "read c-str: " << (str ? str : "<empty string>");
     },
     PARCEL_READ_OPT_STATUS(android::String8, readString8),
-    [] (const ::android::Parcel& p, uint8_t /*data*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to readString8Inplace";
         size_t outLen = 0;
         const char* str = p.readString8Inplace(&outLen);
@@ -165,7 +173,7 @@
     PARCEL_READ_OPT_STATUS(android::String16, readString16),
     PARCEL_READ_WITH_STATUS(std::unique_ptr<android::String16>, readString16),
     PARCEL_READ_WITH_STATUS(std::optional<android::String16>, readString16),
-    [] (const ::android::Parcel& p, uint8_t /*data*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to readString16Inplace";
         size_t outLen = 0;
         const char16_t* str = p.readString16Inplace(&outLen);
@@ -263,13 +271,13 @@
     PARCEL_READ_WITH_STATUS(std::optional<std::array<std::array<std::optional<ExampleParcelable> COMMA 3> COMMA 4>>, readFixedArray),
 #undef COMMA
 
-    [] (const android::Parcel& p, uint8_t /*len*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to read flattenable";
         ExampleFlattenable f;
         status_t status = p.read(f);
         FUZZ_LOG() << "read flattenable: " << status;
     },
-    [] (const android::Parcel& p, uint8_t /*len*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to read lite flattenable";
         ExampleLightFlattenable f;
         status_t status = p.read(f);
@@ -284,7 +292,7 @@
     PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<BigStruct>>, resizeOutVector),
 
     PARCEL_READ_NO_STATUS(int32_t, readExceptionCode),
-    [] (const android::Parcel& p, uint8_t /*len*/) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to readNativeHandle";
         native_handle_t* t = p.readNativeHandle();
         FUZZ_LOG() << "readNativeHandle: " << t;
@@ -303,15 +311,16 @@
     PARCEL_READ_WITH_STATUS(std::optional<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector),
     PARCEL_READ_WITH_STATUS(std::vector<android::base::unique_fd>, readUniqueFileDescriptorVector),
 
-    [] (const android::Parcel& p, uint8_t len) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
+        size_t len = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to readBlob";
         ::android::Parcel::ReadableBlob blob;
         status_t status = p.readBlob(len, &blob);
         FUZZ_LOG() << "readBlob status: " << status;
     },
-    [] (const android::Parcel& p, uint8_t options) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
         FUZZ_LOG() << "about to readObject";
-        bool nullMetaData = options & 0x1;
+        bool nullMetaData = provider.ConsumeBool();
         const void* obj = static_cast<const void*>(p.readObject(nullMetaData));
         FUZZ_LOG() << "readObject: " << obj;
     },
@@ -319,20 +328,19 @@
     PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),
 
     // additional parcelable objects defined in libbinder
-    [] (const ::android::Parcel& p, uint8_t data) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& provider) {
         using ::android::os::ParcelableHolder;
         using ::android::Parcelable;
         FUZZ_LOG() << "about to read ParcelableHolder using readParcelable with status";
-        Parcelable::Stability stability = Parcelable::Stability::STABILITY_LOCAL;
-        if ( (data & 1) == 1 ) {
-            stability = Parcelable::Stability::STABILITY_VINTF;
-        }
+        Parcelable::Stability stability = provider.ConsumeBool()
+            ? Parcelable::Stability::STABILITY_LOCAL
+            : Parcelable::Stability::STABILITY_VINTF;
         ParcelableHolder t = ParcelableHolder(stability);
         status_t status = p.readParcelable(&t);
         FUZZ_LOG() << "ParcelableHolder status: " << status;
     },
     PARCEL_READ_WITH_STATUS(android::os::PersistableBundle, readParcelable),
-    [] (const ::android::Parcel& p, uint8_t /* data */) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to call hasFileDescriptorsInRange() with status";
         size_t offset = p.readUint32();
         size_t length = p.readUint32();
@@ -340,7 +348,7 @@
         status_t status = p.hasFileDescriptorsInRange(offset, length, &result);
         FUZZ_LOG() << " status: " << status  << " result: " << result;
     },
-    [] (const ::android::Parcel& p, uint8_t /* data */) {
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to call compareDataInRange() with status";
         size_t thisOffset = p.readUint32();
         size_t otherOffset = p.readUint32();
@@ -349,6 +357,24 @@
         status_t status = p.compareDataInRange(thisOffset, p, otherOffset, length, &result);
         FUZZ_LOG() << " status: " << status  << " result: " << result;
     },
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
+        FUZZ_LOG() << "about to call readFromParcel() with status for EmptyParcelable";
+        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;
+        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;
+        status_t status = genericDataParcelable.readFromParcel(&p);
+        FUZZ_LOG() <<" status: " << status;
+    },
 };
 // clang-format on
 #pragma clang diagnostic pop
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 5aeb5cc..af773a0 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -16,6 +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 <android/binder_parcel_utils.h>
 #include <android/binder_parcelable_utils.h>
@@ -70,7 +73,7 @@
 }
 
 #define PARCEL_READ(T, FUN)                                              \
-    [](const NdkParcelAdapter& p, uint8_t /*data*/) {                    \
+    [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {    \
         FUZZ_LOG() << "about to read " #T " using " #FUN " with status"; \
         T t{};                                                           \
         binder_status_t status = FUN(p.aParcel(), &t);                   \
@@ -80,32 +83,37 @@
 // clang-format off
 std::vector<ParcelRead<NdkParcelAdapter>> BINDER_NDK_PARCEL_READ_FUNCTIONS{
         // methods from binder_parcel.h
-        [](const NdkParcelAdapter& p, uint8_t pos) {
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& provider) {
+            // aborts on larger values
+            size_t pos = provider.ConsumeIntegralInRange<size_t>(0, INT32_MAX);
             FUZZ_LOG() << "about to set data position to " << pos;
             binder_status_t status = AParcel_setDataPosition(p.aParcel(), pos);
             FUZZ_LOG() << "set data position: " << status;
         },
-        [](const NdkParcelAdapter& p, uint8_t /*data*/) {
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
             FUZZ_LOG() << "about to read status header";
             ndk::ScopedAStatus t;
             binder_status_t status = AParcel_readStatusHeader(p.aParcel(), t.getR());
             FUZZ_LOG() << "read status header: " << status;
         },
-        [](const NdkParcelAdapter& p, uint8_t /*data*/) {
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
             FUZZ_LOG() << "about to getDataSize the parcel";
             AParcel_getDataSize(p.aParcel());
             FUZZ_LOG() << "getDataSize done";
         },
-        [](const NdkParcelAdapter& p, uint8_t data) {
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& provider) {
             FUZZ_LOG() << "about to read a ParcelableHolder";
-            ndk::AParcelableHolder ph {(data % 2 == 1) ? ndk::STABILITY_LOCAL : ndk::STABILITY_VINTF};
+            ndk::AParcelableHolder ph {provider.ConsumeBool() ? ndk::STABILITY_LOCAL : ndk::STABILITY_VINTF};
             binder_status_t status = AParcel_readParcelable(p.aParcel(), &ph);
             FUZZ_LOG() << "read the ParcelableHolder: " << status;
         },
-        [](const NdkParcelAdapter& p, uint8_t data) {
-            FUZZ_LOG() << "about to appendFrom";
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& provider) {
+            size_t offset = provider.ConsumeIntegral<size_t>();
+            size_t pos = provider.ConsumeIntegral<size_t>();
+            FUZZ_LOG() << "about to appendFrom " << pos;
+            // TODO: create random parcel
             AParcel* parcel = AParcel_create();
-            binder_status_t status = AParcel_appendFrom(p.aParcel(), parcel, 0, data);
+            binder_status_t status = AParcel_appendFrom(p.aParcel(), parcel, offset, pos);
             AParcel_delete(parcel);
             FUZZ_LOG() << "appendFrom: " << status;
         },
@@ -172,5 +180,24 @@
         PARCEL_READ(std::array<ndk::ScopedFileDescriptor COMMA 3>, ndk::AParcel_readData),
         PARCEL_READ(std::array<std::shared_ptr<ISomeInterface> COMMA 3>, ndk::AParcel_readData),
 #undef COMMA
+
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
+            FUZZ_LOG() << "about to read parcel using readFromParcel for EmptyParcelable";
+            aidl::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;
+            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;
+            binder_status_t status = genericDataParcelable.readFromParcel(p.aParcel());
+            FUZZ_LOG() << "status: " << status;
+        },
 };
 // clang-format on
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.h b/libs/binder/tests/parcel_fuzzer/binder_ndk.h
index cf24ab9..81e79b5 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.h
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.h
@@ -43,6 +43,10 @@
         return aParcel()->get()->setData(buffer, len);
     }
 
+    android::status_t appendFrom(const NdkParcelAdapter* parcel, int32_t start, int32_t len) {
+        return AParcel_appendFrom(parcel->aParcel(), aParcel(), start, len);
+    }
+
 private:
     ndk::ScopedAParcel mParcel;
 };
diff --git a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
index ee9840f..438e8ae 100644
--- a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
@@ -35,19 +35,19 @@
 #define PARCEL_READ_OPT_STATUS(T, FUN) \
     PARCEL_READ_NO_STATUS(T, FUN), PARCEL_READ_WITH_STATUS(T, FUN)
 
-#define PARCEL_READ_NO_STATUS(T, FUN) \
-    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {\
-        FUZZ_LOG() << "about to read " #T " using " #FUN " with no status";\
-        T t = p.FUN();\
-        FUZZ_LOG() << #T " value: " << t;\
+#define PARCEL_READ_NO_STATUS(T, FUN)                                            \
+    [](const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) { \
+        FUZZ_LOG() << "about to read " #T " using " #FUN " with no status";      \
+        T t = p.FUN();                                                           \
+        FUZZ_LOG() << #T " value: " << t;                                        \
     }
 
-#define PARCEL_READ_WITH_STATUS(T, FUN) \
-    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {\
-        FUZZ_LOG() << "about to read " #T " using " #FUN " with status";\
-        T t;\
-        status_t status = p.FUN(&t);\
-        FUZZ_LOG() << #T " status: " << status << " value: " << t;\
+#define PARCEL_READ_WITH_STATUS(T, FUN)                                          \
+    [](const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) { \
+        FUZZ_LOG() << "about to read " #T " using " #FUN " with status";         \
+        T t;                                                                     \
+        status_t status = p.FUN(&t);                                             \
+        FUZZ_LOG() << #T " status: " << status << " value: " << t;               \
     }
 
 // clang-format off
@@ -56,27 +56,30 @@
     PARCEL_READ_NO_STATUS(size_t, dataAvail),
     PARCEL_READ_NO_STATUS(size_t, dataPosition),
     PARCEL_READ_NO_STATUS(size_t, dataCapacity),
-    [] (const ::android::hardware::Parcel& p, uint8_t pos) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        // aborts on larger values
+        size_t pos = provider.ConsumeIntegralInRange<size_t>(0, INT32_MAX);
         FUZZ_LOG() << "about to setDataPosition: " << pos;
         p.setDataPosition(pos);
         FUZZ_LOG() << "setDataPosition done";
     },
-    [] (const ::android::hardware::Parcel& p, uint8_t length) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
         FUZZ_LOG() << "about to enforceInterface";
-        std::string interfaceName(length, 'a');
-        bool okay = p.enforceInterface(interfaceName.c_str());
+        bool okay = p.enforceInterface(provider.ConsumeRandomLengthString().c_str());
         FUZZ_LOG() << "enforceInterface status: " << okay;
     },
     PARCEL_READ_NO_STATUS(size_t, objectsCount),
-    [] (const ::android::hardware::Parcel& p, uint8_t length) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        // Read at least a bit. Unbounded allocation would OOM.
+        size_t length = provider.ConsumeIntegralInRange<size_t>(0, 1024);
         FUZZ_LOG() << "about to read";
         std::vector<uint8_t> data (length);
         status_t status = p.read(data.data(), length);
         FUZZ_LOG() << "read status: " << status << " data: " << HexString(data.data(), data.size());
     },
-    [] (const ::android::hardware::Parcel& p, uint8_t length) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        size_t length = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to read";
-        std::vector<uint8_t> data (length);
         const void* inplace = p.readInplace(length);
         FUZZ_LOG() << "read status: " << (inplace ? HexString(inplace, length) : "null");
     },
@@ -91,14 +94,14 @@
     PARCEL_READ_OPT_STATUS(float, readFloat),
     PARCEL_READ_OPT_STATUS(double, readDouble),
     PARCEL_READ_OPT_STATUS(bool, readBool),
-    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to readCString";
         const char* str = p.readCString();
         FUZZ_LOG() << "readCString " << (str ? str : "<null>");
     },
     PARCEL_READ_OPT_STATUS(::android::String16, readString16),
     PARCEL_READ_WITH_STATUS(std::unique_ptr<::android::String16>, readString16),
-    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to readString16Inplace";
         size_t outSize = 0;
         const char16_t* str = p.readString16Inplace(&outSize);
@@ -106,7 +109,8 @@
     },
     PARCEL_READ_OPT_STATUS(::android::sp<::android::hardware::IBinder>, readStrongBinder),
     PARCEL_READ_WITH_STATUS(::android::sp<::android::hardware::IBinder>, readNullableStrongBinder),
-    [] (const ::android::hardware::Parcel& p, uint8_t size) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        size_t size = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to readBuffer";
         size_t handle = 0;
         const void* data = nullptr;
@@ -116,7 +120,8 @@
         // should be null since we don't create any IPC objects
         CHECK(data == nullptr) << data;
     },
-    [] (const ::android::hardware::Parcel& p, uint8_t size) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        size_t size = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to readNullableBuffer";
         size_t handle = 0;
         const void* data = nullptr;
@@ -126,7 +131,8 @@
         // should be null since we don't create any IPC objects
         CHECK(data == nullptr) << data;
     },
-    [] (const ::android::hardware::Parcel& p, uint8_t size) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        size_t size = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to readEmbeddedBuffer";
         size_t handle = 0;
         size_t parent_buffer_handle = 0;
@@ -138,7 +144,8 @@
         // should be null since we don't create any IPC objects
         CHECK(data == nullptr) << data;
     },
-    [] (const ::android::hardware::Parcel& p, uint8_t size) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& provider) {
+        size_t size = provider.ConsumeIntegral<size_t>();
         FUZZ_LOG() << "about to readNullableEmbeddedBuffer";
         size_t handle = 0;
         size_t parent_buffer_handle = 0;
@@ -150,7 +157,7 @@
         // should be null since we don't create any IPC objects
         CHECK(data == nullptr) << data;
     },
-    [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
+    [] (const ::android::hardware::Parcel& p, FuzzedDataProvider& /*provider*/) {
         FUZZ_LOG() << "about to readNativeHandleNoDup";
         const native_handle_t* handle = nullptr;
         status_t status = p.readNativeHandleNoDup(&handle);
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
index 843b6e3..6ea9708 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
@@ -19,10 +19,14 @@
 #include <android-base/unique_fd.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
+#include <vector>
+
 namespace android {
 
 // always valid or aborts
 // get a random FD for use in fuzzing, of a few different specific types
-base::unique_fd getRandomFd(FuzzedDataProvider* provider);
+//
+// may return multiple FDs (e.g. pipe), but will always return at least one
+std::vector<base::unique_fd> getRandomFds(FuzzedDataProvider* provider);
 
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index 459fb12..27587a9 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -33,10 +33,13 @@
 /**
  * Fill parcel data, including some random binder objects and FDs
  *
+ * May insert additional FDs/binders if they own data related to the Parcel (e.g. the other
+ * end of a pipe).
+ *
  * p - the Parcel to fill
  * provider - takes ownership and completely consumes provider
  * writeHeader - optional function to write a specific header once the format of the parcel is
  *     picked (for instance, to write an interface header)
  */
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, const RandomParcelOptions& = {});
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOptions* options);
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index d5aa353..32494e3 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -44,7 +44,7 @@
 
         std::vector<uint8_t> subData = provider.ConsumeBytes<uint8_t>(
                 provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
-        fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), options);
+        fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), &options);
 
         Parcel reply;
         (void)target->transact(code, data, &reply, flags);
diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp
index f435dae..bef4ab6 100644
--- a/libs/binder/tests/parcel_fuzzer/main.cpp
+++ b/libs/binder/tests/parcel_fuzzer/main.cpp
@@ -35,17 +35,22 @@
 #include <sys/time.h>
 
 using android::fillRandomParcel;
+using android::RandomParcelOptions;
 using android::sp;
 using android::base::HexString;
 
-void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
+void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider,
+                      RandomParcelOptions* options) {
     // TODO: functionality to create random parcels for libhwbinder parcels
+    (void)options;
+
     std::vector<uint8_t> input = provider.ConsumeRemainingBytes<uint8_t>();
     p->setData(input.data(), input.size());
 }
-static void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider) {
+static void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider,
+                             RandomParcelOptions* options) {
     // fill underlying parcel using functions to fill random libbinder parcel
-    fillRandomParcel(p->parcel(), std::move(provider));
+    fillRandomParcel(p->parcel(), std::move(provider), options);
 }
 
 template <typename P, typename B>
@@ -55,9 +60,11 @@
 
     FUZZ_LOG() << "backend: " << backend;
 
+    RandomParcelOptions options;
+
     P reply;
     P data;
-    fillRandomParcel(&data, std::move(provider));
+    fillRandomParcel(&data, std::move(provider), &options);
     (void)binder->transact(code, data, &reply, flag);
 }
 
@@ -73,8 +80,10 @@
     std::vector<uint8_t> instructions = provider.ConsumeBytes<uint8_t>(
             provider.ConsumeIntegralInRange<size_t>(0, maxInstructions));
 
+    RandomParcelOptions options;
+
     P p;
-    fillRandomParcel(&p, std::move(provider));
+    fillRandomParcel(&p, std::move(provider), &options);
 
     // since we are only using a byte to index
     CHECK(reads.size() <= 255) << reads.size();
@@ -83,22 +92,39 @@
     FUZZ_LOG() << "input: " << HexString(p.data(), p.dataSize());
     FUZZ_LOG() << "instructions: " << HexString(instructions.data(), instructions.size());
 
-    for (size_t i = 0; i + 1 < instructions.size(); i += 2) {
-        uint8_t a = instructions[i];
-        uint8_t readIdx = a % reads.size();
+    FuzzedDataProvider instructionsProvider(instructions.data(), instructions.size());
+    while (instructionsProvider.remaining_bytes() > 0) {
+        uint8_t idx = instructionsProvider.ConsumeIntegralInRange<uint8_t>(0, reads.size() - 1);
 
-        uint8_t b = instructions[i + 1];
+        FUZZ_LOG() << "Instruction " << idx << " avail: " << p.dataAvail()
+                   << " pos: " << p.dataPosition() << " cap: " << p.dataCapacity();
 
-        FUZZ_LOG() << "Instruction: " << (i / 2) + 1 << "/" << instructions.size() / 2
-                   << " cmd: " << static_cast<size_t>(a) << " (" << static_cast<size_t>(readIdx)
-                   << ") arg: " << static_cast<size_t>(b) << " size: " << p.dataSize()
-                   << " avail: " << p.dataAvail() << " pos: " << p.dataPosition()
-                   << " cap: " << p.dataCapacity();
-
-        reads[readIdx](p, b);
+        reads[idx](p, instructionsProvider);
     }
 }
 
+// Append two random parcels.
+template <typename P>
+void doAppendFuzz(const char* backend, FuzzedDataProvider&& provider) {
+    int32_t start = provider.ConsumeIntegral<int32_t>();
+    int32_t len = provider.ConsumeIntegral<int32_t>();
+
+    std::vector<uint8_t> bytes = provider.ConsumeBytes<uint8_t>(
+            provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
+
+    // same options so that FDs and binders could be shared in both Parcels
+    RandomParcelOptions options;
+
+    P p0, p1;
+    fillRandomParcel(&p0, FuzzedDataProvider(bytes.data(), bytes.size()), &options);
+    fillRandomParcel(&p1, std::move(provider), &options);
+
+    FUZZ_LOG() << "backend: " << backend;
+    FUZZ_LOG() << "start: " << start << " len: " << len;
+
+    p0.appendFrom(&p1, start, len);
+}
+
 void* NothingClass_onCreate(void* args) {
     return args;
 }
@@ -148,6 +174,12 @@
                 doReadFuzz<NdkParcelAdapter>("binder_ndk", BINDER_NDK_PARCEL_READ_FUNCTIONS,
                                              std::move(provider));
             },
+            [](FuzzedDataProvider&& provider) {
+                doAppendFuzz<::android::Parcel>("binder", std::move(provider));
+            },
+            [](FuzzedDataProvider&& provider) {
+                doAppendFuzz<NdkParcelAdapter>("binder_ndk", std::move(provider));
+            },
     };
 
     provider.PickValueInArray(fuzzBackend)(std::move(provider));
diff --git a/libs/binder/tests/parcel_fuzzer/parcel_fuzzer.h b/libs/binder/tests/parcel_fuzzer/parcel_fuzzer.h
index b68a8a9..765a93e 100644
--- a/libs/binder/tests/parcel_fuzzer/parcel_fuzzer.h
+++ b/libs/binder/tests/parcel_fuzzer/parcel_fuzzer.h
@@ -15,5 +15,9 @@
  */
 #pragma once
 
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <functional>
+
 template <typename P>
-using ParcelRead = std::function<void(const P& p, uint8_t data)>;
+using ParcelRead = std::function<void(const P& p, FuzzedDataProvider& provider)>;
diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
index ab0b7e3..3fcf104 100644
--- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
@@ -23,13 +23,44 @@
 
 namespace android {
 
-base::unique_fd getRandomFd(FuzzedDataProvider* provider) {
-    int fd = provider->PickValueInArray<std::function<int()>>({
-            []() { return ashmem_create_region("binder test region", 1024); },
-            []() { return open("/dev/null", O_RDWR); },
+using base::unique_fd;
+
+std::vector<unique_fd> getRandomFds(FuzzedDataProvider* provider) {
+    std::vector<unique_fd> fds = provider->PickValueInArray<
+            std::function<std::vector<unique_fd>()>>({
+            [&]() {
+                std::vector<unique_fd> ret;
+                ret.push_back(unique_fd(
+                        ashmem_create_region("binder test region",
+                                             provider->ConsumeIntegralInRange<size_t>(0, 4096))));
+                return ret;
+            },
+            [&]() {
+                std::vector<unique_fd> ret;
+                ret.push_back(unique_fd(open("/dev/null", O_RDWR)));
+                return ret;
+            },
+            [&]() {
+                int pipefds[2];
+
+                int flags = O_CLOEXEC;
+                if (provider->ConsumeBool()) flags |= O_DIRECT;
+                if (provider->ConsumeBool()) flags |= O_NONBLOCK;
+
+                CHECK_EQ(0, pipe2(pipefds, flags));
+
+                if (provider->ConsumeBool()) std::swap(pipefds[0], pipefds[1]);
+
+                std::vector<unique_fd> ret;
+                ret.push_back(unique_fd(pipefds[0]));
+                ret.push_back(unique_fd(pipefds[1]));
+                return ret;
+            },
     })();
-    CHECK(fd >= 0);
-    return base::unique_fd(fd);
+
+    for (const auto& fd : fds) CHECK(fd.ok()) << fd.get();
+
+    return fds;
 }
 
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 0204f5e..51cb768 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -39,23 +39,24 @@
     CHECK(OK == p->write(data.data(), data.size()));
 }
 
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider,
-                      const RandomParcelOptions& options) {
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOptions* options) {
+    CHECK_NE(options, nullptr);
+
     if (provider.ConsumeBool()) {
         auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
         CHECK_EQ(OK, session->addNullDebuggingClient());
         p->markForRpc(session);
 
-        if (options.writeHeader) {
-            options.writeHeader(p, provider);
+        if (options->writeHeader) {
+            options->writeHeader(p, provider);
         }
 
         fillRandomParcelData(p, std::move(provider));
         return;
     }
 
-    if (options.writeHeader) {
-        options.writeHeader(p, provider);
+    if (options->writeHeader) {
+        options->writeHeader(p, provider);
     }
 
     while (provider.remaining_bytes() > 0) {
@@ -69,15 +70,21 @@
                 },
                 // write FD
                 [&]() {
-                    if (options.extraFds.size() > 0 && provider.ConsumeBool()) {
-                        const base::unique_fd& fd = options.extraFds.at(
+                    if (options->extraFds.size() > 0 && provider.ConsumeBool()) {
+                        const base::unique_fd& fd = options->extraFds.at(
                                 provider.ConsumeIntegralInRange<size_t>(0,
-                                                                        options.extraFds.size() -
+                                                                        options->extraFds.size() -
                                                                                 1));
                         CHECK(OK == p->writeFileDescriptor(fd.get(), false /*takeOwnership*/));
                     } else {
-                        base::unique_fd fd = getRandomFd(&provider);
-                        CHECK(OK == p->writeFileDescriptor(fd.release(), true /*takeOwnership*/));
+                        std::vector<base::unique_fd> fds = getRandomFds(&provider);
+                        CHECK(OK ==
+                              p->writeFileDescriptor(fds.begin()->release(),
+                                                     true /*takeOwnership*/));
+
+                        options->extraFds.insert(options->extraFds.end(),
+                                                 std::make_move_iterator(fds.begin() + 1),
+                                                 std::make_move_iterator(fds.end()));
                     }
                 },
                 // write binder
@@ -98,10 +105,10 @@
                                 return IInterface::asBinder(defaultServiceManager());
                             },
                             [&]() -> sp<IBinder> {
-                                if (options.extraBinders.size() > 0 && provider.ConsumeBool()) {
-                                    return options.extraBinders.at(
+                                if (options->extraBinders.size() > 0 && provider.ConsumeBool()) {
+                                    return options->extraBinders.at(
                                             provider.ConsumeIntegralInRange<
-                                                    size_t>(0, options.extraBinders.size() - 1));
+                                                    size_t>(0, options->extraBinders.size() - 1));
                                 } else {
                                     return nullptr;
                                 }
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
index 56d958c..0035e4e 100644
--- a/libs/binder/tests/schd-dbg.cpp
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -398,14 +398,13 @@
   pid_t pid = fork();
   if (pid) {
     // parent
-    return move(get<0>(pipe_pair));
+    return std::move(get<0>(pipe_pair));
   } else {
     // child
     thread_dump(is_client(num) ? "client" : "server");
-    worker_fx(num, no_process, iterations, payload_size,
-              move(get<1>(pipe_pair)));
+    worker_fx(num, no_process, iterations, payload_size, std::move(get<1>(pipe_pair)));
     // never get here
-    return move(get<0>(pipe_pair));
+    return std::move(get<0>(pipe_pair));
   }
 }
 
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
index e77c55c..910c9dc 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
@@ -49,6 +49,7 @@
     });
 
     sp<RpcSession> session = RpcSession::make();
+    session->setMaxIncomingThreads(1);
     status_t status;
     for (size_t tries = 0; tries < 5; tries++) {
         usleep(10000);
diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp
new file mode 100644
index 0000000..187add4
--- /dev/null
+++ b/libs/binder/trusty/OS.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 <openssl/rand.h>
+
+#include "../OS.h"
+
+using android::base::Result;
+
+namespace android {
+
+Result<void> setNonBlocking(android::base::borrowed_fd fd) {
+    // Trusty IPC syscalls are all non-blocking by default.
+    return {};
+}
+
+status_t getRandomBytes(uint8_t* data, size_t size) {
+    int res = RAND_bytes(data, size);
+    return res == 1 ? OK : UNKNOWN_ERROR;
+}
+
+} // namespace android
diff --git a/libs/binder/trusty/README.md b/libs/binder/trusty/README.md
new file mode 100644
index 0000000..1a273aa
--- /dev/null
+++ b/libs/binder/trusty/README.md
@@ -0,0 +1,39 @@
+# Binder for Trusty
+
+This is the Trusty port of the libbinder library.
+To build it, take the following steps:
+
+* Check out copies of the Trusty and AOSP repositories.
+* Apply the patches from the `trusty_binder` topic on both repositories.
+* Build Trusty normally using `build.py`.
+* Run the sample AIDL test for Trusty:
+  ```shell
+  $ ./build-root/.../run --headless --boot-test com.android.trusty.aidl.test
+  ```
+
+To run the Android-Trusty IPC test, do the following:
+
+* Build AOSP for the `qemu_trusty_arm64-userdebug` target:
+  ```shell
+  $ lunch qemu_trusty_arm64-userdebug
+  $ m
+  ```
+* In the Trusty directory, run the emulator with the newly built Android:
+  ```shell
+  $ ./build-root/.../run --android /path/to/aosp
+  ```
+* Using either `adb` or the shell inside the emulator itself, run the Trusty
+  Binder test as root:
+  ```shell
+  # /data/nativetest64/vendor/trusty_binder_test/trusty_binder_test
+  ```
+
+## Running the AIDL compiler
+For now, you will need to run the AIDL compiler manually to generate the C++
+source code for Trusty clients and services. The general syntax is:
+```shell
+$ aidl --lang=cpp -o <output directory> -h <output header directory> <AIDL files...>
+```
+
+The compiler will emit some `.cpp` files in the output directory and their
+corresponding `.h` files in the header directory.
diff --git a/libs/binder/trusty/RpcServerTrusty.cpp b/libs/binder/trusty/RpcServerTrusty.cpp
new file mode 100644
index 0000000..e8b91e7
--- /dev/null
+++ b/libs/binder/trusty/RpcServerTrusty.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "RpcServerTrusty"
+
+#include <binder/Parcel.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcServerTrusty.h>
+#include <binder/RpcThreads.h>
+#include <binder/RpcTransportTipcTrusty.h>
+#include <log/log.h>
+
+#include "../FdTrigger.h"
+#include "../RpcState.h"
+#include "TrustyStatus.h"
+
+using android::base::unexpected;
+
+namespace android {
+
+android::base::expected<sp<RpcServerTrusty>, int> RpcServerTrusty::make(
+        tipc_hset* handleSet, std::string&& portName, std::shared_ptr<const PortAcl>&& portAcl,
+        size_t msgMaxSize, std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+    // Default is without TLS.
+    if (rpcTransportCtxFactory == nullptr)
+        rpcTransportCtxFactory = RpcTransportCtxFactoryTipcTrusty::make();
+    auto ctx = rpcTransportCtxFactory->newServerCtx();
+    if (ctx == nullptr) {
+        return unexpected(ERR_NO_MEMORY);
+    }
+
+    auto srv = sp<RpcServerTrusty>::make(std::move(ctx), std::move(portName), std::move(portAcl),
+                                         msgMaxSize);
+    if (srv == nullptr) {
+        return unexpected(ERR_NO_MEMORY);
+    }
+
+    int rc = tipc_add_service(handleSet, &srv->mTipcPort, 1, 0, &kTipcOps);
+    if (rc != NO_ERROR) {
+        return unexpected(rc);
+    }
+    return srv;
+}
+
+RpcServerTrusty::RpcServerTrusty(std::unique_ptr<RpcTransportCtx> ctx, std::string&& portName,
+                                 std::shared_ptr<const PortAcl>&& portAcl, size_t msgMaxSize)
+      : mRpcServer(sp<RpcServer>::make(std::move(ctx))),
+        mPortName(std::move(portName)),
+        mPortAcl(std::move(portAcl)) {
+    mTipcPort.name = mPortName.c_str();
+    mTipcPort.msg_max_size = msgMaxSize;
+    mTipcPort.msg_queue_len = 6; // Three each way
+    mTipcPort.priv = this;
+
+    if (mPortAcl) {
+        // Initialize the array of pointers to uuids.
+        // The pointers in mUuidPtrs should stay valid across moves of
+        // RpcServerTrusty (the addresses of a std::vector's elements
+        // shouldn't change when the vector is moved), but would be invalidated
+        // by a copy which is why we disable the copy constructor and assignment
+        // operator for RpcServerTrusty.
+        auto numUuids = mPortAcl->uuids.size();
+        mUuidPtrs.resize(numUuids);
+        for (size_t i = 0; i < numUuids; i++) {
+            mUuidPtrs[i] = &mPortAcl->uuids[i];
+        }
+
+        // Copy the contents of portAcl into the tipc_port_acl structure that we
+        // pass to tipc_add_service
+        mTipcPortAcl.flags = mPortAcl->flags;
+        mTipcPortAcl.uuid_num = numUuids;
+        mTipcPortAcl.uuids = mUuidPtrs.data();
+        mTipcPortAcl.extra_data = mPortAcl->extraData;
+
+        mTipcPort.acl = &mTipcPortAcl;
+    } else {
+        mTipcPort.acl = nullptr;
+    }
+}
+
+int RpcServerTrusty::handleConnect(const tipc_port* port, handle_t chan, const uuid* peer,
+                                   void** ctx_p) {
+    auto* server = reinterpret_cast<RpcServerTrusty*>(const_cast<void*>(port->priv));
+    server->mRpcServer->mShutdownTrigger = FdTrigger::make();
+    server->mRpcServer->mConnectingThreads[rpc_this_thread::get_id()] = RpcMaybeThread();
+
+    int rc = NO_ERROR;
+    auto joinFn = [&](sp<RpcSession>&& session, RpcSession::PreJoinSetupResult&& result) {
+        if (result.status != OK) {
+            rc = statusToTrusty(result.status);
+            return;
+        }
+
+        /* Save the session for easy access */
+        *ctx_p = session.get();
+    };
+
+    base::unique_fd clientFd(chan);
+    std::array<uint8_t, RpcServer::kRpcAddressSize> addr;
+    constexpr size_t addrLen = sizeof(*peer);
+    memcpy(addr.data(), peer, addrLen);
+    RpcServer::establishConnection(sp(server->mRpcServer), std::move(clientFd), addr, addrLen,
+                                   joinFn);
+
+    return rc;
+}
+
+int RpcServerTrusty::handleMessage(const tipc_port* port, handle_t chan, void* ctx) {
+    auto* session = reinterpret_cast<RpcSession*>(ctx);
+    status_t status = session->state()->drainCommands(session->mConnections.mIncoming[0], session,
+                                                      RpcState::CommandType::ANY);
+    if (status != OK) {
+        LOG_RPC_DETAIL("Binder connection thread closing w/ status %s",
+                       statusToString(status).c_str());
+    }
+
+    return NO_ERROR;
+}
+
+void RpcServerTrusty::handleDisconnect(const tipc_port* port, handle_t chan, void* ctx) {}
+
+void RpcServerTrusty::handleChannelCleanup(void* ctx) {
+    auto* session = reinterpret_cast<RpcSession*>(ctx);
+    auto& connection = session->mConnections.mIncoming.at(0);
+    LOG_ALWAYS_FATAL_IF(!session->removeIncomingConnection(connection),
+                        "bad state: connection object guaranteed to be in list");
+}
+
+} // namespace android
diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
new file mode 100644
index 0000000..dc27eb9
--- /dev/null
+++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "RpcTransportTipcTrusty"
+
+#include <trusty_ipc.h>
+
+#include <binder/RpcSession.h>
+#include <binder/RpcTransportTipcTrusty.h>
+#include <log/log.h>
+
+#include "../FdTrigger.h"
+#include "../RpcState.h"
+#include "TrustyStatus.h"
+
+namespace android {
+
+namespace {
+
+// RpcTransport for Trusty.
+class RpcTransportTipcTrusty : public RpcTransport {
+public:
+    explicit RpcTransportTipcTrusty(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
+    ~RpcTransportTipcTrusty() { releaseMessage(); }
+
+    status_t pollRead() override {
+        auto status = ensureMessage(false);
+        if (status != OK) {
+            return status;
+        }
+        return mHaveMessage ? OK : WOULD_BLOCK;
+    }
+
+    status_t interruptableWriteFully(
+            FdTrigger* fdTrigger, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
+            override {
+        if (niovs < 0) {
+            return BAD_VALUE;
+        }
+
+        size_t size = 0;
+        for (int i = 0; i < niovs; i++) {
+            size += iovs[i].iov_len;
+        }
+
+        ipc_msg_t msg{
+                .num_iov = static_cast<uint32_t>(niovs),
+                .iov = iovs,
+                .num_handles = 0, // TODO: add ancillaryFds
+                .handles = nullptr,
+        };
+        ssize_t rc = send_msg(mSocket.get(), &msg);
+        if (rc == ERR_NOT_ENOUGH_BUFFER) {
+            // Peer is blocked, wait until it unblocks.
+            // TODO: when tipc supports a send-unblocked handler,
+            // save the message here in a queue and retry it asynchronously
+            // when the handler gets called by the library
+            uevent uevt;
+            do {
+                rc = ::wait(mSocket.get(), &uevt, INFINITE_TIME);
+                if (rc < 0) {
+                    return statusFromTrusty(rc);
+                }
+                if (uevt.event & IPC_HANDLE_POLL_HUP) {
+                    return DEAD_OBJECT;
+                }
+            } while (!(uevt.event & IPC_HANDLE_POLL_SEND_UNBLOCKED));
+
+            // Retry the send, it should go through this time because
+            // sending is now unblocked
+            rc = send_msg(mSocket.get(), &msg);
+        }
+        if (rc < 0) {
+            return statusFromTrusty(rc);
+        }
+        LOG_ALWAYS_FATAL_IF(static_cast<size_t>(rc) != size,
+                            "Sent the wrong number of bytes %zd!=%zu", rc, size);
+
+        return OK;
+    }
+
+    status_t interruptableReadFully(
+            FdTrigger* fdTrigger, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override {
+        if (niovs < 0) {
+            return BAD_VALUE;
+        }
+
+        // If iovs has one or more empty vectors at the end and
+        // we somehow advance past all the preceding vectors and
+        // pass some or all of the empty ones to sendmsg/recvmsg,
+        // the call will return processSize == 0. In that case
+        // we should be returning OK but instead return DEAD_OBJECT.
+        // To avoid this problem, we make sure here that the last
+        // vector at iovs[niovs - 1] has a non-zero length.
+        while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
+            niovs--;
+        }
+        if (niovs == 0) {
+            // The vectors are all empty, so we have nothing to read.
+            return OK;
+        }
+
+        while (true) {
+            auto status = ensureMessage(true);
+            if (status != OK) {
+                return status;
+            }
+
+            ipc_msg_t msg{
+                    .num_iov = static_cast<uint32_t>(niovs),
+                    .iov = iovs,
+                    .num_handles = 0, // TODO: support ancillaryFds
+                    .handles = nullptr,
+            };
+            ssize_t rc = read_msg(mSocket.get(), mMessageInfo.id, mMessageOffset, &msg);
+            if (rc < 0) {
+                return statusFromTrusty(rc);
+            }
+
+            size_t processSize = static_cast<size_t>(rc);
+            mMessageOffset += processSize;
+            LOG_ALWAYS_FATAL_IF(mMessageOffset > mMessageInfo.len,
+                                "Message offset exceeds length %zu/%zu", mMessageOffset,
+                                mMessageInfo.len);
+
+            // Release the message if all of it has been read
+            if (mMessageOffset == mMessageInfo.len) {
+                releaseMessage();
+            }
+
+            while (processSize > 0 && niovs > 0) {
+                auto& iov = iovs[0];
+                if (processSize < iov.iov_len) {
+                    // Advance the base of the current iovec
+                    iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
+                    iov.iov_len -= processSize;
+                    break;
+                }
+
+                // The current iovec was fully written
+                processSize -= iov.iov_len;
+                iovs++;
+                niovs--;
+            }
+            if (niovs == 0) {
+                LOG_ALWAYS_FATAL_IF(processSize > 0,
+                                    "Reached the end of iovecs "
+                                    "with %zd bytes remaining",
+                                    processSize);
+                return OK;
+            }
+        }
+    }
+
+private:
+    status_t ensureMessage(bool wait) {
+        int rc;
+        if (mHaveMessage) {
+            LOG_ALWAYS_FATAL_IF(mMessageOffset >= mMessageInfo.len, "No data left in message");
+            return OK;
+        }
+
+        /* TODO: interruptible wait, maybe with a timeout??? */
+        uevent uevt;
+        rc = ::wait(mSocket.get(), &uevt, wait ? INFINITE_TIME : 0);
+        if (rc < 0) {
+            if (rc == ERR_TIMED_OUT && !wait) {
+                // If we timed out with wait==false, then there's no message
+                return OK;
+            }
+            return statusFromTrusty(rc);
+        }
+        if (!(uevt.event & IPC_HANDLE_POLL_MSG)) {
+            /* No message, terminate here and leave mHaveMessage false */
+            return OK;
+        }
+
+        rc = get_msg(mSocket.get(), &mMessageInfo);
+        if (rc < 0) {
+            return statusFromTrusty(rc);
+        }
+
+        mHaveMessage = true;
+        mMessageOffset = 0;
+        return OK;
+    }
+
+    void releaseMessage() {
+        if (mHaveMessage) {
+            put_msg(mSocket.get(), mMessageInfo.id);
+            mHaveMessage = false;
+        }
+    }
+
+    base::unique_fd mSocket;
+
+    bool mHaveMessage = false;
+    ipc_msg_info mMessageInfo;
+    size_t mMessageOffset;
+};
+
+// RpcTransportCtx for Trusty.
+class RpcTransportCtxTipcTrusty : public RpcTransportCtx {
+public:
+    std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd,
+                                               FdTrigger*) const override {
+        return std::make_unique<RpcTransportTipcTrusty>(std::move(fd));
+    }
+    std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
+};
+
+} // namespace
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newServerCtx() const {
+    return std::make_unique<RpcTransportCtxTipcTrusty>();
+}
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newClientCtx() const {
+    return std::make_unique<RpcTransportCtxTipcTrusty>();
+}
+
+const char* RpcTransportCtxFactoryTipcTrusty::toCString() const {
+    return "trusty";
+}
+
+std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTipcTrusty::make() {
+    return std::unique_ptr<RpcTransportCtxFactoryTipcTrusty>(
+            new RpcTransportCtxFactoryTipcTrusty());
+}
+
+} // namespace android
diff --git a/libs/binder/trusty/TrustyStatus.cpp b/libs/binder/trusty/TrustyStatus.cpp
new file mode 100644
index 0000000..b1caf61
--- /dev/null
+++ b/libs/binder/trusty/TrustyStatus.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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 "TrustyStatus.h"
+#include "../RpcState.h"
+
+namespace android {
+
+status_t statusFromTrusty(int rc) {
+    LOG_RPC_DETAIL("Trusty error: %d", rc);
+    switch (rc) {
+        case NO_ERROR:
+            return OK;
+        case ERR_NOT_FOUND:
+            return NAME_NOT_FOUND;
+        case ERR_NOT_READY:
+            // We get this error if we try to perform an IPC operation when the
+            // channel is not ready
+            return INVALID_OPERATION;
+        case ERR_NO_MSG:
+            return WOULD_BLOCK;
+        case ERR_NO_MEMORY:
+            return NO_MEMORY;
+        case ERR_INVALID_ARGS:
+            return BAD_VALUE;
+        case ERR_NOT_ENOUGH_BUFFER:
+            return WOULD_BLOCK;
+        case ERR_TIMED_OUT:
+            return TIMED_OUT;
+        case ERR_ALREADY_EXISTS:
+            return ALREADY_EXISTS;
+        case ERR_CHANNEL_CLOSED:
+            return DEAD_OBJECT;
+        case ERR_NOT_ALLOWED:
+            return INVALID_OPERATION;
+        case ERR_NOT_SUPPORTED:
+            return INVALID_OPERATION;
+        case ERR_TOO_BIG:
+            return BAD_INDEX;
+        case ERR_CMD_UNKNOWN:
+            return UNKNOWN_TRANSACTION;
+        case ERR_BAD_STATE:
+            return INVALID_OPERATION;
+        case ERR_BAD_LEN:
+            return NOT_ENOUGH_DATA;
+        case ERR_BAD_HANDLE:
+            return BAD_VALUE;
+        case ERR_ACCESS_DENIED:
+            return PERMISSION_DENIED;
+        default:
+            return UNKNOWN_ERROR;
+    }
+}
+
+int statusToTrusty(status_t status) {
+    switch (status) {
+        case OK:
+            return NO_ERROR;
+        case NO_MEMORY:
+            return ERR_NO_MEMORY;
+        case INVALID_OPERATION:
+        case BAD_VALUE:
+        case BAD_TYPE:
+            return ERR_NOT_VALID;
+        case NAME_NOT_FOUND:
+            return ERR_NOT_FOUND;
+        case PERMISSION_DENIED:
+            return ERR_ACCESS_DENIED;
+        case NO_INIT:
+            return ERR_NOT_CONFIGURED;
+        case ALREADY_EXISTS:
+            return ERR_ALREADY_EXISTS;
+        case DEAD_OBJECT:
+            return ERR_CHANNEL_CLOSED;
+        case BAD_INDEX:
+            return ERR_TOO_BIG;
+        case NOT_ENOUGH_DATA:
+            return ERR_BAD_LEN;
+        case WOULD_BLOCK:
+            return ERR_NO_MSG;
+        case TIMED_OUT:
+            return ERR_TIMED_OUT;
+        case UNKNOWN_TRANSACTION:
+            return ERR_CMD_UNKNOWN;
+        case FDS_NOT_ALLOWED:
+            return ERR_NOT_SUPPORTED;
+        case UNEXPECTED_NULL:
+            return ERR_NOT_VALID;
+        default:
+            return ERR_GENERIC;
+    }
+}
+
+} // namespace android
diff --git a/libs/binder/trusty/TrustyStatus.h b/libs/binder/trusty/TrustyStatus.h
new file mode 100644
index 0000000..fcb43f8
--- /dev/null
+++ b/libs/binder/trusty/TrustyStatus.h
@@ -0,0 +1,26 @@
+/*
+ * 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 <uapi/err.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+status_t statusFromTrusty(int rc);
+int statusToTrusty(status_t status);
+
+} // namespace android
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
new file mode 100644
index 0000000..e8fc9f9
--- /dev/null
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -0,0 +1,100 @@
+/*
+ * 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 <android-base/expected.h>
+#include <android-base/macros.h>
+#include <android-base/unique_fd.h>
+#include <binder/IBinder.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
+#include <binder/RpcTransport.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+#include <map>
+#include <vector>
+
+#include <lib/tipc/tipc_srv.h>
+
+namespace android {
+
+/**
+ * This is the Trusty-specific RPC server code.
+ */
+class RpcServerTrusty final : public virtual RefBase {
+public:
+    // C++ equivalent to tipc_port_acl that uses safe data structures instead of
+    // raw pointers, except for |extraData| which doesn't have a good
+    // equivalent.
+    struct PortAcl {
+        uint32_t flags;
+        std::vector<const uuid> uuids;
+        const void* extraData;
+    };
+
+    /**
+     * Creates an RPC server listening on the given port and adds it to the
+     * Trusty handle set at |handleSet|.
+     *
+     * The caller is responsible for calling tipc_run_event_loop() to start
+     * the TIPC event loop after creating one or more services here.
+     */
+    static android::base::expected<sp<RpcServerTrusty>, int> make(
+            tipc_hset* handleSet, std::string&& portName, std::shared_ptr<const PortAcl>&& portAcl,
+            size_t msgMaxSize,
+            std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
+
+    void setProtocolVersion(uint32_t version) { mRpcServer->setProtocolVersion(version); }
+    void setRootObject(const sp<IBinder>& binder) { mRpcServer->setRootObject(binder); }
+    void setRootObjectWeak(const wp<IBinder>& binder) { mRpcServer->setRootObjectWeak(binder); }
+    void setPerSessionRootObject(std::function<sp<IBinder>(const void*, size_t)>&& object) {
+        mRpcServer->setPerSessionRootObject(std::move(object));
+    }
+    sp<IBinder> getRootObject() { return mRpcServer->getRootObject(); }
+
+private:
+    // Both this class and RpcServer have multiple non-copyable fields,
+    // including mPortAcl below which can't be copied because mUuidPtrs
+    // holds pointers into it
+    DISALLOW_COPY_AND_ASSIGN(RpcServerTrusty);
+
+    friend sp<RpcServerTrusty>;
+    explicit RpcServerTrusty(std::unique_ptr<RpcTransportCtx> ctx, std::string&& portName,
+                             std::shared_ptr<const PortAcl>&& portAcl, size_t msgMaxSize);
+
+    static int handleConnect(const tipc_port* port, handle_t chan, const uuid* peer, void** ctx_p);
+    static int handleMessage(const tipc_port* port, handle_t chan, void* ctx);
+    static void handleDisconnect(const tipc_port* port, handle_t chan, void* ctx);
+    static void handleChannelCleanup(void* ctx);
+
+    static constexpr tipc_srv_ops kTipcOps = {
+            .on_connect = &handleConnect,
+            .on_message = &handleMessage,
+            .on_disconnect = &handleDisconnect,
+            .on_channel_cleanup = &handleChannelCleanup,
+    };
+
+    sp<RpcServer> mRpcServer;
+    std::string mPortName;
+    std::shared_ptr<const PortAcl> mPortAcl;
+    std::vector<const uuid*> mUuidPtrs;
+    tipc_port_acl mTipcPortAcl;
+    tipc_port mTipcPort;
+};
+
+} // namespace android
diff --git a/libs/binder/trusty/include/binder/RpcTransportTipcTrusty.h b/libs/binder/trusty/include/binder/RpcTransportTipcTrusty.h
new file mode 100644
index 0000000..8eae8c2
--- /dev/null
+++ b/libs/binder/trusty/include/binder/RpcTransportTipcTrusty.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+// Wraps the transport layer of RPC. Implementation uses plain sockets.
+// Note: don't use directly. You probably want newServerRpcTransportCtx / newClientRpcTransportCtx.
+
+#pragma once
+
+#include <memory>
+
+#include <binder/RpcTransport.h>
+
+namespace android {
+
+// RpcTransportCtxFactory with TLS disabled.
+class RpcTransportCtxFactoryTipcTrusty : public RpcTransportCtxFactory {
+public:
+    static std::unique_ptr<RpcTransportCtxFactory> make();
+
+    std::unique_ptr<RpcTransportCtx> newServerCtx() const override;
+    std::unique_ptr<RpcTransportCtx> newClientCtx() const override;
+    const char* toCString() const override;
+
+private:
+    RpcTransportCtxFactoryTipcTrusty() = default;
+};
+
+} // namespace android
diff --git a/libs/binder/trusty/include/log/log.h b/libs/binder/trusty/include/log/log.h
new file mode 100644
index 0000000..bf877a3
--- /dev/null
+++ b/libs/binder/trusty/include/log/log.h
@@ -0,0 +1,122 @@
+/*
+ * 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
+
+#define BINDER_LOG_LEVEL_NONE 0
+#define BINDER_LOG_LEVEL_NORMAL 1
+#define BINDER_LOG_LEVEL_VERBOSE 2
+
+#ifndef BINDER_LOG_LEVEL
+#define BINDER_LOG_LEVEL BINDER_LOG_LEVEL_NORMAL
+#endif // BINDER_LOG_LEVEL
+
+#ifndef TLOG_TAG
+#ifdef LOG_TAG
+#define TLOG_TAG "libbinder-" LOG_TAG
+#else // LOG_TAG
+#define TLOG_TAG "libbinder"
+#endif // LOG_TAG
+#endif // TLOG_TAG
+
+#include <stdlib.h>
+#include <trusty_log.h>
+
+static inline void __ignore_va_args__(...) {}
+
+#if BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_NORMAL
+#define ALOGD(fmt, ...) TLOGD(fmt "\n", ##__VA_ARGS__)
+#define ALOGI(fmt, ...) TLOGI(fmt "\n", ##__VA_ARGS__)
+#define ALOGW(fmt, ...) TLOGW(fmt "\n", ##__VA_ARGS__)
+#define ALOGE(fmt, ...) TLOGE(fmt "\n", ##__VA_ARGS__)
+#else // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_NORMAL
+#define ALOGD(fmt, ...)                  \
+    while (0) {                          \
+        __ignore_va_args__(__VA_ARGS__); \
+    }
+#define ALOGI(fmt, ...)                  \
+    while (0) {                          \
+        __ignore_va_args__(__VA_ARGS__); \
+    }
+#define ALOGW(fmt, ...)                  \
+    while (0) {                          \
+        __ignore_va_args__(__VA_ARGS__); \
+    }
+#define ALOGE(fmt, ...)                  \
+    while (0) {                          \
+        __ignore_va_args__(__VA_ARGS__); \
+    }
+#endif // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_NORMAL
+
+#if BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_VERBOSE
+#define IF_ALOGV() if (TLOG_LVL >= TLOG_LVL_INFO)
+#define ALOGV(fmt, ...) TLOGI(fmt "\n", ##__VA_ARGS__)
+#else // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_VERBOSE
+#define IF_ALOGV() if (false)
+#define ALOGV(fmt, ...)                  \
+    while (0) {                          \
+        __ignore_va_args__(__VA_ARGS__); \
+    }
+#endif // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_VERBOSE
+
+#define ALOGI_IF(cond, ...)                \
+    do {                                   \
+        if (cond) {                        \
+            ALOGI(#cond ": " __VA_ARGS__); \
+        }                                  \
+    } while (0)
+#define ALOGE_IF(cond, ...)                \
+    do {                                   \
+        if (cond) {                        \
+            ALOGE(#cond ": " __VA_ARGS__); \
+        }                                  \
+    } while (0)
+#define ALOGW_IF(cond, ...)                \
+    do {                                   \
+        if (cond) {                        \
+            ALOGW(#cond ": " __VA_ARGS__); \
+        }                                  \
+    } while (0)
+
+#define LOG_ALWAYS_FATAL(fmt, ...)                                \
+    do {                                                          \
+        TLOGE("libbinder fatal error: " fmt "\n", ##__VA_ARGS__); \
+        abort();                                                  \
+    } while (0)
+#define LOG_ALWAYS_FATAL_IF(cond, ...)                \
+    do {                                              \
+        if (cond) {                                   \
+            LOG_ALWAYS_FATAL(#cond ": " __VA_ARGS__); \
+        }                                             \
+    } while (0)
+#define LOG_FATAL(fmt, ...)                                       \
+    do {                                                          \
+        TLOGE("libbinder fatal error: " fmt "\n", ##__VA_ARGS__); \
+        abort();                                                  \
+    } while (0)
+#define LOG_FATAL_IF(cond, ...)                \
+    do {                                       \
+        if (cond) {                            \
+            LOG_FATAL(#cond ": " __VA_ARGS__); \
+        }                                      \
+    } while (0)
+
+#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ##__VA_ARGS__)
+
+#define android_errorWriteLog(tag, subTag)                               \
+    do {                                                                 \
+        TLOGE("android_errorWriteLog: tag:%x subTag:%s\n", tag, subTag); \
+    } while (0)
diff --git a/libs/binder/trusty/logging.cpp b/libs/binder/trusty/logging.cpp
new file mode 100644
index 0000000..fd54744
--- /dev/null
+++ b/libs/binder/trusty/logging.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#define TLOG_TAG "libbinder"
+
+#include "android-base/logging.h"
+
+#include <trusty_log.h>
+#include <iostream>
+#include <string>
+
+#include <android-base/macros.h>
+#include <android-base/strings.h>
+
+namespace android {
+namespace base {
+
+static const char* GetFileBasename(const char* file) {
+    const char* last_slash = strrchr(file, '/');
+    if (last_slash != nullptr) {
+        return last_slash + 1;
+    }
+    return file;
+}
+
+// This splits the message up line by line, by calling log_function with a pointer to the start of
+// each line and the size up to the newline character.  It sends size = -1 for the final line.
+template <typename F, typename... Args>
+static void SplitByLines(const char* msg, const F& log_function, Args&&... args) {
+    const char* newline;
+    while ((newline = strchr(msg, '\n')) != nullptr) {
+        log_function(msg, newline - msg, args...);
+        msg = newline + 1;
+    }
+
+    log_function(msg, -1, args...);
+}
+
+void DefaultAborter(const char* abort_message) {
+    TLOGC("aborting: %s\n", abort_message);
+    abort();
+}
+
+static void TrustyLogLine(const char* msg, int length, android::base::LogSeverity severity,
+                          const char* tag) {
+    switch (severity) {
+        case VERBOSE:
+        case DEBUG:
+            TLOGD("%s: %s\n", tag, msg);
+            break;
+        case INFO:
+            TLOGI("%s: %s\n", tag, msg);
+            break;
+        case WARNING:
+            TLOGW("%s: %s\n", tag, msg);
+            break;
+        case ERROR:
+            TLOGE("%s: %s\n", tag, msg);
+            break;
+        case FATAL_WITHOUT_ABORT:
+        case FATAL:
+            TLOGC("%s: %s\n", tag, msg);
+            break;
+    }
+}
+
+void TrustyLogger(android::base::LogId, android::base::LogSeverity severity, const char* tag,
+                  const char*, unsigned int, const char* full_message) {
+    SplitByLines(full_message, TrustyLogLine, severity, tag);
+}
+
+// This indirection greatly reduces the stack impact of having lots of
+// checks/logging in a function.
+class LogMessageData {
+public:
+    LogMessageData(const char* file, unsigned int line, LogSeverity severity, const char* tag,
+                   int error)
+          : file_(GetFileBasename(file)),
+            line_number_(line),
+            severity_(severity),
+            tag_(tag),
+            error_(error) {}
+
+    const char* GetFile() const { return file_; }
+
+    unsigned int GetLineNumber() const { return line_number_; }
+
+    LogSeverity GetSeverity() const { return severity_; }
+
+    const char* GetTag() const { return tag_; }
+
+    int GetError() const { return error_; }
+
+    std::ostream& GetBuffer() { return buffer_; }
+
+    std::string ToString() const { return buffer_.str(); }
+
+private:
+    std::ostringstream buffer_;
+    const char* const file_;
+    const unsigned int line_number_;
+    const LogSeverity severity_;
+    const char* const tag_;
+    const int error_;
+
+    DISALLOW_COPY_AND_ASSIGN(LogMessageData);
+};
+
+LogMessage::LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity,
+                       const char* tag, int error)
+      : LogMessage(file, line, severity, tag, error) {}
+
+LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag,
+                       int error)
+      : data_(new LogMessageData(file, line, severity, tag, error)) {}
+
+LogMessage::~LogMessage() {
+    // Check severity again. This is duplicate work wrt/ LOG macros, but not LOG_STREAM.
+    if (!WOULD_LOG(data_->GetSeverity())) {
+        return;
+    }
+
+    // Finish constructing the message.
+    if (data_->GetError() != -1) {
+        data_->GetBuffer() << ": " << strerror(data_->GetError());
+    }
+    std::string msg(data_->ToString());
+
+    LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), data_->GetTag(),
+            msg.c_str());
+
+    // Abort if necessary.
+    if (data_->GetSeverity() == FATAL) {
+        DefaultAborter(msg.c_str());
+    }
+}
+
+std::ostream& LogMessage::stream() {
+    return data_->GetBuffer();
+}
+
+void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag,
+                         const char* message) {
+    TrustyLogger(DEFAULT, severity, tag ?: "<unknown>", file, line, message);
+}
+
+bool ShouldLog(LogSeverity severity, const char* tag) {
+    // This is controlled by Trusty's log level.
+    return true;
+}
+
+} // namespace base
+} // namespace android
diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk
new file mode 100644
index 0000000..83475f5
--- /dev/null
+++ b/libs/binder/trusty/rules.mk
@@ -0,0 +1,87 @@
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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)/OS.cpp \
+	$(LOCAL_DIR)/RpcServerTrusty.cpp \
+	$(LOCAL_DIR)/RpcTransportTipcTrusty.cpp \
+	$(LOCAL_DIR)/TrustyStatus.cpp \
+	$(LOCAL_DIR)/socket.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)/RpcServer.cpp \
+	$(LIBBINDER_DIR)/RpcSession.cpp \
+	$(LIBBINDER_DIR)/RpcState.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_EXPORT_INCLUDES += \
+	$(LOCAL_DIR)/include \
+	$(LIBBINDER_DIR)/include \
+	$(LIBBASE_DIR)/include \
+	$(LIBCUTILS_DIR)/include \
+	$(LIBUTILS_DIR)/include \
+	$(FMTLIB_DIR)/include \
+
+# The android/binder_to_string.h header is shared between libbinder and
+# libbinder_ndk and included by auto-generated AIDL C++ files
+MODULE_EXPORT_INCLUDES += \
+	$(LIBBINDER_DIR)/ndk/include_cpp \
+
+MODULE_EXPORT_COMPILEFLAGS += \
+	-DBINDER_NO_KERNEL_IPC \
+	-DBINDER_RPC_SINGLE_THREADED \
+	-D__ANDROID_VNDK__ \
+
+MODULE_LIBRARY_DEPS += \
+	trusty/user/base/lib/libstdc++-trusty \
+	trusty/user/base/lib/tipc \
+	external/boringssl \
+
+include make/library.mk
diff --git a/libs/binder/trusty/socket.cpp b/libs/binder/trusty/socket.cpp
new file mode 100644
index 0000000..02df8af
--- /dev/null
+++ b/libs/binder/trusty/socket.cpp
@@ -0,0 +1,29 @@
+/*
+ * 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 <log/log.h>
+
+// On some versions of clang, RpcServer.cpp refuses to link without accept4
+__attribute__((weak)) extern "C" int accept4(int, void*, void*, int) {
+    LOG_ALWAYS_FATAL("accept4 called on Trusty");
+    return 0;
+}
+
+// Placeholder for poll used by FdTrigger
+__attribute__((weak)) extern "C" int poll(void*, long, int) {
+    LOG_ALWAYS_FATAL("poll called on Trusty");
+    return 0;
+}
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 7e9bb7d..706704a 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -131,24 +131,24 @@
     }
 
     gTisTotalMapFd =
-            unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_total_time_in_state_map")};
+            unique_fd{bpf_obj_get(BPF_FS_PATH "map_timeInState_total_time_in_state_map")};
     if (gTisTotalMapFd < 0) return false;
 
-    gTisMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")};
+    gTisMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_time_in_state_map")};
     if (gTisMapFd < 0) return false;
 
     gConcurrentMapFd =
-            unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+            unique_fd{bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_concurrent_times_map")};
     if (gConcurrentMapFd < 0) return false;
 
     gUidLastUpdateMapFd =
-            unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_last_update_map")};
+            unique_fd{bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_last_update_map")};
     if (gUidLastUpdateMapFd < 0) return false;
 
-    gPidTisMapFd = unique_fd{mapRetrieveRO(BPF_FS_PATH "map_time_in_state_pid_time_in_state_map")};
+    gPidTisMapFd = unique_fd{mapRetrieveRO(BPF_FS_PATH "map_timeInState_pid_time_in_state_map")};
     if (gPidTisMapFd < 0) return false;
 
-    unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_map"));
+    unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_pid_tracked_map"));
     if (trackedPidMapFd < 0) return false;
 
     gInitialized = true;
@@ -156,7 +156,7 @@
 }
 
 static int retrieveProgramFd(const std::string &eventType, const std::string &eventName) {
-    std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s",
+    std::string path = StringPrintf(BPF_FS_PATH "prog_timeInState_tracepoint_%s_%s",
                                     eventType.c_str(), eventName.c_str());
     return retrieveProgram(path.c_str());
 }
@@ -200,7 +200,7 @@
     if (!initGlobals()) return false;
     if (gTracking) return true;
 
-    unique_fd cpuPolicyFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
+    unique_fd cpuPolicyFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_cpu_policy_map"));
     if (cpuPolicyFd < 0) return false;
 
     for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) {
@@ -209,7 +209,7 @@
         }
     }
 
-    unique_fd freqToIdxFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
+    unique_fd freqToIdxFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_freq_to_idx_map"));
     if (freqToIdxFd < 0) return false;
     freq_idx_key_t key;
     for (uint32_t i = 0; i < gNPolicies; ++i) {
@@ -224,23 +224,23 @@
         }
     }
 
-    unique_fd cpuLastUpdateFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_cpu_last_update_map"));
+    unique_fd cpuLastUpdateFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_cpu_last_update_map"));
     if (cpuLastUpdateFd < 0) return false;
     std::vector<uint64_t> zeros(get_nprocs_conf(), 0);
     uint32_t zero = 0;
     if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false;
 
-    unique_fd nrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_nr_active_map"));
+    unique_fd nrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_nr_active_map"));
     if (nrActiveFd < 0) return false;
     if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false;
 
-    unique_fd policyNrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_policy_nr_active_map"));
+    unique_fd policyNrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_policy_nr_active_map"));
     if (policyNrActiveFd < 0) return false;
     for (uint32_t i = 0; i < gNPolicies; ++i) {
         if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false;
     }
 
-    unique_fd policyFreqIdxFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map"));
+    unique_fd policyFreqIdxFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_policy_freq_idx_map"));
     if (policyFreqIdxFd < 0) return false;
     for (uint32_t i = 0; i < gNPolicies; ++i) {
         auto freqIdx = getPolicyFreqIdx(i);
@@ -300,11 +300,11 @@
     }
 
     std::vector<tis_val_t> vals(gNCpus);
-    time_key_t key = {.uid = uid};
     for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) {
-        key.bucket = i;
+        const time_key_t key = {.uid = uid, .bucket = i};
         if (findMapEntry(gTisMapFd, &key, vals.data())) {
-            if (errno != ENOENT || getFirstMapKey(gTisMapFd, &key)) return {};
+            time_key_t tmpKey;
+            if (errno != ENOENT || getFirstMapKey(gTisMapFd, &tmpKey)) return {};
             continue;
         }
 
@@ -412,10 +412,11 @@
     concurrent_time_t ret = {.active = std::vector<uint64_t>(gNCpus, 0)};
     for (const auto &cpuList : gPolicyCpus) ret.policy.emplace_back(cpuList.size(), 0);
     std::vector<concurrent_val_t> vals(gNCpus);
-    time_key_t key = {.uid = uid};
-    for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) {
+    for (uint32_t i = 0; i <= (gNCpus - 1) / CPUS_PER_ENTRY; ++i) {
+        const time_key_t key = {.uid = uid, .bucket = i};
         if (findMapEntry(gConcurrentMapFd, &key, vals.data())) {
-            if (errno != ENOENT || getFirstMapKey(gConcurrentMapFd, &key)) return {};
+            time_key_t tmpKey;
+            if (errno != ENOENT || getFirstMapKey(gConcurrentMapFd, &tmpKey)) return {};
             continue;
         }
         auto offset = key.bucket * CPUS_PER_ENTRY;
@@ -559,10 +560,10 @@
     if (!gInitialized && !initGlobals()) return false;
 
     unique_fd trackedPidHashMapFd(
-            mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_hash_map"));
+            mapRetrieveWO(BPF_FS_PATH "map_timeInState_pid_tracked_hash_map"));
     if (trackedPidHashMapFd < 0) return false;
 
-    unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_map"));
+    unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_pid_tracked_map"));
     if (trackedPidMapFd < 0) return false;
 
     for (uint32_t index = 0; index < MAX_TRACKED_PIDS; index++) {
@@ -589,7 +590,7 @@
     if (!gInitialized && !initGlobals()) return false;
 
     unique_fd taskAggregationMapFd(
-            mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_task_aggregation_map"));
+            mapRetrieveWO(BPF_FS_PATH "map_timeInState_pid_task_aggregation_map"));
     if (taskAggregationMapFd < 0) return false;
 
     return writeToMapEntry(taskAggregationMapFd, &pid, &aggregationKey, BPF_ANY) == 0;
diff --git a/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/Android.bp b/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/Android.bp
new file mode 100644
index 0000000..2399acd
--- /dev/null
+++ b/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/Android.bp
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ * 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.
+ *
+ *****************************************************************************
+ */
+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: "cputimeinstate_fuzzer",
+    srcs: [
+        "cputimeinstate_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libtimeinstate",
+    ],
+    shared_libs: [
+        "libbpf_bcc",
+        "libbase",
+        "libbpf_minimal",
+    ],
+}
diff --git a/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp b/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp
new file mode 100644
index 0000000..f835997
--- /dev/null
+++ b/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * 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 <fuzzer/FuzzedDataProvider.h>
+#include <android-base/unique_fd.h>
+#include <cputimeinstate.h>
+
+using namespace android::bpf;
+
+static const uint16_t MAX_VEC_SIZE = 500;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+
+    uint32_t uid = fdp.ConsumeIntegral<uint32_t>();
+    uint64_t lastUpdate = fdp.ConsumeIntegral<uint64_t>();
+    uint16_t aggregationKey = fdp.ConsumeIntegral<uint16_t>();
+    pid_t pid = fdp.ConsumeIntegral<pid_t>();
+    std::vector<uint16_t> aggregationKeys;
+    uint16_t aggregationKeysSize = fdp.ConsumeIntegralInRange<size_t>(0, MAX_VEC_SIZE);
+    for (uint16_t i = 0; i < aggregationKeysSize; i++) {
+        aggregationKeys.push_back(fdp.ConsumeIntegral<uint16_t>());
+    }
+
+    // To randomize the API calls
+     while (fdp.remaining_bytes() > 0) {
+        auto func = fdp.PickValueInArray<const std::function<void()>>({
+                [&]() { getUidCpuFreqTimes(uid); },
+                [&]() { getUidsUpdatedCpuFreqTimes(&lastUpdate); },
+                [&]() { getUidConcurrentTimes(uid);},
+                [&]() { getUidsUpdatedConcurrentTimes(&lastUpdate); },
+                [&]() { startAggregatingTaskCpuTimes(pid, aggregationKey); },
+                [&]() { getAggregatedTaskCpuFreqTimes(pid, aggregationKeys); },
+        });
+
+        func();
+    }
+
+    return 0;
+}
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 45a6d47..6ccc6ca 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -462,7 +462,7 @@
         ++uid;
     }
     android::base::unique_fd fd{
-        bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+        bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_concurrent_times_map")};
     ASSERT_GE(fd, 0);
     uint32_t nCpus = get_nprocs_conf();
     uint32_t maxBucket = (nCpus - 1) / CPUS_PER_ENTRY;
@@ -504,7 +504,7 @@
     {
         // Add a map entry for our fake UID by copying a real map entry
         android::base::unique_fd fd{
-                bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")};
+                bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_time_in_state_map")};
         ASSERT_GE(fd, 0);
         time_key_t k;
         ASSERT_FALSE(getFirstMapKey(fd, &k));
@@ -515,7 +515,7 @@
         ASSERT_FALSE(writeToMapEntry(fd, &k, vals.data(), BPF_NOEXIST));
 
         android::base::unique_fd fd2{
-                bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+                bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_concurrent_times_map")};
         k.uid = copiedUid;
         k.bucket = 0;
         std::vector<concurrent_val_t> cvals(get_nprocs_conf());
diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp
index acda402..09fbdea 100644
--- a/libs/dumputils/Android.bp
+++ b/libs/dumputils/Android.bp
@@ -26,6 +26,7 @@
 
     shared_libs: [
         "libbase",
+        "libbinder",
         "libhidlbase",
         "liblog",
         "libutils",
@@ -33,7 +34,10 @@
 
     srcs: ["dump_utils.cpp"],
 
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 
     export_include_dirs: [
         "include",
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 29c788b..a6585c5 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -20,6 +20,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
+#include <binder/IServiceManager.h>
 #include <dumputils/dump_utils.h>
 #include <log/log.h>
 
@@ -52,8 +53,8 @@
         NULL,
 };
 
-/* list of hal interface to dump containing process during native dumps */
-static const char* hal_interfaces_to_dump[] {
+/* list of hidl hal interface to dump containing process during native dumps */
+static const char* hidl_hal_interfaces_to_dump[] {
         "android.hardware.audio@4.0::IDevicesFactory",
         "android.hardware.audio@5.0::IDevicesFactory",
         "android.hardware.audio@6.0::IDevicesFactory",
@@ -82,6 +83,24 @@
         NULL,
 };
 
+/* list of hal interface to dump containing process during native dumps */
+static const std::vector<std::string> aidl_interfaces_to_dump {
+        "android.hardware.automotive.audiocontrol.IAudioControl",
+        "android.hardware.automotive.evs.IEvsEnumerator",
+        "android.hardware.biometrics.face.IBiometricsFace",
+        "android.hardware.biometrics.fingerprint.IBiometricsFingerprint",
+        "android.hardware.camera.provider.ICameraProvider",
+        "android.hardware.drm.IDrmFactory",
+        "android.hardware.graphics.allocator.IAllocator",
+        "android.hardware.graphics.composer3.IComposer",
+        "android.hardware.health.IHealth",
+        "android.hardware.input.processor.IInputProcessor",
+        "android.hardware.neuralnetworks.IDevice",
+        "android.hardware.power.IPower",
+        "android.hardware.power.stats.IPowerStats",
+        "android.hardware.sensors.ISensors",
+};
+
 /* list of extra hal interfaces to dump containing process during native dumps */
 // This is filled when dumpstate is called.
 static std::set<const std::string> extra_hal_interfaces_to_dump;
@@ -104,7 +123,7 @@
 
 // check if interface is included in either default hal list or extra hal list
 bool should_dump_hal_interface(const std::string& interface) {
-    for (const char** i = hal_interfaces_to_dump; *i; i++) {
+    for (const char** i = hidl_hal_interfaces_to_dump; *i; i++) {
         if (interface == *i) {
             return true;
         }
@@ -130,14 +149,26 @@
     return false;
 }
 
-std::set<int> get_interesting_hal_pids() {
+static void get_interesting_aidl_pids(std::set<int> &pids) {
+    using ServiceDebugInfo = android::IServiceManager::ServiceDebugInfo;
+    auto sm = android::defaultServiceManager();
+    std::vector<ServiceDebugInfo> serviceDebugInfos = sm->getServiceDebugInfo();
+    for (const auto & serviceDebugInfo : serviceDebugInfos) {
+        for (const auto &aidl_prefix : aidl_interfaces_to_dump) {
+            // Check for prefix match with aidl interface to dump
+            if (serviceDebugInfo.name.rfind(aidl_prefix, 0) == 0) {
+                pids.insert(serviceDebugInfo.pid);
+            }
+        }
+    }
+}
+
+static void get_interesting_hidl_pids(std::set<int> &pids) {
     using android::hidl::manager::V1_0::IServiceManager;
     using android::sp;
     using android::hardware::Return;
 
     sp<IServiceManager> manager = IServiceManager::getService();
-    std::set<int> pids;
-
     read_extra_hals_to_dump_from_property();
 
     Return<void> ret = manager->debugDump([&](auto& hals) {
@@ -146,11 +177,9 @@
                 continue;
             }
 
-            if (!should_dump_hal_interface(info.interfaceName)) {
-                continue;
+            if (should_dump_hal_interface(info.interfaceName)) {
+                pids.insert(info.pid);
             }
-
-            pids.insert(info.pid);
         }
     });
 
@@ -158,7 +187,14 @@
         ALOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
     }
 
-    return pids; // whether it was okay or not
+    return;
+}
+
+std::set<int> get_interesting_pids() {
+    std::set<int> interesting_pids;
+    get_interesting_hidl_pids(interesting_pids);
+    get_interesting_aidl_pids(interesting_pids);
+    return interesting_pids;
 }
 
 bool IsZygote(int pid) {
diff --git a/libs/dumputils/include/dumputils/dump_utils.h b/libs/dumputils/include/dumputils/dump_utils.h
index 25f7127..7c5329d 100644
--- a/libs/dumputils/include/dumputils/dump_utils.h
+++ b/libs/dumputils/include/dumputils/dump_utils.h
@@ -21,7 +21,7 @@
 
 bool should_dump_native_traces(const char* path);
 
-std::set<int> get_interesting_hal_pids();
+std::set<int> get_interesting_pids();
 
 bool IsZygote(int pid);
 
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 61e4a98..6c6d7f3 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -94,4 +94,8 @@
     return INVALID_OPERATION;
 }
 
+std::vector<IServiceManager::ServiceDebugInfo> ServiceManager::getServiceDebugInfo() {
+    std::vector<IServiceManager::ServiceDebugInfo> ret;
+    return ret;
+}
 }  // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index 6d6e008..e0af5d4 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -20,6 +20,7 @@
 
 #include <map>
 #include <optional>
+#include <vector>
 
 namespace android {
 
@@ -58,6 +59,9 @@
 
     status_t unregisterForNotifications(const String16& name,
                                         const sp<LocalRegistrationCallback>& callback) override;
+
+    std::vector<IServiceManager::ServiceDebugInfo> getServiceDebugInfo() override;
+
 private:
     std::map<String16, sp<IBinder>> mNameToService;
 };
diff --git a/libs/ftl/future_test.cpp b/libs/ftl/future_test.cpp
index 9b3e936..5a245b6 100644
--- a/libs/ftl/future_test.cpp
+++ b/libs/ftl/future_test.cpp
@@ -42,9 +42,9 @@
   }
   {
     auto future = ftl::yield(123);
-    std::future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
+    ftl::Future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
 
-    std::future<char> chain = ftl::chain(std::move(future))
+    ftl::Future<char> chain = ftl::Future(std::move(future))
                                   .then([](int x) { return static_cast<size_t>(x % 2); })
                                   .then([&futures](size_t i) { return std::move(futures[i]); });
 
@@ -71,7 +71,7 @@
     return ByteVector{str.begin(), str.end()};
   });
 
-  std::packaged_task<std::future<ByteVector>(ByteVector)> decrement_bytes(
+  std::packaged_task<ftl::Future<ByteVector>(ByteVector)> decrement_bytes(
       [](ByteVector bytes) { return ftl::defer(decrement, std::move(bytes)); });
 
   auto fetch = fetch_string.get_future();
@@ -81,7 +81,7 @@
 
   EXPECT_EQ(
       "hello, world",
-      ftl::chain(std::move(fetch))
+      ftl::Future(std::move(fetch))
           .then([](const char* str) { return std::string(str); })
           .then([&](std::string str) {
             auto append = append_string.get_future();
@@ -93,7 +93,7 @@
             decrement_thread = std::thread(std::move(decrement_bytes), std::move(bytes));
             return decrement;
           })
-          .then([](std::future<ByteVector> bytes) { return bytes; })
+          .then([](ftl::Future<ByteVector> bytes) { return bytes; })
           .then([](const ByteVector& bytes) { return std::string(bytes.begin(), bytes.end()); })
           .get());
 
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index 68b99b0..61e6657 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -196,35 +196,6 @@
 status_t validateMetadataType(InputHidlVec* input, const MetadataType& expectedMetadataType);
 
 /**
- * Private helper functions
- */
-template <class T>
-status_t encodeInteger(const T& input, OutputHidlVec* output) {
-    static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
-                  std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
-                  std::is_same<T, float>::value || std::is_same<T, double>::value);
-    if (!output) {
-        return BAD_VALUE;
-    }
-
-    const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
-    return output->encode(tmp, sizeof(input));
-}
-
-template <class T>
-status_t decodeInteger(InputHidlVec* input, T* output) {
-    static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
-                  std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
-                  std::is_same<T, float>::value || std::is_same<T, double>::value);
-    if (!output) {
-        return BAD_VALUE;
-    }
-
-    uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
-    return input->decode(tmp, sizeof(*output));
-}
-
-/**
  * encode/encodeMetadata are the main encoding functions. They take in T and uses the encodeHelper
  * function to turn T into the hidl_vec byte stream.
  *
@@ -280,45 +251,10 @@
 template <class T>
 status_t encodeOptionalMetadata(const MetadataType& metadataType, const std::optional<T>& input,
                         hidl_vec<uint8_t>* output, EncodeHelper<T> encodeHelper) {
-    OutputHidlVec outputHidlVec{output};
-
-    status_t err = encodeMetadataType(metadataType, &outputHidlVec);
-    if (err) {
-        return err;
+    if (!input) {
+        return NO_ERROR;
     }
-
-    err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
-    if (err) {
-        return err;
-    }
-
-    if (input) {
-        err = encodeHelper(*input, &outputHidlVec);
-        if (err) {
-            return err;
-        }
-    }
-
-    err = outputHidlVec.resize();
-    if (err) {
-        return err;
-    }
-
-    err = encodeMetadataType(metadataType, &outputHidlVec);
-    if (err) {
-        return err;
-    }
-
-    err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
-    if (err) {
-        return err;
-    }
-
-    if (input) {
-        return encodeHelper(*input, &outputHidlVec);
-    }
-
-    return NO_ERROR;
+    return encodeMetadata(metadataType, *input, output, encodeHelper);
 }
 
 /**
@@ -379,36 +315,45 @@
     if (!output) {
         return BAD_VALUE;
     }
-
-    InputHidlVec inputHidlVec{&input};
-
-    status_t err = validateMetadataType(&inputHidlVec, metadataType);
-    if (err) {
-        return err;
+    if (input.size() <= 0) {
+        output->reset();
+        return NO_ERROR;
     }
-
-    uint32_t present = 0;
-    err = decodeInteger<uint32_t>(&inputHidlVec, &present);
-    if (err) {
-        return err;
-    }
-
-    if (present) {
-        T tmp;
-        err = decodeHelper(&inputHidlVec, &tmp);
-        if (err) {
-            return err;
-        }
-
+    T tmp;
+    status_t err = decodeMetadata(metadataType, input, &tmp, decodeHelper);
+    if (!err) {
         *output = tmp;
     }
+    return err;
+}
 
-    err = inputHidlVec.hasRemainingData();
-    if (err) {
+/**
+ * Private helper functions
+ */
+template <class T>
+status_t encodeInteger(const T& input, OutputHidlVec* output) {
+    static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+                  std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+                  std::is_same<T, float>::value || std::is_same<T, double>::value);
+    if (!output) {
         return BAD_VALUE;
     }
 
-    return NO_ERROR;
+    const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
+    return output->encode(tmp, sizeof(input));
+}
+
+template <class T>
+status_t decodeInteger(InputHidlVec* input, T* output) {
+    static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+                  std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+                  std::is_same<T, float>::value || std::is_same<T, double>::value);
+    if (!output) {
+        return BAD_VALUE;
+    }
+
+    uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
+    return input->decode(tmp, sizeof(*output));
 }
 
 status_t encodeString(const std::string& input, OutputHidlVec* output) {
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/OWNERS b/libs/graphicsenv/OWNERS
index 8c28464..347c4e0 100644
--- a/libs/graphicsenv/OWNERS
+++ b/libs/graphicsenv/OWNERS
@@ -1,4 +1,10 @@
+abdolrashidi@google.com
+cclao@google.com
 chrisforbes@google.com
 cnorthrop@google.com
+ianelliott@google.com
+lfy@google.com
 lpy@google.com
-timvp@google.com
+romanl@google.com
+vantablack@google.com
+yuxinhu@google.com
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 648bcc3..e138212 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -184,7 +184,8 @@
     ],
 
     srcs: [
-        ":framework_native_aidl",
+        ":framework_native_aidl_binder",
+        ":framework_native_aidl_gui",
         ":inputconstants_aidl",
         ":libgui_bufferqueue_sources",
 
@@ -193,6 +194,7 @@
         "BufferHubConsumer.cpp",
         "BufferHubProducer.cpp",
         "BufferItemConsumer.cpp",
+        "CompositorTiming.cpp",
         "ConsumerBase.cpp",
         "CpuConsumer.cpp",
         "DebugEGLImageTracker.cpp",
@@ -334,7 +336,6 @@
 cc_defaults {
     name: "libgui_bufferqueue-defaults",
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -355,7 +356,7 @@
     },
 
     whole_static_libs: [
-        "LibGuiProperties",
+        "libLibGuiProperties",
     ],
 
     shared_libs: [
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index ccb901c..3bf2e19 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -159,13 +159,23 @@
     id++;
     mBufferItemConsumer->setName(String8(consumerName.c_str()));
     mBufferItemConsumer->setFrameAvailableListener(this);
-    mBufferItemConsumer->setBufferFreedListener(this);
 
     ComposerServiceAIDL::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
     mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
     mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
     mNumAcquired = 0;
     mNumFrameAvailable = 0;
+
+    TransactionCompletedListener::getInstance()->addQueueStallListener(
+        [&]() {
+            std::function<void(bool)> callbackCopy;
+            {
+                std::unique_lock _lock{mMutex};
+                callbackCopy = mTransactionHangCallback;
+            }
+            if (callbackCopy) callbackCopy(true);
+        }, this);
+
     BQA_LOGV("BLASTBufferQueue created");
 }
 
@@ -176,6 +186,7 @@
 }
 
 BLASTBufferQueue::~BLASTBufferQueue() {
+    TransactionCompletedListener::getInstance()->removeQueueStallListener(this);
     if (mPendingTransactions.empty()) {
         return;
     }
@@ -276,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 {
@@ -405,9 +415,11 @@
         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);
         }
     }
@@ -431,6 +443,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(
@@ -584,6 +599,7 @@
 }
 
 void BLASTBufferQueue::acquireAndReleaseBuffer() {
+    BBQ_TRACE();
     BufferItem bufferItem;
     status_t status =
             mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
@@ -597,7 +613,8 @@
 }
 
 void BLASTBufferQueue::flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock) {
-    if (mWaitForTransactionCallback && mNumFrameAvailable > 0) {
+    BBQ_TRACE();
+    if (!mSyncedFrameNumbers.empty() && mNumFrameAvailable > 0) {
         // We are waiting on a previous sync's transaction callback so allow another sync
         // transaction to proceed.
         //
@@ -624,9 +641,11 @@
 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};
+        BBQ_TRACE();
         const bool syncTransactionSet = mTransactionReadyCallback != nullptr;
         BQA_LOGV("onFrameAvailable-start syncTransactionSet=%s", boolToString(syncTransactionSet));
 
@@ -655,7 +674,7 @@
 
         // add to shadow queue
         mNumFrameAvailable++;
-        if (mWaitForTransactionCallback && mNumFrameAvailable >= 2) {
+        if (waitForTransactionCallback && mNumFrameAvailable >= 2) {
             acquireAndReleaseBuffer();
         }
         ATRACE_INT(mQueuedBufferTrace.c_str(),
@@ -672,14 +691,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);
         }
     }
@@ -1086,9 +1105,9 @@
     }
 
     // Clear sync states
-    if (mWaitForTransactionCallback) {
-        BQA_LOGD("mWaitForTransactionCallback cleared");
-        mWaitForTransactionCallback = false;
+    if (!mSyncedFrameNumbers.empty()) {
+        BQA_LOGD("mSyncedFrameNumbers cleared");
+        mSyncedFrameNumbers.clear();
     }
 
     if (mSyncTransaction != nullptr) {
@@ -1102,7 +1121,6 @@
     if (mBufferItemConsumer != nullptr) {
         mBufferItemConsumer->abandon();
         mBufferItemConsumer->setFrameAvailableListener(nullptr);
-        mBufferItemConsumer->setBufferFreedListener(nullptr);
     }
     mBufferItemConsumer = nullptr;
     mConsumer = nullptr;
@@ -1114,4 +1132,9 @@
     return SurfaceControl::isSameSurface(mSurfaceControl, surfaceControl);
 }
 
+void BLASTBufferQueue::setTransactionHangCallback(std::function<void(bool)> callback) {
+    std::unique_lock _lock{mMutex};
+    mTransactionHangCallback = callback;
+}
+
 } // namespace android
diff --git a/libs/gui/CompositorTiming.cpp b/libs/gui/CompositorTiming.cpp
new file mode 100644
index 0000000..50f7b25
--- /dev/null
+++ b/libs/gui/CompositorTiming.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "CompositorTiming"
+
+#include <cutils/compiler.h>
+#include <gui/CompositorTiming.h>
+#include <log/log.h>
+
+namespace android::gui {
+
+CompositorTiming::CompositorTiming(nsecs_t vsyncDeadline, nsecs_t vsyncPeriod, nsecs_t vsyncPhase,
+                                   nsecs_t presentLatency) {
+    if (CC_UNLIKELY(vsyncPeriod <= 0)) {
+        ALOGE("Invalid VSYNC period");
+        return;
+    }
+
+    const nsecs_t idealLatency = [=] {
+        // Modulo rounds toward 0 not INT64_MIN, so treat signs separately.
+        if (vsyncPhase < 0) return -vsyncPhase % vsyncPeriod;
+
+        const nsecs_t latency = (vsyncPeriod - vsyncPhase) % vsyncPeriod;
+        return latency > 0 ? latency : vsyncPeriod;
+    }();
+
+    // Snap the latency to a value that removes scheduling jitter from the composite and present
+    // times, which often have >1ms of jitter. Reducing jitter is important if an app attempts to
+    // extrapolate something like user input to an accurate present time. Snapping also allows an
+    // app to precisely calculate vsyncPhase with (presentLatency % interval).
+    const nsecs_t bias = vsyncPeriod / 2;
+    const nsecs_t extraVsyncs = (presentLatency - idealLatency + bias) / vsyncPeriod;
+    const nsecs_t snappedLatency =
+            extraVsyncs > 0 ? idealLatency + extraVsyncs * vsyncPeriod : idealLatency;
+
+    this->deadline = vsyncDeadline - idealLatency;
+    this->interval = vsyncPeriod;
+    this->presentLatency = snappedLatency;
+}
+
+} // namespace android::gui
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index dfdce20..501e69a 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -35,11 +35,14 @@
 
 static constexpr nsecs_t WAITING_FOR_VSYNC_TIMEOUT = ms2ns(300);
 
-DisplayEventDispatcher::DisplayEventDispatcher(
-        const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource,
-        ISurfaceComposer::EventRegistrationFlags eventRegistration)
-      : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false),
-        mLastVsyncCount(0), mLastScheduleVsyncTime(0) {
+DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
+                                               gui::ISurfaceComposer::VsyncSource vsyncSource,
+                                               EventRegistrationFlags eventRegistration)
+      : mLooper(looper),
+        mReceiver(vsyncSource, eventRegistration),
+        mWaitingForVsync(false),
+        mLastVsyncCount(0),
+        mLastScheduleVsyncTime(0) {
     ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
 }
 
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index bfb7769..c52fb6b 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -19,10 +19,9 @@
 #include <utils/Errors.h>
 
 #include <gui/DisplayEventReceiver.h>
-#include <gui/ISurfaceComposer.h>
 #include <gui/VsyncEventData.h>
 
-#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 
 #include <private/gui/BitTube.h>
 
@@ -32,15 +31,20 @@
 
 // ---------------------------------------------------------------------------
 
-DisplayEventReceiver::DisplayEventReceiver(
-        ISurfaceComposer::VsyncSource vsyncSource,
-        ISurfaceComposer::EventRegistrationFlags eventRegistration) {
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+DisplayEventReceiver::DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource vsyncSource,
+                                           EventRegistrationFlags eventRegistration) {
+    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
     if (sf != nullptr) {
-        mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration);
+        mEventConnection = nullptr;
+        binder::Status status =
+                sf->createDisplayEventConnection(vsyncSource,
+                                                 static_cast<
+                                                         gui::ISurfaceComposer::EventRegistration>(
+                                                         eventRegistration.get()),
+                                                 &mEventConnection);
         if (mEventConnection != nullptr) {
             mDataChannel = std::make_unique<gui::BitTube>();
-            const auto status = mEventConnection->stealReceiveChannel(mDataChannel.get());
+            status = mEventConnection->stealReceiveChannel(mDataChannel.get());
             if (!status.isOk()) {
                 ALOGE("stealReceiveChannel failed: %s", status.toString8().c_str());
                 mInitError = std::make_optional<status_t>(status.transactionError());
diff --git a/libs/gui/GLConsumerUtils.cpp b/libs/gui/GLConsumerUtils.cpp
index 7a06c3d..a1c69e7 100644
--- a/libs/gui/GLConsumerUtils.cpp
+++ b/libs/gui/GLConsumerUtils.cpp
@@ -27,6 +27,13 @@
 void GLConsumer::computeTransformMatrix(float outTransform[16],
         const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
         bool filtering) {
+    computeTransformMatrix(outTransform, buf->getWidth(), buf->getHeight(), buf->getPixelFormat(),
+                           cropRect, transform, filtering);
+}
+
+void GLConsumer::computeTransformMatrix(float outTransform[16], float bufferWidth,
+                                        float bufferHeight, PixelFormat pixelFormat,
+                                        const Rect& cropRect, uint32_t transform, bool filtering) {
     // Transform matrices
     static const mat4 mtxFlipH(
         -1, 0, 0, 0,
@@ -60,8 +67,6 @@
 
     if (!cropRect.isEmpty()) {
         float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
-        float bufferWidth = buf->getWidth();
-        float bufferHeight = buf->getHeight();
         float shrinkAmount = 0.0f;
         if (filtering) {
             // In order to prevent bilinear sampling beyond the edge of the
@@ -70,7 +75,7 @@
             // off each end, but because the chroma channels of YUV420 images
             // are subsampled we may need to shrink the crop region by a whole
             // texel on each side.
-            switch (buf->getPixelFormat()) {
+            switch (pixelFormat) {
                 case PIXEL_FORMAT_RGBA_8888:
                 case PIXEL_FORMAT_RGBX_8888:
                 case PIXEL_FORMAT_RGBA_FP16:
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 54e50b5..af64b3b 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -108,35 +108,6 @@
                     data, &reply);
         }
     }
-
-    void bootFinished() override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
-    }
-
-    sp<IDisplayEventConnection> createDisplayEventConnection(
-            VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) override {
-        Parcel data, reply;
-        sp<IDisplayEventConnection> result;
-        int err = data.writeInterfaceToken(
-                ISurfaceComposer::getInterfaceDescriptor());
-        if (err != NO_ERROR) {
-            return result;
-        }
-        data.writeInt32(static_cast<int32_t>(vsyncSource));
-        data.writeUint32(eventRegistration.get());
-        err = remote()->transact(
-                BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION,
-                data, &reply);
-        if (err != NO_ERROR) {
-            ALOGE("ISurfaceComposer::createDisplayEventConnection: error performing "
-                    "transaction: %s (%d)", strerror(-err), -err);
-            return result;
-        }
-        result = interface_cast<IDisplayEventConnection>(reply.readStrongBinder());
-        return result;
-    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -215,22 +186,6 @@
                                        uncachedBuffer, hasListenerCallbacks, listenerCallbacks,
                                        transactionId);
         }
-        case BOOT_FINISHED: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            bootFinished();
-            return NO_ERROR;
-        }
-        case CREATE_DISPLAY_EVENT_CONNECTION: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            auto vsyncSource = static_cast<ISurfaceComposer::VsyncSource>(data.readInt32());
-            EventRegistrationFlags eventRegistration =
-                    static_cast<EventRegistration>(data.readUint32());
-
-            sp<IDisplayEventConnection> connection(
-                    createDisplayEventConnection(vsyncSource, eventRegistration));
-            reply->writeStrongBinder(IInterface::asBinder(connection));
-            return NO_ERROR;
-        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index f7392d4..e4b8bad 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -29,6 +29,7 @@
 enum class Tag : uint32_t {
     ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION,
     ON_RELEASE_BUFFER,
+    ON_TRANSACTION_QUEUE_STALLED,
     LAST = ON_RELEASE_BUFFER,
 };
 
@@ -277,6 +278,11 @@
                                                                   callbackId, releaseFence,
                                                                   currentMaxAcquiredBufferCount);
     }
+
+    void onTransactionQueueStalled() override {
+        callRemoteAsync<decltype(&ITransactionCompletedListener::onTransactionQueueStalled)>(
+            Tag::ON_TRANSACTION_QUEUE_STALLED);
+    }
 };
 
 // Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
@@ -297,6 +303,9 @@
                                   &ITransactionCompletedListener::onTransactionCompleted);
         case Tag::ON_RELEASE_BUFFER:
             return callLocalAsync(data, reply, &ITransactionCompletedListener::onReleaseBuffer);
+        case Tag::ON_TRANSACTION_QUEUE_STALLED:
+            return callLocalAsync(data, reply,
+                                  &ITransactionCompletedListener::onTransactionQueueStalled);
     }
 }
 
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 3ab9e97..bb66085 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -63,9 +63,11 @@
         frameRate(0.0f),
         frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT),
         changeFrameRateStrategy(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS),
+        defaultFrameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT),
         fixedTransformHint(ui::Transform::ROT_INVALID),
         autoRefresh(false),
         isTrustedOverlay(false),
+        borderEnabled(false),
         bufferCrop(Rect::INVALID_RECT),
         destinationFrame(Rect::INVALID_RECT),
         dropInputMode(gui::DropInputMode::NONE) {
@@ -100,7 +102,12 @@
     SAFE_PARCEL(output.write, transparentRegion);
     SAFE_PARCEL(output.writeUint32, transform);
     SAFE_PARCEL(output.writeBool, transformToDisplayInverse);
-
+    SAFE_PARCEL(output.writeBool, borderEnabled);
+    SAFE_PARCEL(output.writeFloat, borderWidth);
+    SAFE_PARCEL(output.writeFloat, borderColor.r);
+    SAFE_PARCEL(output.writeFloat, borderColor.g);
+    SAFE_PARCEL(output.writeFloat, borderColor.b);
+    SAFE_PARCEL(output.writeFloat, borderColor.a);
     SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dataspace));
     SAFE_PARCEL(output.write, hdrMetadata);
     SAFE_PARCEL(output.write, surfaceDamageRegion);
@@ -131,6 +138,7 @@
     SAFE_PARCEL(output.writeFloat, frameRate);
     SAFE_PARCEL(output.writeByte, frameRateCompatibility);
     SAFE_PARCEL(output.writeByte, changeFrameRateStrategy);
+    SAFE_PARCEL(output.writeByte, defaultFrameRateCompatibility);
     SAFE_PARCEL(output.writeUint32, fixedTransformHint);
     SAFE_PARCEL(output.writeBool, autoRefresh);
     SAFE_PARCEL(output.writeBool, dimmingEnabled);
@@ -200,6 +208,17 @@
     SAFE_PARCEL(input.read, transparentRegion);
     SAFE_PARCEL(input.readUint32, &transform);
     SAFE_PARCEL(input.readBool, &transformToDisplayInverse);
+    SAFE_PARCEL(input.readBool, &borderEnabled);
+    SAFE_PARCEL(input.readFloat, &tmpFloat);
+    borderWidth = tmpFloat;
+    SAFE_PARCEL(input.readFloat, &tmpFloat);
+    borderColor.r = tmpFloat;
+    SAFE_PARCEL(input.readFloat, &tmpFloat);
+    borderColor.g = tmpFloat;
+    SAFE_PARCEL(input.readFloat, &tmpFloat);
+    borderColor.b = tmpFloat;
+    SAFE_PARCEL(input.readFloat, &tmpFloat);
+    borderColor.a = tmpFloat;
 
     uint32_t tmpUint32 = 0;
     SAFE_PARCEL(input.readUint32, &tmpUint32);
@@ -240,6 +259,7 @@
     SAFE_PARCEL(input.readFloat, &frameRate);
     SAFE_PARCEL(input.readByte, &frameRateCompatibility);
     SAFE_PARCEL(input.readByte, &changeFrameRateStrategy);
+    SAFE_PARCEL(input.readByte, &defaultFrameRateCompatibility);
     SAFE_PARCEL(input.readUint32, &tmpUint32);
     fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
     SAFE_PARCEL(input.readBool, &autoRefresh);
@@ -550,6 +570,16 @@
         what |= eShadowRadiusChanged;
         shadowRadius = other.shadowRadius;
     }
+    if (other.what & eRenderBorderChanged) {
+        what |= eRenderBorderChanged;
+        borderEnabled = other.borderEnabled;
+        borderWidth = other.borderWidth;
+        borderColor = other.borderColor;
+    }
+    if (other.what & eDefaultFrameRateCompatibilityChanged) {
+        what |= eDefaultFrameRateCompatibilityChanged;
+        defaultFrameRateCompatibility = other.defaultFrameRateCompatibility;
+    }
     if (other.what & eFrameRateSelectionPriority) {
         what |= eFrameRateSelectionPriority;
         frameRateSelectionPriority = other.frameRateSelectionPriority;
@@ -641,29 +671,44 @@
     changes |= !other.focusRequests.empty();
     focusRequests.insert(focusRequests.end(), std::make_move_iterator(other.focusRequests.begin()),
                          std::make_move_iterator(other.focusRequests.end()));
-    changes |= other.syncInputWindows && !syncInputWindows;
-    syncInputWindows |= other.syncInputWindows;
+    changes |= !other.windowInfosReportedListeners.empty();
+    windowInfosReportedListeners.insert(other.windowInfosReportedListeners.begin(),
+                                        other.windowInfosReportedListeners.end());
     return changes;
 }
 
 bool InputWindowCommands::empty() const {
-    return focusRequests.empty() && !syncInputWindows;
+    return focusRequests.empty() && windowInfosReportedListeners.empty();
 }
 
 void InputWindowCommands::clear() {
     focusRequests.clear();
-    syncInputWindows = false;
+    windowInfosReportedListeners.clear();
 }
 
 status_t InputWindowCommands::write(Parcel& output) const {
     SAFE_PARCEL(output.writeParcelableVector, focusRequests);
-    SAFE_PARCEL(output.writeBool, syncInputWindows);
+
+    SAFE_PARCEL(output.writeInt32, windowInfosReportedListeners.size());
+    for (const auto& listener : windowInfosReportedListeners) {
+        SAFE_PARCEL(output.writeStrongBinder, listener);
+    }
+
     return NO_ERROR;
 }
 
 status_t InputWindowCommands::read(const Parcel& input) {
     SAFE_PARCEL(input.readParcelableVector, &focusRequests);
-    SAFE_PARCEL(input.readBool, &syncInputWindows);
+
+    int listenerSize = 0;
+    SAFE_PARCEL_READ_SIZE(input.readInt32, &listenerSize, input.dataSize());
+    windowInfosReportedListeners.reserve(listenerSize);
+    for (int i = 0; i < listenerSize; i++) {
+        sp<gui::IWindowInfosReportedListener> listener;
+        SAFE_PARCEL(input.readStrongBinder, &listener);
+        windowInfosReportedListeners.insert(listener);
+    }
+
     return NO_ERROR;
 }
 
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index 45c958e..31bf895 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -2,9 +2,8 @@
 alecmouri@google.com
 chaviw@google.com
 chrisforbes@google.com
-jessehall@google.com
 lpy@google.com
-mathias@google.com
+jreck@google.com
 racarr@google.com
 vishnun@google.com
 
diff --git a/libs/gui/ScreenCaptureResults.cpp b/libs/gui/ScreenCaptureResults.cpp
index e91f74f..fe38706 100644
--- a/libs/gui/ScreenCaptureResults.cpp
+++ b/libs/gui/ScreenCaptureResults.cpp
@@ -36,6 +36,7 @@
     }
 
     SAFE_PARCEL(parcel->writeBool, capturedSecureLayers);
+    SAFE_PARCEL(parcel->writeBool, capturedHdrLayers);
     SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(capturedDataspace));
     SAFE_PARCEL(parcel->writeInt32, result);
     return NO_ERROR;
@@ -57,6 +58,7 @@
     }
 
     SAFE_PARCEL(parcel->readBool, &capturedSecureLayers);
+    SAFE_PARCEL(parcel->readBool, &capturedHdrLayers);
     uint32_t dataspace = 0;
     SAFE_PARCEL(parcel->readUint32, &dataspace);
     capturedDataspace = static_cast<ui::Dataspace>(dataspace);
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 7a2615f..4b4d46a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -30,9 +30,10 @@
 #include <android/gui/DisplayStatInfo.h>
 #include <android/native_window.h>
 
+#include <gui/TraceUtils.h>
 #include <utils/Log.h>
-#include <utils/Trace.h>
 #include <utils/NativeHandle.h>
+#include <utils/Trace.h>
 
 #include <ui/DynamicDisplayInfo.h>
 #include <ui/Fence.h>
@@ -637,7 +638,7 @@
 }
 
 int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
-    ATRACE_CALL();
+    ATRACE_FORMAT("dequeueBuffer - %s", getDebugName());
     ALOGV("Surface::dequeueBuffer");
 
     IGraphicBufferProducer::DequeueBufferInput dqInput;
@@ -1947,6 +1948,7 @@
         mReqHeight = 0;
         mReqUsage = 0;
         mCrop.clear();
+        mDataSpace = Dataspace::UNKNOWN;
         mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
         mTransform = 0;
         mStickyTransform = 0;
@@ -2627,12 +2629,13 @@
     mSurfaceListener->onBuffersDiscarded(discardedBufs);
 }
 
-status_t Surface::setFrameRate(float /*frameRate*/, int8_t /*compatibility*/,
-                               int8_t /*changeFrameRateStrategy*/) {
-    ATRACE_CALL();
-    ALOGV("Surface::setFrameRate");
-    // ISurfaceComposer no longer supports setFrameRate
-    return BAD_VALUE;
+[[deprecated]] status_t Surface::setFrameRate(float /*frameRate*/, int8_t /*compatibility*/,
+                                              int8_t /*changeFrameRateStrategy*/) {
+    ALOGI("Surface::setFrameRate is deprecated, setFrameRate hint is dropped as destination is not "
+          "SurfaceFlinger");
+    // ISurfaceComposer no longer supports setFrameRate, we will return NO_ERROR when the api is
+    // called to avoid apps crashing, as BAD_VALUE can generate fatal exception in apps.
+    return NO_ERROR;
 }
 
 status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& /*frameTimelineInfo*/) {
@@ -2650,4 +2653,12 @@
     mSurfaceControlHandle = nullptr;
 }
 
+const char* Surface::getDebugName() {
+    std::unique_lock lock{mNameMutex};
+    if (mName.empty()) {
+        mName = getConsumerName();
+    }
+    return mName.c_str();
+}
+
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 035aac9..e8aaf62 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -19,6 +19,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <android/gui/BnWindowInfosReportedListener.h>
 #include <android/gui/DisplayState.h>
 #include <android/gui/ISurfaceComposerClient.h>
 #include <android/gui/IWindowInfosListener.h>
@@ -450,6 +451,27 @@
     }
 }
 
+void TransactionCompletedListener::onTransactionQueueStalled() {
+      std::unordered_map<void*, std::function<void()>> callbackCopy;
+      {
+          std::scoped_lock<std::mutex> lock(mMutex);
+          callbackCopy = mQueueStallListeners;
+      }
+      for (auto const& it : callbackCopy) {
+          it.second();
+      }
+}
+
+void TransactionCompletedListener::addQueueStallListener(std::function<void()> stallListener,
+                                                         void* id) {
+    std::scoped_lock<std::mutex> lock(mMutex);
+    mQueueStallListeners[id] = stallListener;
+}
+void TransactionCompletedListener::removeQueueStallListener(void *id) {
+    std::scoped_lock<std::mutex> lock(mMutex);
+    mQueueStallListeners.erase(id);
+}
+
 void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId,
                                                    sp<Fence> releaseFence,
                                                    uint32_t currentMaxAcquiredBufferCount) {
@@ -639,6 +661,7 @@
 
 
 status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) {
+    const uint64_t transactionId = parcel->readUint64();
     const uint32_t forceSynchronous = parcel->readUint32();
     const uint32_t transactionNestCount = parcel->readUint32();
     const bool animation = parcel->readBool();
@@ -716,6 +739,7 @@
     inputWindowCommands.read(*parcel);
 
     // Parsing was successful. Update the object.
+    mId = transactionId;
     mForceSynchronous = forceSynchronous;
     mTransactionNestCount = transactionNestCount;
     mAnimation = animation;
@@ -747,6 +771,7 @@
 
     const_cast<SurfaceComposerClient::Transaction*>(this)->cacheBuffers();
 
+    parcel->writeUint64(mId);
     parcel->writeUint32(mForceSynchronous);
     parcel->writeUint32(mTransactionNestCount);
     parcel->writeBool(mAnimation);
@@ -879,6 +904,10 @@
     mApplyToken = nullptr;
 }
 
+uint64_t SurfaceComposerClient::Transaction::getId() {
+    return mId;
+}
+
 void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
 
@@ -1056,16 +1085,6 @@
     return physicalDisplayIds;
 }
 
-status_t SurfaceComposerClient::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) {
-    int64_t displayId;
-    binder::Status status =
-            ComposerServiceAIDL::getComposerService()->getPrimaryPhysicalDisplayId(&displayId);
-    if (status.isOk()) {
-        *id = *DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
-    }
-    return statusTFromBinderStatus(status);
-}
-
 std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
     ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
     return instance.getInternalDisplayId();
@@ -1250,8 +1269,11 @@
         mStatus = BAD_INDEX;
         return *this;
     }
+    if (alpha < 0.0f || alpha > 1.0f) {
+        ALOGE("SurfaceComposerClient::Transaction::setAlpha: invalid alpha %f, clamping", alpha);
+    }
     s->what |= layer_state_t::eAlphaChanged;
-    s->alpha = alpha;
+    s->alpha = std::clamp(alpha, 0.f, 1.f);
 
     registerSurfaceControlForCallback(sc);
     return *this;
@@ -1479,6 +1501,13 @@
 
     releaseBufferIfOverwriting(*s);
 
+    if (buffer == nullptr) {
+        s->what &= ~layer_state_t::eBufferChanged;
+        s->bufferData = nullptr;
+        mContainsBuffer = false;
+        return *this;
+    }
+
     std::shared_ptr<BufferData> bufferData = std::make_shared<BufferData>();
     bufferData->buffer = buffer;
     uint64_t frameNumber = sc->resolveFrameNumber(optFrameNumber);
@@ -1498,6 +1527,18 @@
     s->bufferData = std::move(bufferData);
     registerSurfaceControlForCallback(sc);
 
+    // With the current infrastructure, a release callback will not be invoked if there's no
+    // transaction callback in the case when a buffer is latched and not released early. This is
+    // because the legacy implementation didn't have a release callback and sent releases in the
+    // transaction callback. Because of this, we need to make sure to have a transaction callback
+    // set up when a buffer is sent in a transaction to ensure the caller gets the release
+    // callback, regardless if they set up a transaction callback.
+    //
+    // TODO (b/230380821): Remove when release callbacks are separated from transaction callbacks
+    addTransactionCompletedCallback([](void*, nsecs_t, const sp<Fence>&,
+                                       const std::vector<SurfaceControlStats>&) {},
+                                    nullptr);
+
     mContainsBuffer = true;
     return *this;
 }
@@ -1686,8 +1727,10 @@
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() {
-    mInputWindowCommands.syncInputWindows = true;
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::addWindowInfosReportedListener(
+        sp<gui::IWindowInfosReportedListener> windowInfosReportedListener) {
+    mInputWindowCommands.windowInfosReportedListeners.insert(windowInfosReportedListener);
     return *this;
 }
 
@@ -1794,6 +1837,19 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::setDefaultFrameRateCompatibility(const sp<SurfaceControl>& sc,
+                                                                     int8_t compatibility) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eDefaultFrameRateCompatibilityChanged;
+    s->defaultFrameRateCompatibility = compatibility;
+    return *this;
+}
+
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixedTransformHint(
         const sp<SurfaceControl>& sc, int32_t fixedTransformHint) {
     layer_state_t* s = getLayerState(sc);
@@ -1906,6 +1962,23 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::enableBorder(
+        const sp<SurfaceControl>& sc, bool shouldEnable, float width, const half4& color) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+
+    s->what |= layer_state_t::eRenderBorderChanged;
+    s->borderEnabled = shouldEnable;
+    s->borderWidth = width;
+    s->borderColor = color;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
 // ---------------------------------------------------------------------------
 
 DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
@@ -2097,6 +2170,16 @@
     return nullptr;
 }
 
+sp<SurfaceControl> SurfaceComposerClient::mirrorDisplay(DisplayId displayId) {
+    gui::MirrorSurfaceResult result;
+    const binder::Status status = mClient->mirrorDisplay(displayId.value, &result);
+    const status_t err = statusTFromBinderStatus(status);
+    if (err == NO_ERROR) {
+        return new SurfaceControl(this, result.handle, result.layerId);
+    }
+    return nullptr;
+}
+
 status_t SurfaceComposerClient::clearLayerFrameStats(const sp<IBinder>& token) const {
     if (mStatus != NO_ERROR) {
         return mStatus;
@@ -2181,6 +2264,10 @@
             size_t count = std::max<size_t>(kMaxPnpIdSize, dpi->manufacturerPnpId.size());
             std::copy_n(dpi->manufacturerPnpId.begin(), count, info.manufacturerPnpId.begin());
         }
+        if (dpi->relativeAddress.size() > 0) {
+            std::copy(dpi->relativeAddress.begin(), dpi->relativeAddress.end(),
+                      std::back_inserter(info.relativeAddress));
+        }
         info.productId = dpi->productId;
         if (date.getTag() == Tag::modelYear) {
             DeviceProductInfo::ModelYear modelYear;
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index 26b4e81..3c220fc 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -30,6 +30,7 @@
 import android.gui.DynamicDisplayInfo;
 import android.gui.FrameEvent;
 import android.gui.FrameStats;
+import android.gui.IDisplayEventConnection;
 import android.gui.IFpsListener;
 import android.gui.IHdrLayerInfoListener;
 import android.gui.IRegionSamplingListener;
@@ -47,6 +48,30 @@
 /** @hide */
 interface ISurfaceComposer {
 
+    enum VsyncSource {
+        eVsyncSourceApp = 0,
+        eVsyncSourceSurfaceFlinger = 1
+    }
+
+    enum EventRegistration {
+        modeChanged = 1 << 0,
+        frameRateOverride = 1 << 1,
+    }
+
+    /**
+     * Signal that we're done booting.
+     * Requires ACCESS_SURFACE_FLINGER permission
+     */
+    // Note this must be the 1st method, so IBinder::FIRST_CALL_TRANSACTION
+    // is assigned, as it is called from Java by ActivityManagerService.
+    void bootFinished();
+
+    /**
+     * Create a display event connection
+     */
+    @nullable IDisplayEventConnection createDisplayEventConnection(VsyncSource vsyncSource,
+            EventRegistration eventRegistration);
+
     /**
      * Create a connection with SurfaceFlinger.
      */
@@ -69,8 +94,6 @@
      */
     long[] getPhysicalDisplayIds();
 
-    long getPrimaryPhysicalDisplayId();
-
     /**
      * Get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or
      * a DisplayEventReceiver hotplug event.
@@ -93,7 +116,7 @@
      * Returns display statistics for a given display
      * intended to be used by the media framework to properly schedule
      * video frames */
-    DisplayStatInfo getDisplayStats(IBinder display);
+    DisplayStatInfo getDisplayStats(@nullable IBinder display);
 
     /**
      * Get transactional state of given display.
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl
index 71933aa..b8ee4d7 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl
@@ -59,4 +59,6 @@
     FrameStats getLayerFrameStats(IBinder handle);
 
     MirrorSurfaceResult mirrorSurface(IBinder mirrorFromHandle);
+
+    MirrorSurfaceResult mirrorDisplay(long displayId);
 }
diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp
new file mode 100644
index 0000000..cdc9376
--- /dev/null
+++ b/libs/gui/fuzzer/Android.bp
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_defaults {
+    name: "libgui_fuzzer_defaults",
+    static_libs: [
+        "android.hidl.token@1.0-utils",
+        "libbinder_random_parcel",
+        "libgui_aidl_static",
+        "libgui_window_info_static",
+        "libpdx",
+        "libgmock",
+        "libgui_mocks",
+        "libgmock_ndk",
+        "libgmock_main",
+        "libgtest_ndk_c++",
+        "libgmock_main_ndk",
+        "librenderengine_mocks",
+        "perfetto_trace_protos",
+        "libcompositionengine_mocks",
+        "perfetto_trace_protos",
+    ],
+    shared_libs: [
+        "android.hardware.configstore@1.0",
+        "android.hardware.configstore-utils",
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+        "android.hardware.power-V2-cpp",
+        "android.hidl.token@1.0",
+        "libSurfaceFlingerProp",
+        "libgui",
+        "libbase",
+        "liblog",
+        "libEGL",
+        "libGLESv2",
+        "libbinder",
+        "libcutils",
+        "libhidlbase",
+        "libinput",
+        "libui",
+        "libutils",
+        "libnativewindow",
+        "libvndksupport",
+        "libbufferhubqueue",
+    ],
+    header_libs: [
+        "libdvr_headers",
+        "libui_fuzzableDataspaces_headers",
+    ],
+    fuzz_config: {
+        cc: [
+            "android-media-fuzzing-reports@google.com",
+        ],
+        componentid: 155276,
+    },
+}
+
+cc_fuzz {
+    name: "libgui_surfaceComposer_fuzzer",
+    srcs: [
+        "libgui_surfaceComposer_fuzzer.cpp",
+    ],
+    defaults: [
+        "libgui_fuzzer_defaults",
+    ],
+}
+
+cc_fuzz {
+    name: "libgui_surfaceComposerClient_fuzzer",
+    srcs: [
+        "libgui_surfaceComposerClient_fuzzer.cpp",
+    ],
+    defaults: [
+        "libgui_fuzzer_defaults",
+    ],
+}
+
+cc_fuzz {
+    name: "libgui_parcelable_fuzzer",
+    srcs: [
+        "libgui_parcelable_fuzzer.cpp",
+    ],
+    defaults: [
+        "libgui_fuzzer_defaults",
+    ],
+}
+
+cc_fuzz {
+    name: "libgui_bufferQueue_fuzzer",
+    srcs: [
+        "libgui_bufferQueue_fuzzer.cpp",
+    ],
+    defaults: [
+        "libgui_fuzzer_defaults",
+    ],
+}
+
+cc_fuzz {
+    name: "libgui_consumer_fuzzer",
+    srcs: [
+        "libgui_consumer_fuzzer.cpp",
+    ],
+    defaults: [
+        "libgui_fuzzer_defaults",
+    ],
+}
+
+cc_fuzz {
+    name: "libgui_displayEvent_fuzzer",
+    srcs: [
+        "libgui_displayEvent_fuzzer.cpp",
+    ],
+    defaults: [
+        "libgui_fuzzer_defaults",
+    ],
+}
diff --git a/libs/gui/fuzzer/README.md b/libs/gui/fuzzer/README.md
new file mode 100644
index 0000000..96e27c9
--- /dev/null
+++ b/libs/gui/fuzzer/README.md
@@ -0,0 +1,219 @@
+# Fuzzers for Libgui
+
+## Table of contents
++ [libgui_surfaceComposer_fuzzer](#SurfaceComposer)
++ [libgui_surfaceComposerClient_fuzzer](#SurfaceComposerClient)
++ [libgui_parcelable_fuzzer](#Libgui_Parcelable)
++ [libgui_bufferQueue_fuzzer](#BufferQueue)
++ [libgui_consumer_fuzzer](#Libgui_Consumer)
++ [libgui_displayEvent_fuzzer](#LibGui_DisplayEvent)
+
+# <a name="libgui_surfaceComposer_fuzzer"></a> Fuzzer for SurfaceComposer
+
+SurfaceComposer supports the following parameters:
+1. SurfaceWidth (parameter name:`width`)
+2. SurfaceHeight (parameter name:`height`)
+3. TransactionStateFlags (parameter name:`flags`)
+4. TransformHint (parameter name:`outTransformHint`)
+5. SurfacePixelFormat (parameter name:`format`)
+6. LayerId (parameter name:`outLayerId`)
+7. SurfaceComposerTags (parameter name:`surfaceTag`)
+8. PowerBoostID (parameter name:`boostId`)
+9. VsyncSource (parameter name:`vsyncSource`)
+10. EventRegistrationFlags (parameter name:`eventRegistration`)
+11. FrameRateCompatibility (parameter name:`frameRateCompatibility`)
+12. ChangeFrameRateStrategy (parameter name:`changeFrameRateStrategy`)
+13. HdrTypes (parameter name:`hdrTypes`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`surfaceTag` | 0.`BnSurfaceComposer::BOOT_FINISHED`, 1.`BnSurfaceComposer::CREATE_CONNECTION`, 2.`BnSurfaceComposer::GET_STATIC_DISPLAY_INFO`, 3.`BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION`, 4.`BnSurfaceComposer::CREATE_DISPLAY`, 5.`BnSurfaceComposer::DESTROY_DISPLAY`, 6.`BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN`, 7.`BnSurfaceComposer::SET_TRANSACTION_STATE`, 8.`BnSurfaceComposer::AUTHENTICATE_SURFACE`, 9.`BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS`, 10.`BnSurfaceComposer::GET_DISPLAY_STATE`, 11.`BnSurfaceComposer::CAPTURE_DISPLAY`, 12.`BnSurfaceComposer::CAPTURE_LAYERS`, 13.`BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS`, 14.`BnSurfaceComposer::GET_ANIMATION_FRAME_STATS`, 15.`BnSurfaceComposer::SET_POWER_MODE`, 16.`BnSurfaceComposer::GET_DISPLAY_STATS`, 17.`BnSurfaceComposer::SET_ACTIVE_COLOR_MODE`, 18.`BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS`, 19.`BnSurfaceComposer::INJECT_VSYNC`, 20.`BnSurfaceComposer::GET_LAYER_DEBUG_INFO`, 21.`BnSurfaceComposer::GET_COMPOSITION_PREFERENCE`, 22.`BnSurfaceComposer::GET_COLOR_MANAGEMENT`, 23.`BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES`, 24.`BnSurfaceComposer::SET_DISPLAY_CONTENT_SAMPLING_ENABLED`, 25.`BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLE`, 26.`BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT`, 27.`BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY`, 28.`BnSurfaceComposer::GET_DISPLAY_NATIVE_PRIMARIES`, 29.`BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS`, 30.`BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER`, 31.`BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER`, 32.`BnSurfaceComposer::SET_DESIRED_DISPLAY_MODE_SPECS`, 33.`BnSurfaceComposer::GET_DESIRED_DISPLAY_MODE_SPECS`, 34.`BnSurfaceComposer::GET_DISPLAY_BRIGHTNESS_SUPPORT`, 35.`BnSurfaceComposer::SET_DISPLAY_BRIGHTNESS`, 36.`BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID`, 37.`BnSurfaceComposer::NOTIFY_POWER_BOOST`, 38.`BnSurfaceComposer::SET_GLOBAL_SHADOW_SETTINGS`, 39.`BnSurfaceComposer::SET_AUTO_LOW_LATENCY_MODE`, 40.`BnSurfaceComposer::SET_GAME_CONTENT_TYPE`, 41.`BnSurfaceComposer::SET_FRAME_RATE`, 42.`BnSurfaceComposer::ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN`, 43.`BnSurfaceComposer::SET_FRAME_TIMELINE_INFO`, 44.`BnSurfaceComposer::ADD_TRANSACTION_TRACE_LISTENER`, 45.`BnSurfaceComposer::GET_GPU_CONTEXT_PRIORITY`, 46.`BnSurfaceComposer::GET_MAX_ACQUIRED_BUFFER_COUNT`, 47.`BnSurfaceComposer::GET_DYNAMIC_DISPLAY_INFO`, 48.`BnSurfaceComposer::ADD_FPS_LISTENER`, 49.`BnSurfaceComposer::REMOVE_FPS_LISTENER`, 50.`BnSurfaceComposer::OVERRIDE_HDR_TYPES`, 51.`BnSurfaceComposer::ADD_HDR_LAYER_INFO_LISTENER`, 52.`BnSurfaceComposer::REMOVE_HDR_LAYER_INFO_LISTENER`, 53.`BnSurfaceComposer::ON_PULL_ATOM`, 54.`BnSurfaceComposer::ADD_TUNNEL_MODE_ENABLED_LISTENER`, 55.`BnSurfaceComposer::REMOVE_TUNNEL_MODE_ENABLED_LISTENER` | Value obtained from FuzzedDataProvider|
+|`boostId`| 0.`hardware::power::Boost::INTERACTION`, 1.`hardware::power::Boost::DISPLAY_UPDATE_IMMINENT`, 2.`hardware::power::Boost::ML_ACC`, 3.`hardware::power::Boost::AUDIO_LAUNCH`, 4.`hardware::power::Boost::CAMERA_LAUNCH`, 5.`hardware::power::Boost::CAMERA_SHOT` |Value obtained from FuzzedDataProvider|
+|`vsyncSource`| 0.`ISurfaceComposer::eVsyncSourceApp`, 1.`ISurfaceComposer::eVsyncSourceSurfaceFlinger`, |Value obtained from FuzzedDataProvider|
+|`eventRegistration`| 0.`ISurfaceComposer::EventRegistration::modeChanged`, 1.`ISurfaceComposer::EventRegistration::frameRateOverride` |Value obtained from FuzzedDataProvider|
+|`frameRateCompatibility`| 0.`ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT`, 1.`ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE` |Value obtained from FuzzedDataProvider|
+|`changeFrameRateStrategy`| 0.`ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS`, 1.`ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS` |Value obtained from FuzzedDataProvider|
+|`hdrTypes`| 0.`ui::Hdr::DOLBY_VISION`, 1.`ui::Hdr::HDR10`, 2.`ui::Hdr::HLG`, 3.`ui::Hdr::HDR10_PLUS` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) libgui_surfaceComposer_fuzzer
+```
+2. Run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/libgui_surfaceComposer_fuzzer/libgui_surfaceComposer_fuzzer
+```
+
+# <a name="libgui_surfaceComposerClient_fuzzer"></a> Fuzzer for SurfaceComposerClient
+
+SurfaceComposerClient supports the following data sources:
+1. SurfaceWidth (parameter name:`width`)
+2. SurfaceHeight (parameter name:`height`)
+3. TransactionStateFlags (parameter name:`flags`)
+4. TransformHint (parameter name:`outTransformHint`)
+5. SurfacePixelFormat (parameter name:`format`)
+6. LayerId (parameter name:`outLayerId`)
+7. SurfaceComposerClientTags (parameter name:`surfaceTag`)
+8. DefaultMode (parameter name:`defaultMode`)
+9. PrimaryRefreshRateMin (parameter name:`primaryRefreshRateMin`)
+10. PrimaryRefreshRateMax (parameter name:`primaryRefreshRateMax`)
+11. AppRefreshRateMin (parameter name:`appRefreshRateMin`)
+12. AppRefreshRateMax (parameter name:`appRefreshRateMax`)
+13. DisplayPowerMode (parameter name:`mode`)
+14. CacheId (parameter name:`cacheId`)
+15. DisplayBrightness (parameter name:`brightness`)
+16. PowerBoostID (parameter name:`boostId`)
+17. AtomId (parameter name:`atomId`)
+18. ComponentMask (parameter name:`componentMask`)
+19. MaxFrames (parameter name:`maxFrames`)
+20. TaskId (parameter name:`taskId`)
+21. Alpha (parameter name:`aplha`)
+22. CornerRadius (parameter name:`cornerRadius`)
+23. BackgroundBlurRadius (parameter name:`backgroundBlurRadius`)
+24. Half3Color (parameter name:`color`)
+25. LayerStack (parameter name:`layerStack`)
+26. Dataspace (parameter name:`dataspace`)
+27. Api (parameter name:`api`)
+28. Priority (parameter name:`priority`)
+29. TouchableRegionPointX (parameter name:`pointX`)
+30. TouchableRegionPointY (parameter name:`pointY`)
+31. ColorMode (parameter name:`colorMode`)
+32. WindowInfoFlags (parameter name:`flags`)
+33. WindowInfoTransformOrientation (parameter name:`transform`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`surfaceTag`| 0.`Tag::CREATE_SURFACE`, 1.`Tag::CREATE_WITH_SURFACE_PARENT`, 2.`Tag::CLEAR_LAYER_FRAME_STATS`, 3.`Tag::GET_LAYER_FRAME_STATS`, 4.`Tag::MIRROR_SURFACE`, 5.`Tag::LAST` |Value obtained from FuzzedDataProvider|
+|`mode`| 0.`gui::TouchOcclusionMode::BLOCK_UNTRUSTED`, 1.`gui::TouchOcclusionMode::USE_OPACITY`, 2.`gui::TouchOcclusionMode::ALLOW` |Value obtained from FuzzedDataProvider|
+|`boostId`| 0.`hardware::power::Boost::INTERACTION`, 1.`hardware::power::Boost::DISPLAY_UPDATE_IMMINENT`, 2.`hardware::power::Boost::ML_ACC`, 3.`hardware::power::Boost::AUDIO_LAUNCH`, 4.`hardware::power::Boost::CAMERA_LAUNCH`, 5.`hardware::power::Boost::CAMERA_SHOT` |Value obtained from FuzzedDataProvider|
+|`colorMode`|0.`ui::ColorMode::NATIVE`, 1.`ui::ColorMode::STANDARD_BT601_625`, 2.`ui::ColorMode::STANDARD_BT601_625_UNADJUSTED`, 3.`ui::ColorMode::STANDARD_BT601_525`, 4.`ui::ColorMode::STANDARD_BT601_525_UNADJUSTED`, 5.`ui::ColorMode::STANDARD_BT709`, 6.`ui::ColorMode::DCI_P3`, 7.`ui::ColorMode::SRGB`, 8.`ui::ColorMode::ADOBE_RGB`, 9.`ui::ColorMode::DISPLAY_P3`, 10.`ui::ColorMode::BT2020`, 11.`ui::ColorMode::BT2100_PQ`, 12.`ui::ColorMode::BT2100_HLG`, 13.`ui::ColorMode::DISPLAY_BT2020` |Value obtained from FuzzedDataProvider|
+|`flags`|0 .`gui::WindowInfo::Flag::ALLOW_LOCK_WHILE_SCREEN_ON`, 1.`gui::WindowInfo::Flag::DIM_BEHIND`, 2.`gui::WindowInfo::Flag::BLUR_BEHIND`, 3.`gui::WindowInfo::Flag::NOT_FOCUSABLE`, 4.`gui::WindowInfo::Flag::NOT_TOUCHABLE`, 5.`gui::WindowInfo::Flag::NOT_TOUCH_MODAL`, 6.`gui::WindowInfo::Flag::TOUCHABLE_WHEN_WAKING`, 7.`gui::WindowInfo::Flag::KEEP_SCREEN_ON`, 8.`gui::WindowInfo::Flag::LAYOUT_IN_SCREEN`, 9.`gui::WindowInfo::Flag::LAYOUT_NO_LIMITS`, 10.`gui::WindowInfo::Flag::FULLSCREEN`, 11.`gui::WindowInfo::Flag::FORCE_NOT_FULLSCREEN`, 12.`gui::WindowInfo::Flag::DITHER`, 13.`gui::WindowInfo::Flag::SECURE`, 14.`gui::WindowInfo::Flag::SCALED`, 15.`gui::WindowInfo::Flag::IGNORE_CHEEK_PRESSES`, 16.`gui::WindowInfo::Flag::LAYOUT_INSET_DECOR`, 17.`gui::WindowInfo::Flag::ALT_FOCUSABLE_IM`, 18.`gui::WindowInfo::Flag::WATCH_OUTSIDE_TOUCH`, 19.`gui::WindowInfo::Flag::SHOW_WHEN_LOCKED`, 20.`gui::WindowInfo::Flag::SHOW_WALLPAPER`, 21.`gui::WindowInfo::Flag::TURN_SCREEN_ON`, 22.`gui::WindowInfo::Flag::DISMISS_KEYGUARD`, 23.`gui::WindowInfo::Flag::SPLIT_TOUCH`, 24.`gui::WindowInfo::Flag::HARDWARE_ACCELERATED`, 25.`gui::WindowInfo::Flag::LAYOUT_IN_OVERSCAN`, 26.`gui::WindowInfo::Flag::TRANSLUCENT_STATUS`, 27.`gui::WindowInfo::Flag::TRANSLUCENT_NAVIGATION`, 28.`gui::WindowInfo::Flag::LOCAL_FOCUS_MODE`, 29.`gui::WindowInfo::Flag::SLIPPERY`, 30.`gui::WindowInfo::Flag::LAYOUT_ATTACHED_IN_DECOR`, 31.`gui::WindowInfo::Flag::DRAWS_SYSTEM_BAR_BACKGROUNDS`, |Value obtained from FuzzedDataProvider|
+|`dataspace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider|
+|`transform`| 0.`ui::Transform::ROT_0`, 1.`ui::Transform::FLIP_H`, 2.`ui::Transform::FLIP_V`, 3.`ui::Transform::ROT_90`, 4.`ui::Transform::ROT_180`, 5.`ui::Transform::ROT_270` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) libgui_surfaceComposerClient_fuzzer
+```
+2. To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/libgui_surfaceComposerClient_fuzzer/libgui_surfaceComposerClient_fuzzer
+```
+
+# <a name="libgui_parcelable_fuzzer"></a> Fuzzer for Libgui_Parcelable
+
+Libgui_Parcelable supports the following parameters:
+1. LayerMetadataKey (parameter name:`key`)
+2. Dataspace (parameter name:`mDataspace`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`key`| 0.`view::LayerMetadataKey::METADATA_OWNER_UID`, 1.`view::LayerMetadataKey::METADATA_WINDOW_TYPE`, 2.`view::LayerMetadataKey::METADATA_TASK_ID`, 3.`view::LayerMetadataKey::METADATA_MOUSE_CURSOR`, 4.`view::LayerMetadataKey::METADATA_ACCESSIBILITY_ID`, 5.`view::LayerMetadataKey::METADATA_OWNER_PID`, 6.`view::LayerMetadataKey::METADATA_DEQUEUE_TIME`, 7.`view::LayerMetadataKey::METADATA_GAME_MODE`, |Value obtained from FuzzedDataProvider|
+|`mDataSpace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) libgui_fuzzer
+```
+2. Run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/libgui_fuzzer/libgui_fuzzer
+```
+
+# <a name="libgui_bufferQueue_fuzzer"></a> Fuzzer for BufferQueue
+
+BufferQueue supports the following parameters:
+1. SurfaceWidth (parameter name:`width`)
+2. SurfaceHeight (parameter name:`height`)
+3. TransactionStateFlags (parameter name:`flags`)
+4. TransformHint (parameter name:`outTransformHint`)
+5. SurfacePixelFormat (parameter name:`format`)
+6. LayerId (parameter name:`layerId`)
+7. BufferId (parameter name:`bufferId`)
+8. FrameNumber (parameter name:`frameNumber`)
+9. FrameRate (parameter name:`frameRate`)
+10. Compatability (parameter name:`compatability`)
+11. LatchTime (parameter name:`latchTime`)
+12. AcquireTime (parameter name:`acquireTime`)
+13. RefreshTime (parameter name:`refreshTime`)
+14. DequeueTime (parameter name:`dequeueTime`)
+15. Slot (parameter name:`slot`)
+16. MaxBuffers (parameter name:`maxBuffers`)
+17. GenerationNumber (parameter name:`generationNumber`)
+18. Api (parameter name:`api`)
+19. Usage (parameter name:`usage`)
+20. MaxFrameNumber (parameter name:`maxFrameNumber`)
+21. BufferCount (parameter name:`bufferCount`)
+22. MaxAcquredBufferCount (parameter name:`maxAcquredBufferCount`)
+23. Status (parameter name:`status`)
+24. ApiConnection (parameter name:`apiConnection`)
+25. Dataspace (parameter name:`dataspace`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`status`| 0.`OK`, 1.`NO_MEMORY`, 2.`NO_INIT`, 3.`BAD_VALUE`, 4.`DEAD_OBJECT`, 5.`INVALID_OPERATION`, 6.`TIMED_OUT`, 7.`WOULD_BLOCK`, 8.`UNKNOWN_ERROR`, 9.`ALREADY_EXISTS`, |Value obtained from FuzzedDataProvider|
+|`apiConnection`| 0.`BufferQueueCore::CURRENTLY_CONNECTED_API`, 1.`BufferQueueCore::NO_CONNECTED_API`, 2.`NATIVE_WINDOW_API_EGL`, 3.`NATIVE_WINDOW_API_CPU`, 4.`NATIVE_WINDOW_API_MEDIA`, 5.`NATIVE_WINDOW_API_CAMERA`, |Value obtained from FuzzedDataProvider|
+|`dataspace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) libgui_bufferQueue_fuzzer
+```
+2. To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/libgui_bufferQueue_fuzzer/libgui_bufferQueue_fuzzer
+```
+
+# <a name="libgui_consumer_fuzzer"></a> Fuzzer for Libgui_Consumer
+
+Libgui_Consumer supports the following parameters:
+1. GraphicWidth (parameter name:`graphicWidth`)
+2. GraphicHeight (parameter name:`graphicHeight`)
+4. TransformHint (parameter name:`outTransformHint`)
+5. GraphicPixelFormat (parameter name:`format`)
+6. Usage (parameter name:`usage`)
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) libgui_consumer_fuzzer
+```
+2. Run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/libgui_consumer_fuzzer/libgui_consumer_fuzzer
+```
+
+# <a name="libgui_displayEvent_fuzzer"></a> Fuzzer for LibGui_DisplayEvent
+
+LibGui_DisplayEvent supports the following parameters:
+1. DisplayEventType (parameter name:`type`)
+2. Events (parameter name:`events`)
+3. VsyncSource (parameter name:`vsyncSource`)
+4. EventRegistrationFlags (parameter name:`flags`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`vsyncSource`| 0.`ISurfaceComposer::eVsyncSourceApp`, 1.`ISurfaceComposer::eVsyncSourceSurfaceFlinger`, |Value obtained from FuzzedDataProvider|
+|`flags`| 0.`ISurfaceComposer::EventRegistration::modeChanged`, 1.`ISurfaceComposer::EventRegistration::frameRateOverride`, |Value obtained from FuzzedDataProvider|
+|`type`| 0.`DisplayEventReceiver::DISPLAY_EVENT_NULL`, 1.`DisplayEventReceiver::DISPLAY_EVENT_VSYNC`, 2.`DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG`, 3.`DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE`, 4.`DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE`, 5.`DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH`, |Value obtained from FuzzedDataProvider|
+|`events`| 0.`Looper::EVENT_INPUT`, 1.`Looper::EVENT_OUTPUT`, 2.`Looper::EVENT_ERROR`, 3.`Looper::EVENT_HANGUP`, 4.`Looper::EVENT_INVALID`, |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) libgui_displayEvent_fuzzer
+```
+2. Run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/libgui_displayEvent_fuzzer/libgui_displayEvent_fuzzer
+```
diff --git a/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp b/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
new file mode 100644
index 0000000..c97770b
--- /dev/null
+++ b/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
@@ -0,0 +1,388 @@
+/*
+ * 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.
+ */
+#include <gui/BufferQueueConsumer.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <system/window.h>
+
+#include <libgui_fuzzer_utils.h>
+
+using namespace android;
+using namespace hardware::graphics::bufferqueue;
+using namespace V1_0::utils;
+using namespace V2_0::utils;
+
+constexpr int32_t kMaxBytes = 256;
+
+constexpr int32_t kError[] = {
+        OK,        NO_MEMORY,   NO_INIT,       BAD_VALUE,      DEAD_OBJECT, INVALID_OPERATION,
+        TIMED_OUT, WOULD_BLOCK, UNKNOWN_ERROR, ALREADY_EXISTS,
+};
+
+constexpr int32_t kAPIConnection[] = {
+        BufferQueueCore::CURRENTLY_CONNECTED_API,
+        BufferQueueCore::NO_CONNECTED_API,
+        NATIVE_WINDOW_API_EGL,
+        NATIVE_WINDOW_API_CPU,
+        NATIVE_WINDOW_API_MEDIA,
+        NATIVE_WINDOW_API_CAMERA,
+};
+
+class BufferQueueFuzzer {
+public:
+    BufferQueueFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+
+private:
+    void invokeTypes();
+    void invokeH2BGraphicBufferV1();
+    void invokeH2BGraphicBufferV2();
+    void invokeBufferQueueConsumer();
+    void invokeBufferQueueProducer();
+    void invokeBlastBufferQueue();
+    void invokeQuery(sp<BufferQueueProducer>);
+    void invokeQuery(sp<V1_0::utils::H2BGraphicBufferProducer>);
+    void invokeQuery(sp<V2_0::utils::H2BGraphicBufferProducer>);
+    void invokeAcquireBuffer(sp<BufferQueueConsumer>);
+    void invokeOccupancyTracker(sp<BufferQueueConsumer>);
+    sp<SurfaceControl> makeSurfaceControl();
+    sp<BLASTBufferQueue> makeBLASTBufferQueue(sp<SurfaceControl>);
+
+    FuzzedDataProvider mFdp;
+};
+
+class ManageResourceHandle {
+public:
+    ManageResourceHandle(FuzzedDataProvider* fdp) {
+        mNativeHandle = native_handle_create(0 /*numFds*/, 1 /*numInts*/);
+        mShouldOwn = fdp->ConsumeBool();
+        mStream = NativeHandle::create(mNativeHandle, mShouldOwn);
+    }
+    ~ManageResourceHandle() {
+        if (!mShouldOwn) {
+            native_handle_close(mNativeHandle);
+            native_handle_delete(mNativeHandle);
+        }
+    }
+    sp<NativeHandle> getStream() { return mStream; }
+
+private:
+    bool mShouldOwn;
+    sp<NativeHandle> mStream;
+    native_handle_t* mNativeHandle;
+};
+
+sp<SurfaceControl> BufferQueueFuzzer::makeSurfaceControl() {
+    sp<IBinder> handle;
+    const sp<FakeBnSurfaceComposerClient> testClient(new FakeBnSurfaceComposerClient());
+    sp<SurfaceComposerClient> client = new SurfaceComposerClient(testClient);
+    sp<BnGraphicBufferProducer> producer;
+    return sp<SurfaceControl>::make(client, handle, mFdp.ConsumeIntegral<int32_t>(),
+                                    mFdp.ConsumeIntegral<uint32_t>(),
+                                    mFdp.ConsumeIntegral<uint32_t>(),
+                                    mFdp.ConsumeIntegral<int32_t>(),
+                                    mFdp.ConsumeIntegral<uint32_t>(),
+                                    mFdp.ConsumeIntegral<uint32_t>());
+}
+
+sp<BLASTBufferQueue> BufferQueueFuzzer::makeBLASTBufferQueue(sp<SurfaceControl> surface) {
+    return sp<BLASTBufferQueue>::make(mFdp.ConsumeRandomLengthString(kMaxBytes), surface,
+                                      mFdp.ConsumeIntegral<uint32_t>(),
+                                      mFdp.ConsumeIntegral<uint32_t>(),
+                                      mFdp.ConsumeIntegral<int32_t>());
+}
+
+void BufferQueueFuzzer::invokeBlastBufferQueue() {
+    sp<SurfaceControl> surface = makeSurfaceControl();
+    sp<BLASTBufferQueue> queue = makeBLASTBufferQueue(surface);
+
+    BufferItem item;
+    queue->onFrameAvailable(item);
+    queue->onFrameReplaced(item);
+    uint64_t bufferId = mFdp.ConsumeIntegral<uint64_t>();
+    queue->onFrameDequeued(bufferId);
+    queue->onFrameCancelled(bufferId);
+
+    SurfaceComposerClient::Transaction next;
+    uint64_t frameNumber = mFdp.ConsumeIntegral<uint64_t>();
+    queue->mergeWithNextTransaction(&next, frameNumber);
+    queue->applyPendingTransactions(frameNumber);
+
+    queue->update(surface, mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
+                  mFdp.ConsumeIntegral<int32_t>());
+    queue->setFrameRate(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeIntegral<int8_t>(),
+                        mFdp.ConsumeBool() /*shouldBeSeamless*/);
+    FrameTimelineInfo info;
+    queue->setFrameTimelineInfo(info);
+
+    ManageResourceHandle handle(&mFdp);
+    queue->setSidebandStream(handle.getStream());
+
+    queue->getLastTransformHint();
+    queue->getLastAcquiredFrameNum();
+
+    CompositorTiming compTiming;
+    sp<Fence> previousFence = new Fence(memfd_create("pfd", MFD_ALLOW_SEALING));
+    sp<Fence> gpuFence = new Fence(memfd_create("gfd", MFD_ALLOW_SEALING));
+    FrameEventHistoryStats frameStats(frameNumber, gpuFence, compTiming,
+                                      mFdp.ConsumeIntegral<int64_t>(),
+                                      mFdp.ConsumeIntegral<int64_t>());
+    std::vector<SurfaceControlStats> stats;
+    sp<Fence> presentFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
+    SurfaceControlStats controlStats(surface, mFdp.ConsumeIntegral<int64_t>(),
+                                     mFdp.ConsumeIntegral<int64_t>(), presentFence, previousFence,
+                                     mFdp.ConsumeIntegral<uint32_t>(), frameStats);
+    stats.push_back(controlStats);
+}
+
+void BufferQueueFuzzer::invokeQuery(sp<BufferQueueProducer> producer) {
+    int32_t value;
+    producer->query(mFdp.ConsumeIntegral<int32_t>(), &value);
+}
+
+void BufferQueueFuzzer::invokeQuery(sp<V1_0::utils::H2BGraphicBufferProducer> producer) {
+    int32_t value;
+    producer->query(mFdp.ConsumeIntegral<int32_t>(), &value);
+}
+
+void BufferQueueFuzzer::invokeQuery(sp<V2_0::utils::H2BGraphicBufferProducer> producer) {
+    int32_t value;
+    producer->query(mFdp.ConsumeIntegral<int32_t>(), &value);
+}
+
+void BufferQueueFuzzer::invokeBufferQueueProducer() {
+    sp<BufferQueueCore> core(new BufferQueueCore());
+    sp<BufferQueueProducer> producer(new BufferQueueProducer(core));
+    const sp<android::IProducerListener> listener;
+    android::IGraphicBufferProducer::QueueBufferOutput output;
+    uint32_t api = mFdp.ConsumeIntegral<uint32_t>();
+    producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output);
+
+    sp<GraphicBuffer> buffer;
+    int32_t slot = mFdp.ConsumeIntegral<int32_t>();
+    uint32_t maxBuffers = mFdp.ConsumeIntegral<uint32_t>();
+    producer->requestBuffer(slot, &buffer);
+    producer->setMaxDequeuedBufferCount(maxBuffers);
+    producer->setAsyncMode(mFdp.ConsumeBool() /*async*/);
+
+    android::IGraphicBufferProducer::QueueBufferInput input;
+    producer->attachBuffer(&slot, buffer);
+    producer->queueBuffer(slot, input, &output);
+
+    int32_t format = mFdp.ConsumeIntegral<int32_t>();
+    uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
+    uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
+    uint64_t usage = mFdp.ConsumeIntegral<uint64_t>();
+    uint64_t outBufferAge;
+    FrameEventHistoryDelta outTimestamps;
+    sp<android::Fence> fence;
+    producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge,
+                            &outTimestamps);
+    producer->detachBuffer(slot);
+    producer->detachNextBuffer(&buffer, &fence);
+    producer->cancelBuffer(slot, fence);
+
+    invokeQuery(producer);
+
+    ManageResourceHandle handle(&mFdp);
+    producer->setSidebandStream(handle.getStream());
+
+    producer->allocateBuffers(width, height, format, usage);
+    producer->allowAllocation(mFdp.ConsumeBool() /*allow*/);
+    producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/);
+    producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/);
+    producer->setLegacyBufferDrop(mFdp.ConsumeBool() /*drop*/);
+    producer->setAutoPrerotation(mFdp.ConsumeBool() /*autoPrerotation*/);
+
+    producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>());
+    producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>());
+    producer->disconnect(api);
+}
+
+void BufferQueueFuzzer::invokeAcquireBuffer(sp<BufferQueueConsumer> consumer) {
+    BufferItem item;
+    consumer->acquireBuffer(&item, mFdp.ConsumeIntegral<uint32_t>(),
+                            mFdp.ConsumeIntegral<uint64_t>());
+}
+
+void BufferQueueFuzzer::invokeOccupancyTracker(sp<BufferQueueConsumer> consumer) {
+    String8 outResult;
+    String8 prefix((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
+    consumer->dumpState(prefix, &outResult);
+
+    std::vector<OccupancyTracker::Segment> outHistory;
+    consumer->getOccupancyHistory(mFdp.ConsumeBool() /*forceFlush*/, &outHistory);
+}
+
+void BufferQueueFuzzer::invokeBufferQueueConsumer() {
+    sp<BufferQueueCore> core(new BufferQueueCore());
+    sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
+    sp<android::IConsumerListener> listener;
+    consumer->consumerConnect(listener, mFdp.ConsumeBool() /*controlledByApp*/);
+    invokeAcquireBuffer(consumer);
+
+    int32_t slot = mFdp.ConsumeIntegral<int32_t>();
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
+                              mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
+                              mFdp.ConsumeIntegral<uint64_t>());
+    consumer->attachBuffer(&slot, buffer);
+    consumer->detachBuffer(slot);
+
+    consumer->setDefaultBufferSize(mFdp.ConsumeIntegral<uint32_t>(),
+                                   mFdp.ConsumeIntegral<uint32_t>());
+    consumer->setMaxBufferCount(mFdp.ConsumeIntegral<int32_t>());
+    consumer->setMaxAcquiredBufferCount(mFdp.ConsumeIntegral<int32_t>());
+
+    String8 name((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
+    consumer->setConsumerName(name);
+    consumer->setDefaultBufferFormat(mFdp.ConsumeIntegral<int32_t>());
+    android_dataspace dataspace =
+            static_cast<android_dataspace>(mFdp.PickValueInArray(kDataspaces));
+    consumer->setDefaultBufferDataSpace(dataspace);
+
+    consumer->setTransformHint(mFdp.ConsumeIntegral<uint32_t>());
+    consumer->setConsumerUsageBits(mFdp.ConsumeIntegral<uint64_t>());
+    consumer->setConsumerIsProtected(mFdp.ConsumeBool() /*isProtected*/);
+    invokeOccupancyTracker(consumer);
+
+    sp<Fence> releaseFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
+    consumer->releaseBuffer(mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint64_t>(),
+                            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence);
+    consumer->consumerDisconnect();
+}
+
+void BufferQueueFuzzer::invokeTypes() {
+    HStatus hStatus;
+    int32_t status = mFdp.PickValueInArray(kError);
+    bool bufferNeedsReallocation = mFdp.ConsumeBool();
+    bool releaseAllBuffers = mFdp.ConsumeBool();
+    b2h(status, &hStatus, &bufferNeedsReallocation, &releaseAllBuffers);
+    h2b(hStatus, &status);
+
+    HConnectionType type;
+    int32_t apiConnection = mFdp.PickValueInArray(kAPIConnection);
+    b2h(apiConnection, &type);
+    h2b(type, &apiConnection);
+}
+
+void BufferQueueFuzzer::invokeH2BGraphicBufferV1() {
+    sp<V1_0::utils::H2BGraphicBufferProducer> producer(
+            new V1_0::utils::H2BGraphicBufferProducer(new FakeGraphicBufferProducerV1()));
+    const sp<android::IProducerListener> listener;
+    android::IGraphicBufferProducer::QueueBufferOutput output;
+    uint32_t api = mFdp.ConsumeIntegral<uint32_t>();
+    producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output);
+
+    sp<GraphicBuffer> buffer;
+    int32_t slot = mFdp.ConsumeIntegral<int32_t>();
+    producer->requestBuffer(slot, &buffer);
+    producer->setMaxDequeuedBufferCount(mFdp.ConsumeIntegral<int32_t>());
+    producer->setAsyncMode(mFdp.ConsumeBool());
+
+    android::IGraphicBufferProducer::QueueBufferInput input;
+    input.fence = new Fence(memfd_create("ffd", MFD_ALLOW_SEALING));
+    producer->attachBuffer(&slot, buffer);
+    producer->queueBuffer(slot, input, &output);
+
+    int32_t format = mFdp.ConsumeIntegral<int32_t>();
+    uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
+    uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
+    uint64_t usage = mFdp.ConsumeIntegral<uint64_t>();
+    uint64_t outBufferAge;
+    FrameEventHistoryDelta outTimestamps;
+    sp<android::Fence> fence;
+    producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge,
+                            &outTimestamps);
+    producer->detachBuffer(slot);
+    producer->cancelBuffer(slot, fence);
+
+    invokeQuery(producer);
+
+    ManageResourceHandle handle(&mFdp);
+    producer->setSidebandStream(handle.getStream());
+
+    producer->allocateBuffers(width, height, format, usage);
+    producer->allowAllocation(mFdp.ConsumeBool() /*allow*/);
+    producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/);
+    producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/);
+
+    producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>());
+    producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>());
+    producer->disconnect(api);
+}
+
+void BufferQueueFuzzer::invokeH2BGraphicBufferV2() {
+    sp<V2_0::utils::H2BGraphicBufferProducer> producer(
+            new V2_0::utils::H2BGraphicBufferProducer(new FakeGraphicBufferProducerV2()));
+    const sp<android::IProducerListener> listener;
+    android::IGraphicBufferProducer::QueueBufferOutput output;
+    uint32_t api = mFdp.ConsumeIntegral<uint32_t>();
+    producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output);
+
+    sp<GraphicBuffer> buffer;
+    int32_t slot = mFdp.ConsumeIntegral<int32_t>();
+    producer->requestBuffer(slot, &buffer);
+    producer->setMaxDequeuedBufferCount(mFdp.ConsumeIntegral<uint32_t>());
+    producer->setAsyncMode(mFdp.ConsumeBool());
+
+    android::IGraphicBufferProducer::QueueBufferInput input;
+    input.fence = new Fence(memfd_create("ffd", MFD_ALLOW_SEALING));
+    producer->attachBuffer(&slot, buffer);
+    producer->queueBuffer(slot, input, &output);
+
+    int32_t format = mFdp.ConsumeIntegral<int32_t>();
+    uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
+    uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
+    uint64_t usage = mFdp.ConsumeIntegral<uint64_t>();
+    uint64_t outBufferAge;
+    FrameEventHistoryDelta outTimestamps;
+    sp<android::Fence> fence;
+    producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge,
+                            &outTimestamps);
+    producer->detachBuffer(slot);
+    producer->cancelBuffer(slot, fence);
+
+    invokeQuery(producer);
+
+    ManageResourceHandle handle(&mFdp);
+    producer->setSidebandStream(handle.getStream());
+
+    producer->allocateBuffers(width, height, format, usage);
+    producer->allowAllocation(mFdp.ConsumeBool() /*allow*/);
+    producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/);
+    producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/);
+
+    producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>());
+    producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>());
+    producer->disconnect(api);
+}
+
+void BufferQueueFuzzer::process() {
+    invokeBlastBufferQueue();
+    invokeH2BGraphicBufferV1();
+    invokeH2BGraphicBufferV2();
+    invokeTypes();
+    invokeBufferQueueConsumer();
+    invokeBufferQueueProducer();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    BufferQueueFuzzer bufferQueueFuzzer(data, size);
+    bufferQueueFuzzer.process();
+    return 0;
+}
diff --git a/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp b/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp
new file mode 100644
index 0000000..24a046d
--- /dev/null
+++ b/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+#include <gui/BufferQueueConsumer.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/GLConsumer.h>
+#include <libgui_fuzzer_utils.h>
+
+using namespace android;
+
+constexpr int32_t kMinBuffer = 0;
+constexpr int32_t kMaxBuffer = 100000;
+
+class ConsumerFuzzer {
+public:
+    ConsumerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+
+private:
+    FuzzedDataProvider mFdp;
+};
+
+void ConsumerFuzzer::process() {
+    sp<BufferQueueCore> core(new BufferQueueCore());
+    sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
+
+    uint64_t maxBuffers = mFdp.ConsumeIntegralInRange<uint64_t>(kMinBuffer, kMaxBuffer);
+    sp<CpuConsumer> cpu(
+            new CpuConsumer(consumer, maxBuffers, mFdp.ConsumeBool() /*controlledByApp*/));
+    CpuConsumer::LockedBuffer lockBuffer;
+    cpu->lockNextBuffer(&lockBuffer);
+    cpu->unlockBuffer(lockBuffer);
+    cpu->abandon();
+
+    uint32_t tex = mFdp.ConsumeIntegral<uint32_t>();
+    sp<GLConsumer> glComsumer(new GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL,
+                                             mFdp.ConsumeBool() /*useFenceSync*/,
+                                             mFdp.ConsumeBool() /*isControlledByApp*/));
+    sp<Fence> releaseFence = new Fence(memfd_create("rfd", MFD_ALLOW_SEALING));
+    glComsumer->setReleaseFence(releaseFence);
+    glComsumer->updateTexImage();
+    glComsumer->releaseTexImage();
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
+                              mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
+                              mFdp.ConsumeIntegral<uint64_t>());
+    float mtx[16];
+    glComsumer->getTransformMatrix(mtx);
+    glComsumer->computeTransformMatrix(mtx, buffer, getRect(&mFdp),
+                                       mFdp.ConsumeIntegral<uint32_t>(),
+                                       mFdp.ConsumeBool() /*filtering*/);
+    glComsumer->scaleDownCrop(getRect(&mFdp), mFdp.ConsumeIntegral<uint32_t>(),
+                              mFdp.ConsumeIntegral<uint32_t>());
+
+    glComsumer->setDefaultBufferSize(mFdp.ConsumeIntegral<uint32_t>(),
+                                     mFdp.ConsumeIntegral<uint32_t>());
+    glComsumer->setFilteringEnabled(mFdp.ConsumeBool() /*enabled*/);
+
+    glComsumer->setConsumerUsageBits(mFdp.ConsumeIntegral<uint64_t>());
+    glComsumer->attachToContext(tex);
+    glComsumer->abandon();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    ConsumerFuzzer consumerFuzzer(data, size);
+    consumerFuzzer.process();
+    return 0;
+}
diff --git a/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp b/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp
new file mode 100644
index 0000000..6d5ae49
--- /dev/null
+++ b/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#include <android/gui/ISurfaceComposer.h>
+
+#include <libgui_fuzzer_utils.h>
+
+using namespace android;
+
+constexpr gui::ISurfaceComposer::VsyncSource kVsyncSource[] = {
+        gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp,
+        gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger,
+};
+
+constexpr gui::ISurfaceComposer::EventRegistration kEventRegistration[] = {
+        gui::ISurfaceComposer::EventRegistration::modeChanged,
+        gui::ISurfaceComposer::EventRegistration::frameRateOverride,
+};
+
+constexpr uint32_t kDisplayEvent[] = {
+        DisplayEventReceiver::DISPLAY_EVENT_NULL,
+        DisplayEventReceiver::DISPLAY_EVENT_VSYNC,
+        DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
+        DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE,
+        DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
+        DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH,
+};
+
+constexpr int32_t kEvents[] = {
+        Looper::EVENT_INPUT,  Looper::EVENT_OUTPUT,  Looper::EVENT_ERROR,
+        Looper::EVENT_HANGUP, Looper::EVENT_INVALID,
+};
+
+DisplayEventReceiver::Event buildDisplayEvent(FuzzedDataProvider* fdp, uint32_t type,
+                                              DisplayEventReceiver::Event event) {
+    switch (type) {
+        case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: {
+            event.vsync.count = fdp->ConsumeIntegral<uint32_t>();
+            event.vsync.vsyncData.frameInterval = fdp->ConsumeIntegral<uint64_t>();
+            event.vsync.vsyncData.preferredFrameTimelineIndex = fdp->ConsumeIntegral<uint32_t>();
+            for (size_t idx = 0; idx < gui::VsyncEventData::kFrameTimelinesLength; ++idx) {
+                event.vsync.vsyncData.frameTimelines[idx].vsyncId = fdp->ConsumeIntegral<int64_t>();
+                event.vsync.vsyncData.frameTimelines[idx].deadlineTimestamp =
+                        fdp->ConsumeIntegral<uint64_t>();
+                event.vsync.vsyncData.frameTimelines[idx].expectedPresentationTime =
+                        fdp->ConsumeIntegral<uint64_t>();
+            }
+            break;
+
+        }
+        case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: {
+            event.hotplug = DisplayEventReceiver::Event::Hotplug{fdp->ConsumeBool() /*connected*/};
+            break;
+        }
+        case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: {
+            event.modeChange =
+                    DisplayEventReceiver::Event::ModeChange{fdp->ConsumeIntegral<int32_t>(),
+                                                            fdp->ConsumeIntegral<int64_t>()};
+            break;
+        }
+        case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
+        case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH: {
+            event.frameRateOverride =
+                    DisplayEventReceiver::Event::FrameRateOverride{fdp->ConsumeIntegral<uint32_t>(),
+                                                                   fdp->ConsumeFloatingPoint<
+                                                                           float>()};
+            break;
+        }
+    }
+    return event;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+    sp<Looper> looper;
+    sp<FakeDisplayEventDispatcher> dispatcher(
+            new FakeDisplayEventDispatcher(looper, fdp.PickValueInArray(kVsyncSource),
+                                           fdp.PickValueInArray(kEventRegistration)));
+
+    dispatcher->initialize();
+    DisplayEventReceiver::Event event;
+    uint32_t type = fdp.PickValueInArray(kDisplayEvent);
+    PhysicalDisplayId displayId;
+    event.header =
+            DisplayEventReceiver::Event::Header{type, displayId, fdp.ConsumeIntegral<int64_t>()};
+    event = buildDisplayEvent(&fdp, type, event);
+
+    dispatcher->injectEvent(event);
+    dispatcher->handleEvent(0, fdp.PickValueInArray(kEvents), nullptr);
+    return 0;
+}
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
new file mode 100644
index 0000000..d51f685
--- /dev/null
+++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/gui/BnRegionSamplingListener.h>
+#include <android/gui/BnSurfaceComposer.h>
+#include <android/gui/BnSurfaceComposerClient.h>
+#include <android/gui/IDisplayEventConnection.h>
+#include <android/gui/ISurfaceComposerClient.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gmock/gmock.h>
+#include <gui/BLASTBufferQueue.h>
+#include <gui/DisplayEventDispatcher.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/LayerState.h>
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
+#include <ui/fuzzer/FuzzableDataspaces.h>
+
+namespace android {
+
+constexpr uint32_t kOrientation[] = {
+        ui::Transform::ROT_0,  ui::Transform::FLIP_H,  ui::Transform::FLIP_V,
+        ui::Transform::ROT_90, ui::Transform::ROT_180, ui::Transform::ROT_270,
+};
+
+Rect getRect(FuzzedDataProvider* fdp) {
+    const int32_t left = fdp->ConsumeIntegral<int32_t>();
+    const int32_t top = fdp->ConsumeIntegral<int32_t>();
+    const int32_t right = fdp->ConsumeIntegral<int32_t>();
+    const int32_t bottom = fdp->ConsumeIntegral<int32_t>();
+    return Rect(left, top, right, bottom);
+}
+
+gui::DisplayBrightness getBrightness(FuzzedDataProvider* fdp) {
+    static constexpr float kMinBrightness = 0;
+    static constexpr float kMaxBrightness = 1;
+    gui::DisplayBrightness brightness;
+    brightness.sdrWhitePoint =
+            fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness);
+    brightness.sdrWhitePointNits =
+            fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness);
+    brightness.displayBrightness =
+            fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness);
+    brightness.displayBrightnessNits =
+            fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness);
+    return brightness;
+}
+
+class FakeBnSurfaceComposer : public gui::BnSurfaceComposer {
+public:
+    MOCK_METHOD(binder::Status, bootFinished, (), (override));
+    MOCK_METHOD(binder::Status, createDisplayEventConnection,
+                (gui::ISurfaceComposer::VsyncSource, gui::ISurfaceComposer::EventRegistration,
+                 sp<gui::IDisplayEventConnection>*),
+                (override));
+    MOCK_METHOD(binder::Status, createConnection, (sp<gui::ISurfaceComposerClient>*), (override));
+    MOCK_METHOD(binder::Status, createDisplay, (const std::string&, bool, sp<IBinder>*),
+                (override));
+    MOCK_METHOD(binder::Status, destroyDisplay, (const sp<IBinder>&), (override));
+    MOCK_METHOD(binder::Status, getPhysicalDisplayIds, (std::vector<int64_t>*), (override));
+    MOCK_METHOD(binder::Status, getPhysicalDisplayToken, (int64_t, sp<IBinder>*), (override));
+    MOCK_METHOD(binder::Status, setPowerMode, (const sp<IBinder>&, int), (override));
+    MOCK_METHOD(binder::Status, getSupportedFrameTimestamps, (std::vector<FrameEvent>*),
+                (override));
+    MOCK_METHOD(binder::Status, getDisplayStats, (const sp<IBinder>&, gui::DisplayStatInfo*),
+                (override));
+    MOCK_METHOD(binder::Status, getDisplayState, (const sp<IBinder>&, gui::DisplayState*),
+                (override));
+    MOCK_METHOD(binder::Status, getStaticDisplayInfo, (const sp<IBinder>&, gui::StaticDisplayInfo*),
+                (override));
+    MOCK_METHOD(binder::Status, getDynamicDisplayInfo,
+                (const sp<IBinder>&, gui::DynamicDisplayInfo*), (override));
+    MOCK_METHOD(binder::Status, getDisplayNativePrimaries,
+                (const sp<IBinder>&, gui::DisplayPrimaries*), (override));
+    MOCK_METHOD(binder::Status, setActiveColorMode, (const sp<IBinder>&, int), (override));
+    MOCK_METHOD(binder::Status, setBootDisplayMode, (const sp<IBinder>&, int), (override));
+    MOCK_METHOD(binder::Status, clearBootDisplayMode, (const sp<IBinder>&), (override));
+    MOCK_METHOD(binder::Status, getBootDisplayModeSupport, (bool*), (override));
+    MOCK_METHOD(binder::Status, setAutoLowLatencyMode, (const sp<IBinder>&, bool), (override));
+    MOCK_METHOD(binder::Status, setGameContentType, (const sp<IBinder>&, bool), (override));
+    MOCK_METHOD(binder::Status, captureDisplay,
+                (const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&), (override));
+    MOCK_METHOD(binder::Status, captureDisplayById, (int64_t, const sp<IScreenCaptureListener>&),
+                (override));
+    MOCK_METHOD(binder::Status, captureLayers,
+                (const LayerCaptureArgs&, const sp<IScreenCaptureListener>&), (override));
+    MOCK_METHOD(binder::Status, clearAnimationFrameStats, (), (override));
+    MOCK_METHOD(binder::Status, getAnimationFrameStats, (gui::FrameStats*), (override));
+    MOCK_METHOD(binder::Status, overrideHdrTypes, (const sp<IBinder>&, const std::vector<int32_t>&),
+                (override));
+    MOCK_METHOD(binder::Status, onPullAtom, (int32_t, gui::PullAtomData*), (override));
+    MOCK_METHOD(binder::Status, enableVSyncInjections, (bool), (override));
+    MOCK_METHOD(binder::Status, injectVSync, (int64_t), (override));
+    MOCK_METHOD(binder::Status, getLayerDebugInfo, (std::vector<gui::LayerDebugInfo>*), (override));
+    MOCK_METHOD(binder::Status, getColorManagement, (bool*), (override));
+    MOCK_METHOD(binder::Status, getCompositionPreference, (gui::CompositionPreference*),
+                (override));
+    MOCK_METHOD(binder::Status, getDisplayedContentSamplingAttributes,
+                (const sp<IBinder>&, gui::ContentSamplingAttributes*), (override));
+    MOCK_METHOD(binder::Status, setDisplayContentSamplingEnabled,
+                (const sp<IBinder>&, bool, int8_t, int64_t), (override));
+    MOCK_METHOD(binder::Status, getDisplayedContentSample,
+                (const sp<IBinder>&, int64_t, int64_t, gui::DisplayedFrameStats*), (override));
+    MOCK_METHOD(binder::Status, getProtectedContentSupport, (bool*), (override));
+    MOCK_METHOD(binder::Status, isWideColorDisplay, (const sp<IBinder>&, bool*), (override));
+    MOCK_METHOD(binder::Status, addRegionSamplingListener,
+                (const gui::ARect&, const sp<IBinder>&, const sp<gui::IRegionSamplingListener>&),
+                (override));
+    MOCK_METHOD(binder::Status, removeRegionSamplingListener,
+                (const sp<gui::IRegionSamplingListener>&), (override));
+    MOCK_METHOD(binder::Status, addFpsListener, (int32_t, const sp<gui::IFpsListener>&),
+                (override));
+    MOCK_METHOD(binder::Status, removeFpsListener, (const sp<gui::IFpsListener>&), (override));
+    MOCK_METHOD(binder::Status, addTunnelModeEnabledListener,
+                (const sp<gui::ITunnelModeEnabledListener>&), (override));
+    MOCK_METHOD(binder::Status, removeTunnelModeEnabledListener,
+                (const sp<gui::ITunnelModeEnabledListener>&), (override));
+    MOCK_METHOD(binder::Status, setDesiredDisplayModeSpecs,
+                (const sp<IBinder>&, int32_t, bool, float, float, float,
+                 float appRequestRefreshRateMax),
+                (override));
+    MOCK_METHOD(binder::Status, getDesiredDisplayModeSpecs,
+                (const sp<IBinder>&, gui::DisplayModeSpecs*), (override));
+    MOCK_METHOD(binder::Status, getDisplayBrightnessSupport, (const sp<IBinder>&, bool*),
+                (override));
+    MOCK_METHOD(binder::Status, setDisplayBrightness,
+                (const sp<IBinder>&, const gui::DisplayBrightness&), (override));
+    MOCK_METHOD(binder::Status, addHdrLayerInfoListener,
+                (const sp<IBinder>&, const sp<gui::IHdrLayerInfoListener>&), (override));
+    MOCK_METHOD(binder::Status, removeHdrLayerInfoListener,
+                (const sp<IBinder>&, const sp<gui::IHdrLayerInfoListener>&), (override));
+    MOCK_METHOD(binder::Status, notifyPowerBoost, (int), (override));
+    MOCK_METHOD(binder::Status, setGlobalShadowSettings,
+                (const gui::Color&, const gui::Color&, float, float, float), (override));
+    MOCK_METHOD(binder::Status, getDisplayDecorationSupport,
+                (const sp<IBinder>&, std::optional<gui::DisplayDecorationSupport>*), (override));
+    MOCK_METHOD(binder::Status, setOverrideFrameRate, (int32_t, float), (override));
+    MOCK_METHOD(binder::Status, addTransactionTraceListener,
+                (const sp<gui::ITransactionTraceListener>&), (override));
+    MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override));
+    MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override));
+    MOCK_METHOD(binder::Status, addWindowInfosListener, (const sp<gui::IWindowInfosListener>&),
+                (override));
+    MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp<gui::IWindowInfosListener>&),
+                (override));
+};
+
+class FakeBnSurfaceComposerClient : public gui::BnSurfaceComposerClient {
+public:
+    MOCK_METHOD(binder::Status, createSurface,
+                (const std::string& name, int32_t flags, const sp<IBinder>& parent,
+                 const gui::LayerMetadata& metadata, gui::CreateSurfaceResult* outResult),
+                (override));
+
+    MOCK_METHOD(binder::Status, clearLayerFrameStats, (const sp<IBinder>& handle), (override));
+
+    MOCK_METHOD(binder::Status, getLayerFrameStats,
+                (const sp<IBinder>& handle, gui::FrameStats* outStats), (override));
+
+    MOCK_METHOD(binder::Status, mirrorSurface,
+                (const sp<IBinder>& mirrorFromHandle, gui::MirrorSurfaceResult* outResult),
+                (override));
+
+    MOCK_METHOD(binder::Status, mirrorDisplay,
+                (int64_t displayId, gui::MirrorSurfaceResult* outResult), (override));
+};
+
+class FakeDisplayEventDispatcher : public DisplayEventDispatcher {
+public:
+    FakeDisplayEventDispatcher(const sp<Looper>& looper,
+                               gui::ISurfaceComposer::VsyncSource vsyncSource,
+                               gui::ISurfaceComposer::EventRegistration eventRegistration)
+          : DisplayEventDispatcher(looper, vsyncSource, eventRegistration){};
+
+    MOCK_METHOD4(dispatchVsync, void(nsecs_t, PhysicalDisplayId, uint32_t, VsyncEventData));
+    MOCK_METHOD3(dispatchHotplug, void(nsecs_t, PhysicalDisplayId, bool));
+    MOCK_METHOD4(dispatchModeChanged, void(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t));
+    MOCK_METHOD2(dispatchNullEvent, void(nsecs_t, PhysicalDisplayId));
+    MOCK_METHOD3(dispatchFrameRateOverrides,
+                 void(nsecs_t, PhysicalDisplayId, std::vector<FrameRateOverride>));
+};
+
+} // namespace android
+
+namespace android::hardware {
+
+namespace graphics::bufferqueue::V1_0::utils {
+
+class FakeGraphicBufferProducerV1 : public HGraphicBufferProducer {
+public:
+    FakeGraphicBufferProducerV1() {
+        ON_CALL(*this, setMaxDequeuedBufferCount).WillByDefault([]() { return 0; });
+        ON_CALL(*this, setAsyncMode).WillByDefault([]() { return 0; });
+        ON_CALL(*this, detachBuffer).WillByDefault([]() { return 0; });
+        ON_CALL(*this, cancelBuffer).WillByDefault([]() { return 0; });
+        ON_CALL(*this, disconnect).WillByDefault([]() { return 0; });
+        ON_CALL(*this, setSidebandStream).WillByDefault([]() { return 0; });
+        ON_CALL(*this, allowAllocation).WillByDefault([]() { return 0; });
+        ON_CALL(*this, setGenerationNumber).WillByDefault([]() { return 0; });
+        ON_CALL(*this, setSharedBufferMode).WillByDefault([]() { return 0; });
+        ON_CALL(*this, setAutoRefresh).WillByDefault([]() { return 0; });
+        ON_CALL(*this, setDequeueTimeout).WillByDefault([]() { return 0; });
+        ON_CALL(*this, setLegacyBufferDrop).WillByDefault([]() { return 0; });
+    };
+    MOCK_METHOD2(requestBuffer, Return<void>(int, requestBuffer_cb));
+    MOCK_METHOD1(setMaxDequeuedBufferCount, Return<int32_t>(int32_t));
+    MOCK_METHOD1(setAsyncMode, Return<int32_t>(bool));
+    MOCK_METHOD6(dequeueBuffer,
+                 Return<void>(uint32_t, uint32_t, graphics::common::V1_0::PixelFormat, uint32_t,
+                              bool, dequeueBuffer_cb));
+    MOCK_METHOD1(detachBuffer, Return<int32_t>(int));
+    MOCK_METHOD1(detachNextBuffer, Return<void>(detachNextBuffer_cb));
+    MOCK_METHOD2(attachBuffer, Return<void>(const media::V1_0::AnwBuffer&, attachBuffer_cb));
+    MOCK_METHOD3(
+            queueBuffer,
+            Return<void>(
+                    int,
+                    const graphics::bufferqueue::V1_0::IGraphicBufferProducer::QueueBufferInput&,
+                    queueBuffer_cb));
+    MOCK_METHOD2(cancelBuffer, Return<int32_t>(int, const hidl_handle&));
+    MOCK_METHOD2(query, Return<void>(int32_t, query_cb));
+    MOCK_METHOD4(connect,
+                 Return<void>(const sp<graphics::bufferqueue::V1_0::IProducerListener>&, int32_t,
+                              bool, connect_cb));
+    MOCK_METHOD2(disconnect,
+                 Return<int32_t>(
+                         int, graphics::bufferqueue::V1_0::IGraphicBufferProducer::DisconnectMode));
+    MOCK_METHOD1(setSidebandStream, Return<int32_t>(const hidl_handle&));
+    MOCK_METHOD4(allocateBuffers,
+                 Return<void>(uint32_t, uint32_t, graphics::common::V1_0::PixelFormat, uint32_t));
+    MOCK_METHOD1(allowAllocation, Return<int32_t>(bool));
+    MOCK_METHOD1(setGenerationNumber, Return<int32_t>(uint32_t));
+    MOCK_METHOD1(getConsumerName, Return<void>(getConsumerName_cb));
+    MOCK_METHOD1(setSharedBufferMode, Return<int32_t>(bool));
+    MOCK_METHOD1(setAutoRefresh, Return<int32_t>(bool));
+    MOCK_METHOD1(setDequeueTimeout, Return<int32_t>(nsecs_t));
+    MOCK_METHOD1(setLegacyBufferDrop, Return<int32_t>(bool));
+    MOCK_METHOD1(getLastQueuedBuffer, Return<void>(getLastQueuedBuffer_cb));
+    MOCK_METHOD1(getFrameTimestamps, Return<void>(getFrameTimestamps_cb));
+    MOCK_METHOD1(getUniqueId, Return<void>(getUniqueId_cb));
+};
+
+}; // namespace graphics::bufferqueue::V1_0::utils
+
+namespace graphics::bufferqueue::V2_0::utils {
+
+class FakeGraphicBufferProducerV2 : public HGraphicBufferProducer {
+public:
+    FakeGraphicBufferProducerV2() {
+        ON_CALL(*this, setMaxDequeuedBufferCount).WillByDefault([]() { return Status::OK; });
+        ON_CALL(*this, setAsyncMode).WillByDefault([]() { return Status::OK; });
+        ON_CALL(*this, detachBuffer).WillByDefault([]() { return Status::OK; });
+        ON_CALL(*this, cancelBuffer).WillByDefault([]() { return Status::OK; });
+        ON_CALL(*this, disconnect).WillByDefault([]() { return Status::OK; });
+        ON_CALL(*this, allocateBuffers).WillByDefault([]() { return Status::OK; });
+        ON_CALL(*this, allowAllocation).WillByDefault([]() { return Status::OK; });
+        ON_CALL(*this, setGenerationNumber).WillByDefault([]() { return Status::OK; });
+        ON_CALL(*this, setDequeueTimeout).WillByDefault([]() { return Status::OK; });
+        ON_CALL(*this, getUniqueId).WillByDefault([]() { return 0; });
+    };
+    MOCK_METHOD2(requestBuffer, Return<void>(int, requestBuffer_cb));
+    MOCK_METHOD1(setMaxDequeuedBufferCount, Return<graphics::bufferqueue::V2_0::Status>(int));
+    MOCK_METHOD1(setAsyncMode, Return<graphics::bufferqueue::V2_0::Status>(bool));
+    MOCK_METHOD2(
+            dequeueBuffer,
+            Return<void>(
+                    const graphics::bufferqueue::V2_0::IGraphicBufferProducer::DequeueBufferInput&,
+                    dequeueBuffer_cb));
+    MOCK_METHOD1(detachBuffer, Return<graphics::bufferqueue::V2_0::Status>(int));
+    MOCK_METHOD1(detachNextBuffer, Return<void>(detachNextBuffer_cb));
+    MOCK_METHOD3(attachBuffer,
+                 Return<void>(const graphics::common::V1_2::HardwareBuffer&, uint32_t,
+                              attachBuffer_cb));
+    MOCK_METHOD3(
+            queueBuffer,
+            Return<void>(
+                    int,
+                    const graphics::bufferqueue::V2_0::IGraphicBufferProducer::QueueBufferInput&,
+                    queueBuffer_cb));
+    MOCK_METHOD2(cancelBuffer,
+                 Return<graphics::bufferqueue::V2_0::Status>(int, const hidl_handle&));
+    MOCK_METHOD2(query, Return<void>(int32_t, query_cb));
+    MOCK_METHOD4(connect,
+                 Return<void>(const sp<graphics::bufferqueue::V2_0::IProducerListener>&,
+                              graphics::bufferqueue::V2_0::ConnectionType, bool, connect_cb));
+    MOCK_METHOD1(disconnect,
+                 Return<graphics::bufferqueue::V2_0::Status>(
+                         graphics::bufferqueue::V2_0::ConnectionType));
+    MOCK_METHOD4(allocateBuffers,
+                 Return<graphics::bufferqueue::V2_0::Status>(uint32_t, uint32_t, uint32_t,
+                                                             uint64_t));
+    MOCK_METHOD1(allowAllocation, Return<graphics::bufferqueue::V2_0::Status>(bool));
+    MOCK_METHOD1(setGenerationNumber, Return<graphics::bufferqueue::V2_0::Status>(uint32_t));
+    MOCK_METHOD1(getConsumerName, Return<void>(getConsumerName_cb));
+    MOCK_METHOD1(setDequeueTimeout, Return<graphics::bufferqueue::V2_0::Status>(int64_t));
+    MOCK_METHOD0(getUniqueId, Return<uint64_t>());
+};
+
+}; // namespace graphics::bufferqueue::V2_0::utils
+}; // namespace android::hardware
diff --git a/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp b/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp
new file mode 100644
index 0000000..9f0f6ca
--- /dev/null
+++ b/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+#include <gui/BufferQueueConsumer.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/LayerMetadata.h>
+#include <gui/OccupancyTracker.h>
+#include <gui/StreamSplitter.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceControl.h>
+#include <gui/view/Surface.h>
+#include <libgui_fuzzer_utils.h>
+#include "android/view/LayerMetadataKey.h"
+
+using namespace android;
+
+constexpr int32_t kMaxBytes = 256;
+constexpr int32_t kMatrixSize = 4;
+constexpr int32_t kLayerMetadataKeyCount = 8;
+
+constexpr uint32_t kMetadataKey[] = {
+        (uint32_t)view::LayerMetadataKey::METADATA_OWNER_UID,
+        (uint32_t)view::LayerMetadataKey::METADATA_WINDOW_TYPE,
+        (uint32_t)view::LayerMetadataKey::METADATA_TASK_ID,
+        (uint32_t)view::LayerMetadataKey::METADATA_MOUSE_CURSOR,
+        (uint32_t)view::LayerMetadataKey::METADATA_ACCESSIBILITY_ID,
+        (uint32_t)view::LayerMetadataKey::METADATA_OWNER_PID,
+        (uint32_t)view::LayerMetadataKey::METADATA_DEQUEUE_TIME,
+        (uint32_t)view::LayerMetadataKey::METADATA_GAME_MODE,
+};
+
+class ParcelableFuzzer {
+public:
+    ParcelableFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+
+private:
+    void invokeStreamSplitter();
+    void invokeOccupancyTracker();
+    void invokeLayerDebugInfo();
+    void invokeLayerMetadata();
+    void invokeViewSurface();
+
+    FuzzedDataProvider mFdp;
+};
+
+void ParcelableFuzzer::invokeViewSurface() {
+    view::Surface surface;
+    surface.name = String16((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
+    Parcel parcel;
+    surface.writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+    surface.readFromParcel(&parcel);
+    bool nameAlreadyWritten = mFdp.ConsumeBool();
+    surface.writeToParcel(&parcel, nameAlreadyWritten);
+    parcel.setDataPosition(0);
+    surface.readFromParcel(&parcel, mFdp.ConsumeBool());
+}
+
+void ParcelableFuzzer::invokeLayerMetadata() {
+    std::unordered_map<uint32_t, std::vector<uint8_t>> map;
+    for (size_t idx = 0; idx < kLayerMetadataKeyCount; ++idx) {
+        std::vector<uint8_t> data;
+        for (size_t idx1 = 0; idx1 < mFdp.ConsumeIntegral<uint32_t>(); ++idx1) {
+            data.push_back(mFdp.ConsumeIntegral<uint8_t>());
+        }
+        map[kMetadataKey[idx]] = data;
+    }
+    LayerMetadata metadata(map);
+    uint32_t key = mFdp.PickValueInArray(kMetadataKey);
+    metadata.setInt32(key, mFdp.ConsumeIntegral<int32_t>());
+    metadata.itemToString(key, (mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
+
+    Parcel parcel;
+    metadata.writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+    metadata.readFromParcel(&parcel);
+}
+
+void ParcelableFuzzer::invokeLayerDebugInfo() {
+    gui::LayerDebugInfo info;
+    info.mName = mFdp.ConsumeRandomLengthString(kMaxBytes);
+    info.mParentName = mFdp.ConsumeRandomLengthString(kMaxBytes);
+    info.mType = mFdp.ConsumeRandomLengthString(kMaxBytes);
+    info.mLayerStack = mFdp.ConsumeIntegral<uint32_t>();
+    info.mX = mFdp.ConsumeFloatingPoint<float>();
+    info.mY = mFdp.ConsumeFloatingPoint<float>();
+    info.mZ = mFdp.ConsumeIntegral<uint32_t>();
+    info.mWidth = mFdp.ConsumeIntegral<int32_t>();
+    info.mHeight = mFdp.ConsumeIntegral<int32_t>();
+    info.mActiveBufferWidth = mFdp.ConsumeIntegral<int32_t>();
+    info.mActiveBufferHeight = mFdp.ConsumeIntegral<int32_t>();
+    info.mActiveBufferStride = mFdp.ConsumeIntegral<int32_t>();
+    info.mActiveBufferFormat = mFdp.ConsumeIntegral<int32_t>();
+    info.mNumQueuedFrames = mFdp.ConsumeIntegral<int32_t>();
+
+    info.mFlags = mFdp.ConsumeIntegral<uint32_t>();
+    info.mPixelFormat = mFdp.ConsumeIntegral<int32_t>();
+    info.mTransparentRegion = Region(getRect(&mFdp));
+    info.mVisibleRegion = Region(getRect(&mFdp));
+    info.mSurfaceDamageRegion = Region(getRect(&mFdp));
+    info.mCrop = getRect(&mFdp);
+    info.mDataSpace = static_cast<android_dataspace>(mFdp.PickValueInArray(kDataspaces));
+    info.mColor = half4(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+                        mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>());
+    for (size_t idx = 0; idx < kMatrixSize; ++idx) {
+        info.mMatrix[idx / 2][idx % 2] = mFdp.ConsumeFloatingPoint<float>();
+    }
+    info.mIsOpaque = mFdp.ConsumeBool();
+    info.mContentDirty = mFdp.ConsumeBool();
+    info.mStretchEffect.width = mFdp.ConsumeFloatingPoint<float>();
+    info.mStretchEffect.height = mFdp.ConsumeFloatingPoint<float>();
+    info.mStretchEffect.vectorX = mFdp.ConsumeFloatingPoint<float>();
+    info.mStretchEffect.vectorY = mFdp.ConsumeFloatingPoint<float>();
+    info.mStretchEffect.maxAmountX = mFdp.ConsumeFloatingPoint<float>();
+    info.mStretchEffect.maxAmountY = mFdp.ConsumeFloatingPoint<float>();
+    info.mStretchEffect.mappedChildBounds =
+            FloatRect(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+                      mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>());
+
+    Parcel parcel;
+    info.writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+    info.readFromParcel(&parcel);
+}
+
+void ParcelableFuzzer::invokeOccupancyTracker() {
+    nsecs_t totalTime = mFdp.ConsumeIntegral<uint32_t>();
+    size_t numFrames = mFdp.ConsumeIntegral<size_t>();
+    float occupancyAverage = mFdp.ConsumeFloatingPoint<float>();
+    OccupancyTracker::Segment segment(totalTime, numFrames, occupancyAverage,
+                                      mFdp.ConsumeBool() /*usedThirdBuffer*/);
+    Parcel parcel;
+    segment.writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+    segment.readFromParcel(&parcel);
+}
+
+void ParcelableFuzzer::invokeStreamSplitter() {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    sp<StreamSplitter> splitter;
+    StreamSplitter::createSplitter(consumer, &splitter);
+    splitter->addOutput(producer);
+    std::string name = mFdp.ConsumeRandomLengthString(kMaxBytes);
+    splitter->setName(String8(name.c_str()));
+}
+
+void ParcelableFuzzer::process() {
+    invokeStreamSplitter();
+    invokeOccupancyTracker();
+    invokeLayerDebugInfo();
+    invokeLayerMetadata();
+    invokeViewSurface();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    ParcelableFuzzer libGuiFuzzer(data, size);
+    libGuiFuzzer.process();
+    return 0;
+}
diff --git a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
new file mode 100644
index 0000000..05564e0
--- /dev/null
+++ b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
@@ -0,0 +1,308 @@
+/*
+ * 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.
+ */
+#include <android/hardware/power/Boost.h>
+#include <fuzzbinder/libbinder_driver.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <libgui_fuzzer_utils.h>
+
+using namespace android;
+
+constexpr int32_t kRandomStringMaxBytes = 256;
+
+constexpr ui::ColorMode kColormodes[] = {ui::ColorMode::NATIVE,
+                                         ui::ColorMode::STANDARD_BT601_625,
+                                         ui::ColorMode::STANDARD_BT601_625_UNADJUSTED,
+                                         ui::ColorMode::STANDARD_BT601_525,
+                                         ui::ColorMode::STANDARD_BT601_525_UNADJUSTED,
+                                         ui::ColorMode::STANDARD_BT709,
+                                         ui::ColorMode::DCI_P3,
+                                         ui::ColorMode::SRGB,
+                                         ui::ColorMode::ADOBE_RGB,
+                                         ui::ColorMode::DISPLAY_P3,
+                                         ui::ColorMode::BT2020,
+                                         ui::ColorMode::BT2100_PQ,
+                                         ui::ColorMode::BT2100_HLG,
+                                         ui::ColorMode::DISPLAY_BT2020};
+
+constexpr hardware::power::Boost kBoost[] = {
+        hardware::power::Boost::INTERACTION,   hardware::power::Boost::DISPLAY_UPDATE_IMMINENT,
+        hardware::power::Boost::ML_ACC,        hardware::power::Boost::AUDIO_LAUNCH,
+        hardware::power::Boost::CAMERA_LAUNCH, hardware::power::Boost::CAMERA_SHOT,
+};
+
+constexpr gui::TouchOcclusionMode kMode[] = {
+        gui::TouchOcclusionMode::BLOCK_UNTRUSTED,
+        gui::TouchOcclusionMode::USE_OPACITY,
+        gui::TouchOcclusionMode::ALLOW,
+};
+
+constexpr gui::WindowInfo::Flag kFlags[] = {
+        gui::WindowInfo::Flag::ALLOW_LOCK_WHILE_SCREEN_ON,
+        gui::WindowInfo::Flag::DIM_BEHIND,
+        gui::WindowInfo::Flag::BLUR_BEHIND,
+        gui::WindowInfo::Flag::NOT_FOCUSABLE,
+        gui::WindowInfo::Flag::NOT_TOUCHABLE,
+        gui::WindowInfo::Flag::NOT_TOUCH_MODAL,
+        gui::WindowInfo::Flag::TOUCHABLE_WHEN_WAKING,
+        gui::WindowInfo::Flag::KEEP_SCREEN_ON,
+        gui::WindowInfo::Flag::LAYOUT_IN_SCREEN,
+        gui::WindowInfo::Flag::LAYOUT_NO_LIMITS,
+        gui::WindowInfo::Flag::FULLSCREEN,
+        gui::WindowInfo::Flag::FORCE_NOT_FULLSCREEN,
+        gui::WindowInfo::Flag::DITHER,
+        gui::WindowInfo::Flag::SECURE,
+        gui::WindowInfo::Flag::SCALED,
+        gui::WindowInfo::Flag::IGNORE_CHEEK_PRESSES,
+        gui::WindowInfo::Flag::LAYOUT_INSET_DECOR,
+        gui::WindowInfo::Flag::ALT_FOCUSABLE_IM,
+        gui::WindowInfo::Flag::WATCH_OUTSIDE_TOUCH,
+        gui::WindowInfo::Flag::SHOW_WHEN_LOCKED,
+        gui::WindowInfo::Flag::SHOW_WALLPAPER,
+        gui::WindowInfo::Flag::TURN_SCREEN_ON,
+        gui::WindowInfo::Flag::DISMISS_KEYGUARD,
+        gui::WindowInfo::Flag::SPLIT_TOUCH,
+        gui::WindowInfo::Flag::HARDWARE_ACCELERATED,
+        gui::WindowInfo::Flag::LAYOUT_IN_OVERSCAN,
+        gui::WindowInfo::Flag::TRANSLUCENT_STATUS,
+        gui::WindowInfo::Flag::TRANSLUCENT_NAVIGATION,
+        gui::WindowInfo::Flag::LOCAL_FOCUS_MODE,
+        gui::WindowInfo::Flag::SLIPPERY,
+        gui::WindowInfo::Flag::LAYOUT_ATTACHED_IN_DECOR,
+        gui::WindowInfo::Flag::DRAWS_SYSTEM_BAR_BACKGROUNDS,
+};
+
+constexpr gui::WindowInfo::Type kType[] = {
+        gui::WindowInfo::Type::UNKNOWN,
+        gui::WindowInfo::Type::FIRST_APPLICATION_WINDOW,
+        gui::WindowInfo::Type::BASE_APPLICATION,
+        gui::WindowInfo::Type::APPLICATION,
+        gui::WindowInfo::Type::APPLICATION_STARTING,
+        gui::WindowInfo::Type::LAST_APPLICATION_WINDOW,
+        gui::WindowInfo::Type::FIRST_SUB_WINDOW,
+        gui::WindowInfo::Type::APPLICATION_PANEL,
+        gui::WindowInfo::Type::APPLICATION_MEDIA,
+        gui::WindowInfo::Type::APPLICATION_SUB_PANEL,
+        gui::WindowInfo::Type::APPLICATION_ATTACHED_DIALOG,
+        gui::WindowInfo::Type::APPLICATION_MEDIA_OVERLAY,
+};
+
+constexpr gui::WindowInfo::InputConfig kFeatures[] = {
+        gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL,
+        gui::WindowInfo::InputConfig::DISABLE_USER_ACTIVITY,
+        gui::WindowInfo::InputConfig::DROP_INPUT,
+        gui::WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED,
+        gui::WindowInfo::InputConfig::SPY,
+        gui::WindowInfo::InputConfig::INTERCEPTS_STYLUS,
+};
+
+class SurfaceComposerClientFuzzer {
+public:
+    SurfaceComposerClientFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+
+private:
+    void invokeSurfaceComposerClient();
+    void invokeSurfaceComposerClientBinder();
+    void invokeSurfaceComposerTransaction();
+    void getWindowInfo(gui::WindowInfo*);
+    sp<SurfaceControl> makeSurfaceControl();
+    BlurRegion getBlurRegion();
+    void fuzzOnPullAtom();
+
+    FuzzedDataProvider mFdp;
+};
+
+BlurRegion SurfaceComposerClientFuzzer::getBlurRegion() {
+    int32_t left = mFdp.ConsumeIntegral<int32_t>();
+    int32_t right = mFdp.ConsumeIntegral<int32_t>();
+    int32_t top = mFdp.ConsumeIntegral<int32_t>();
+    int32_t bottom = mFdp.ConsumeIntegral<int32_t>();
+    uint32_t blurRadius = mFdp.ConsumeIntegral<uint32_t>();
+    float alpha = mFdp.ConsumeFloatingPoint<float>();
+    float cornerRadiusTL = mFdp.ConsumeFloatingPoint<float>();
+    float cornerRadiusTR = mFdp.ConsumeFloatingPoint<float>();
+    float cornerRadiusBL = mFdp.ConsumeFloatingPoint<float>();
+    float cornerRadiusBR = mFdp.ConsumeFloatingPoint<float>();
+    return BlurRegion{blurRadius,     cornerRadiusTL, cornerRadiusTR, cornerRadiusBL,
+                      cornerRadiusBR, alpha,          left,           top,
+                      right,          bottom};
+}
+
+void SurfaceComposerClientFuzzer::getWindowInfo(gui::WindowInfo* windowInfo) {
+    windowInfo->id = mFdp.ConsumeIntegral<int32_t>();
+    windowInfo->name = mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes);
+    windowInfo->layoutParamsFlags = mFdp.PickValueInArray(kFlags);
+    windowInfo->layoutParamsType = mFdp.PickValueInArray(kType);
+    windowInfo->frameLeft = mFdp.ConsumeIntegral<int32_t>();
+    windowInfo->frameTop = mFdp.ConsumeIntegral<int32_t>();
+    windowInfo->frameRight = mFdp.ConsumeIntegral<int32_t>();
+    windowInfo->frameBottom = mFdp.ConsumeIntegral<int32_t>();
+    windowInfo->surfaceInset = mFdp.ConsumeIntegral<int32_t>();
+    windowInfo->alpha = mFdp.ConsumeFloatingPointInRange<float>(0, 1);
+    ui::Transform transform(mFdp.PickValueInArray(kOrientation));
+    windowInfo->transform = transform;
+    windowInfo->touchableRegion = Region(getRect(&mFdp));
+    windowInfo->replaceTouchableRegionWithCrop = mFdp.ConsumeBool();
+    windowInfo->touchOcclusionMode = mFdp.PickValueInArray(kMode);
+    windowInfo->ownerPid = mFdp.ConsumeIntegral<int32_t>();
+    windowInfo->ownerUid = mFdp.ConsumeIntegral<int32_t>();
+    windowInfo->packageName = mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes);
+    windowInfo->inputConfig = mFdp.PickValueInArray(kFeatures);
+}
+
+sp<SurfaceControl> SurfaceComposerClientFuzzer::makeSurfaceControl() {
+    sp<IBinder> handle;
+    const sp<FakeBnSurfaceComposerClient> testClient(new FakeBnSurfaceComposerClient());
+    sp<SurfaceComposerClient> client = new SurfaceComposerClient(testClient);
+    sp<BnGraphicBufferProducer> producer;
+    uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
+    uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
+    uint32_t transformHint = mFdp.ConsumeIntegral<uint32_t>();
+    uint32_t flags = mFdp.ConsumeIntegral<uint32_t>();
+    int32_t format = mFdp.ConsumeIntegral<int32_t>();
+    int32_t layerId = mFdp.ConsumeIntegral<int32_t>();
+    return new SurfaceControl(client, handle, layerId, width, height, format, transformHint, flags);
+}
+
+void SurfaceComposerClientFuzzer::invokeSurfaceComposerTransaction() {
+    sp<SurfaceControl> surface = makeSurfaceControl();
+
+    SurfaceComposerClient::Transaction transaction;
+    transaction.setSize(surface, mFdp.ConsumeIntegral<uint32_t>(),
+                        mFdp.ConsumeIntegral<uint32_t>());
+    int32_t layer = mFdp.ConsumeIntegral<int32_t>();
+    transaction.setLayer(surface, layer);
+
+    sp<SurfaceControl> relativeSurface = makeSurfaceControl();
+    transaction.setRelativeLayer(surface, relativeSurface, layer);
+
+    Region transparentRegion(getRect(&mFdp));
+    transaction.setTransparentRegionHint(surface, transparentRegion);
+    transaction.setAlpha(surface, mFdp.ConsumeFloatingPoint<float>());
+
+    transaction.setCornerRadius(surface, mFdp.ConsumeFloatingPoint<float>());
+    transaction.setBackgroundBlurRadius(surface, mFdp.ConsumeFloatingPoint<float>());
+    std::vector<BlurRegion> regions;
+    uint32_t vectorSize = mFdp.ConsumeIntegralInRange<uint32_t>(0, 100);
+    regions.resize(vectorSize);
+    for (size_t idx = 0; idx < vectorSize; ++idx) {
+        regions.push_back(getBlurRegion());
+    }
+    transaction.setBlurRegions(surface, regions);
+
+    transaction.setLayerStack(surface, {mFdp.ConsumeIntegral<uint32_t>()});
+    half3 color = {mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
+                   mFdp.ConsumeIntegral<uint32_t>()};
+    transaction.setColor(surface, color);
+    transaction.setBackgroundColor(surface, color, mFdp.ConsumeFloatingPoint<float>(),
+                                   mFdp.PickValueInArray(kDataspaces));
+
+    transaction.setApi(surface, mFdp.ConsumeIntegral<int32_t>());
+    transaction.setFrameRateSelectionPriority(surface, mFdp.ConsumeIntegral<int32_t>());
+    transaction.setColorSpaceAgnostic(surface, mFdp.ConsumeBool() /*agnostic*/);
+
+    gui::WindowInfo windowInfo;
+    getWindowInfo(&windowInfo);
+    transaction.setInputWindowInfo(surface, windowInfo);
+    Parcel windowParcel;
+    windowInfo.writeToParcel(&windowParcel);
+    windowParcel.setDataPosition(0);
+    windowInfo.readFromParcel(&windowParcel);
+
+    windowInfo.addTouchableRegion(getRect(&mFdp));
+    int32_t pointX = mFdp.ConsumeIntegral<int32_t>();
+    int32_t pointY = mFdp.ConsumeIntegral<int32_t>();
+    windowInfo.touchableRegionContainsPoint(pointX, pointY);
+    windowInfo.frameContainsPoint(pointX, pointY);
+
+    Parcel transactionParcel;
+    transaction.writeToParcel(&transactionParcel);
+    transactionParcel.setDataPosition(0);
+    transaction.readFromParcel(&transactionParcel);
+    SurfaceComposerClient::Transaction::createFromParcel(&transactionParcel);
+}
+
+void SurfaceComposerClientFuzzer::fuzzOnPullAtom() {
+    std::string outData;
+    bool success;
+    SurfaceComposerClient::onPullAtom(mFdp.ConsumeIntegral<int32_t>(), &outData, &success);
+}
+
+void SurfaceComposerClientFuzzer::invokeSurfaceComposerClient() {
+    String8 displayName((mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes)).c_str());
+    sp<IBinder> displayToken =
+            SurfaceComposerClient::createDisplay(displayName, mFdp.ConsumeBool() /*secure*/);
+    SurfaceComposerClient::setDesiredDisplayModeSpecs(displayToken, mFdp.ConsumeIntegral<int32_t>(),
+                                                      mFdp.ConsumeBool() /*allowGroupSwitching*/,
+                                                      mFdp.ConsumeFloatingPoint<float>(),
+                                                      mFdp.ConsumeFloatingPoint<float>(),
+                                                      mFdp.ConsumeFloatingPoint<float>(),
+                                                      mFdp.ConsumeFloatingPoint<float>());
+
+    ui::ColorMode colorMode = mFdp.PickValueInArray(kColormodes);
+    SurfaceComposerClient::setActiveColorMode(displayToken, colorMode);
+    SurfaceComposerClient::setAutoLowLatencyMode(displayToken, mFdp.ConsumeBool() /*on*/);
+    SurfaceComposerClient::setGameContentType(displayToken, mFdp.ConsumeBool() /*on*/);
+    SurfaceComposerClient::setDisplayPowerMode(displayToken, mFdp.ConsumeIntegral<int32_t>());
+    SurfaceComposerClient::doUncacheBufferTransaction(mFdp.ConsumeIntegral<uint64_t>());
+
+    SurfaceComposerClient::setDisplayBrightness(displayToken, getBrightness(&mFdp));
+    hardware::power::Boost boostId = mFdp.PickValueInArray(kBoost);
+    SurfaceComposerClient::notifyPowerBoost((int32_t)boostId);
+
+    String8 surfaceName((mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes)).c_str());
+    sp<BBinder> handle(new BBinder());
+    sp<BnGraphicBufferProducer> producer;
+    sp<Surface> surfaceParent(
+            new Surface(producer, mFdp.ConsumeBool() /*controlledByApp*/, handle));
+
+    SurfaceComposerClient::enableVSyncInjections(mFdp.ConsumeBool() /*secure*/);
+    nsecs_t when = mFdp.ConsumeIntegral<uint32_t>();
+    SurfaceComposerClient::injectVSync(when);
+
+    fuzzOnPullAtom();
+    SurfaceComposerClient::setDisplayContentSamplingEnabled(displayToken,
+                                                            mFdp.ConsumeBool() /*enable*/,
+                                                            mFdp.ConsumeIntegral<uint8_t>(),
+                                                            mFdp.ConsumeIntegral<uint64_t>());
+
+    sp<IBinder> stopLayerHandle;
+    sp<gui::IRegionSamplingListener> listener = sp<gui::IRegionSamplingListenerDefault>::make();
+    sp<gui::IRegionSamplingListenerDelegator> sampleListener =
+            new gui::IRegionSamplingListenerDelegator(listener);
+    SurfaceComposerClient::addRegionSamplingListener(getRect(&mFdp), stopLayerHandle,
+                                                     sampleListener);
+    sp<gui::IFpsListenerDefault> fpsListener;
+    SurfaceComposerClient::addFpsListener(mFdp.ConsumeIntegral<int32_t>(), fpsListener);
+}
+
+void SurfaceComposerClientFuzzer::invokeSurfaceComposerClientBinder() {
+    sp<FakeBnSurfaceComposerClient> client(new FakeBnSurfaceComposerClient());
+    fuzzService(client.get(), std::move(mFdp));
+}
+
+void SurfaceComposerClientFuzzer::process() {
+    invokeSurfaceComposerClient();
+    invokeSurfaceComposerTransaction();
+    invokeSurfaceComposerClientBinder();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    SurfaceComposerClientFuzzer surfaceComposerClientFuzzer(data, size);
+    surfaceComposerClientFuzzer.process();
+    return 0;
+}
diff --git a/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp
new file mode 100644
index 0000000..6d5427b
--- /dev/null
+++ b/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <libgui_fuzzer_utils.h>
+
+using namespace android;
+
+class SurfaceComposerFuzzer {
+public:
+    SurfaceComposerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+
+private:
+    FuzzedDataProvider mFdp;
+};
+
+void SurfaceComposerFuzzer::process() {
+    sp<FakeBnSurfaceComposer> composer(new FakeBnSurfaceComposer());
+    fuzzService(composer.get(), std::move(mFdp));
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    SurfaceComposerFuzzer surfaceComposerFuzzer(data, size);
+    surfaceComposerFuzzer.process();
+    return 0;
+}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 65fc04d..95df811 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -69,9 +69,7 @@
     bool mPreviouslyConnected GUARDED_BY(mMutex);
 };
 
-class BLASTBufferQueue
-    : public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener
-{
+class BLASTBufferQueue : public ConsumerBase::FrameAvailableListener {
 public:
     BLASTBufferQueue(const std::string& name, bool updateDestinationFrame = true);
     BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width,
@@ -83,7 +81,6 @@
     sp<Surface> getSurface(bool includeSurfaceControlHandle);
     bool isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const;
 
-    void onBufferFreed(const wp<GraphicBuffer>&/* graphicBuffer*/) override { /* TODO */ }
     void onFrameReplaced(const BufferItem& item) override;
     void onFrameAvailable(const BufferItem& item) override;
     void onFrameDequeued(const uint64_t) override;
@@ -113,6 +110,14 @@
     uint64_t getLastAcquiredFrameNum();
     void abandon();
 
+    /**
+     * Set a callback to be invoked when we are hung. The boolean parameter
+     * indicates whether the hang is due to an unfired fence.
+     * TODO: The boolean is always true atm, unfired fence is
+     * the only case we detect.
+     */
+    void setTransactionHangCallback(std::function<void(bool)> callback);
+
     virtual ~BLASTBufferQueue();
 
 private:
@@ -228,7 +233,7 @@
 
     // Queues up transactions using this token in SurfaceFlinger. This prevents queued up
     // transactions from other parts of the client from blocking this transaction.
-    const sp<IBinder> mApplyToken GUARDED_BY(mMutex) = new BBinder();
+    const sp<IBinder> mApplyToken GUARDED_BY(mMutex) = sp<BBinder>::make();
 
     // Guards access to mDequeueTimestamps since we cannot hold to mMutex in onFrameDequeued or
     // we will deadlock.
@@ -243,7 +248,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
@@ -269,6 +273,10 @@
     // transaction that will be applied by some sync consumer.
     bool mAppliedLastTransaction = false;
     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/CompositorTiming.h b/libs/gui/include/gui/CompositorTiming.h
new file mode 100644
index 0000000..cb8ca7a
--- /dev/null
+++ b/libs/gui/include/gui/CompositorTiming.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <utils/Timers.h>
+
+namespace android::gui {
+
+// Expected timing of the next composited frame, based on the timing of the latest frames.
+struct CompositorTiming {
+    static constexpr nsecs_t kDefaultVsyncPeriod = 16'666'667;
+
+    CompositorTiming() = default;
+    CompositorTiming(nsecs_t vsyncDeadline, nsecs_t vsyncPeriod, nsecs_t vsyncPhase,
+                     nsecs_t presentLatency);
+
+    // Time point when compositing is expected to start.
+    nsecs_t deadline = 0;
+
+    // Duration between consecutive frames. In other words, the VSYNC period.
+    nsecs_t interval = kDefaultVsyncPeriod;
+
+    // Duration between composite start and present. For missed frames, the extra latency is rounded
+    // to a multiple of the VSYNC period, such that the remainder (presentLatency % interval) always
+    // evaluates to the VSYNC phase offset.
+    nsecs_t presentLatency = kDefaultVsyncPeriod;
+};
+
+} // namespace android::gui
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index a342539..bf3a07b 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -23,10 +23,10 @@
 
 class DisplayEventDispatcher : public LooperCallback {
 public:
-    explicit DisplayEventDispatcher(
-            const sp<Looper>& looper,
-            ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
-            ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
+    explicit DisplayEventDispatcher(const sp<Looper>& looper,
+                                    gui::ISurfaceComposer::VsyncSource vsyncSource =
+                                            gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp,
+                                    EventRegistrationFlags eventRegistration = {});
 
     status_t initialize();
     void dispose();
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index cf7a4e5..0f4907f 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -20,20 +20,26 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <ftl/flags.h>
+
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 
+#include <android/gui/ISurfaceComposer.h>
 #include <binder/IInterface.h>
-#include <gui/ISurfaceComposer.h>
 #include <gui/VsyncEventData.h>
 
+#include <ui/DisplayId.h>
+
 // ----------------------------------------------------------------------------
 
 namespace android {
 
 // ----------------------------------------------------------------------------
 
+using EventRegistrationFlags = ftl::Flags<gui::ISurfaceComposer::EventRegistration>;
+
 using gui::IDisplayEventConnection;
 using gui::ParcelableVsyncEventData;
 using gui::VsyncEventData;
@@ -111,9 +117,9 @@
      * To receive ModeChanged and/or FrameRateOverrides events specify this in
      * the constructor. Other events start being delivered immediately.
      */
-    explicit DisplayEventReceiver(
-            ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
-            ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
+    explicit DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource vsyncSource =
+                                          gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp,
+                                  EventRegistrationFlags eventRegistration = {});
 
     /*
      * ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
index f73bc3b..c08a9b1 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -19,6 +19,7 @@
 
 #include <android/gui/FrameEvent.h>
 
+#include <gui/CompositorTiming.h>
 #include <ui/FenceTime.h>
 #include <utils/Flattenable.h>
 #include <utils/StrongPointer.h>
@@ -33,6 +34,7 @@
 struct FrameEvents;
 class FrameEventHistoryDelta;
 
+using gui::CompositorTiming;
 using gui::FrameEvent;
 
 // A collection of timestamps corresponding to a single frame.
@@ -83,12 +85,6 @@
     std::shared_ptr<FenceTime> releaseFence{FenceTime::NO_FENCE};
 };
 
-struct CompositorTiming {
-    nsecs_t deadline{0};
-    nsecs_t interval{16666667};
-    nsecs_t presentLatency{16666667};
-};
-
 // A short history of frames that are synchronized between the consumer and
 // producer via deltas.
 class FrameEventHistory {
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index 2f538ff..ba268ab 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -138,6 +138,10 @@
             const sp<GraphicBuffer>& buf, const Rect& cropRect,
             uint32_t transform, bool filtering);
 
+    static void computeTransformMatrix(float outTransform[16], float bufferWidth,
+                                       float bufferHeight, PixelFormat pixelFormat,
+                                       const Rect& cropRect, uint32_t transform, bool filtering);
+
     // Scale the crop down horizontally or vertically such that it has the
     // same aspect ratio as the buffer does.
     static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth,
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 7139e1b..1e85131 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -28,7 +28,6 @@
 #include <android/gui/IWindowInfosListener.h>
 #include <binder/IBinder.h>
 #include <binder/IInterface.h>
-#include <ftl/flags.h>
 #include <gui/ITransactionCompletedListener.h>
 #include <gui/SpHash.h>
 #include <math/vec4.h>
@@ -94,8 +93,6 @@
 public:
     DECLARE_META_INTERFACE(SurfaceComposer)
 
-    static constexpr size_t MAX_LAYERS = 4096;
-
     // flags for setTransactionState()
     enum {
         eSynchronous = 0x01,
@@ -113,23 +110,6 @@
         eOneWay = 0x20
     };
 
-    enum VsyncSource {
-        eVsyncSourceApp = 0,
-        eVsyncSourceSurfaceFlinger = 1
-    };
-
-    enum class EventRegistration {
-        modeChanged = 1 << 0,
-        frameRateOverride = 1 << 1,
-    };
-
-    using EventRegistrationFlags = ftl::Flags<EventRegistration>;
-
-    /* return an IDisplayEventConnection */
-    virtual sp<IDisplayEventConnection> createDisplayEventConnection(
-            VsyncSource vsyncSource = eVsyncSourceApp,
-            EventRegistrationFlags eventRegistration = {}) = 0;
-
     /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
     virtual status_t setTransactionState(
             const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state,
@@ -137,11 +117,6 @@
             const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
             bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
             const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) = 0;
-
-    /* signal that we're done booting.
-     * Requires ACCESS_SURFACE_FLINGER permission
-     */
-    virtual void bootFinished() = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -152,12 +127,12 @@
         // Note: BOOT_FINISHED must remain this value, it is called from
         // Java by ActivityManagerService.
         BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
-        CREATE_CONNECTION,       // Deprecated. Autogenerated by .aidl now.
-        GET_STATIC_DISPLAY_INFO, // Deprecated. Autogenerated by .aidl now.
-        CREATE_DISPLAY_EVENT_CONNECTION,
-        CREATE_DISPLAY,             // Deprecated. Autogenerated by .aidl now.
-        DESTROY_DISPLAY,            // Deprecated. Autogenerated by .aidl now.
-        GET_PHYSICAL_DISPLAY_TOKEN, // Deprecated. Autogenerated by .aidl now.
+        CREATE_CONNECTION,               // Deprecated. Autogenerated by .aidl now.
+        GET_STATIC_DISPLAY_INFO,         // Deprecated. Autogenerated by .aidl now.
+        CREATE_DISPLAY_EVENT_CONNECTION, // Deprecated. Autogenerated by .aidl now.
+        CREATE_DISPLAY,                  // Deprecated. Autogenerated by .aidl now.
+        DESTROY_DISPLAY,                 // Deprecated. Autogenerated by .aidl now.
+        GET_PHYSICAL_DISPLAY_TOKEN,      // Deprecated. Autogenerated by .aidl now.
         SET_TRANSACTION_STATE,
         AUTHENTICATE_SURFACE,           // Deprecated. Autogenerated by .aidl now.
         GET_SUPPORTED_FRAME_TIMESTAMPS, // Deprecated. Autogenerated by .aidl now.
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index a791c66..cc136bb 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -194,6 +194,7 @@
 
     virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence,
                                  uint32_t currentMaxAcquiredBufferCount) = 0;
+    virtual void onTransactionQueueStalled() = 0;
 };
 
 class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> {
diff --git a/libs/gui/include/gui/JankInfo.h b/libs/gui/include/gui/JankInfo.h
index ce9716f..1dddeba 100644
--- a/libs/gui/include/gui/JankInfo.h
+++ b/libs/gui/include/gui/JankInfo.h
@@ -24,9 +24,9 @@
     None = 0x0,
     // Jank that occurs in the layers below SurfaceFlinger
     DisplayHAL = 0x1,
-    // SF took too long on the CPU
+    // SF took too long on the CPU; deadline missed during HWC
     SurfaceFlingerCpuDeadlineMissed = 0x2,
-    // SF took too long on the GPU
+    // SF took too long on the GPU; deadline missed during GPU composition
     SurfaceFlingerGpuDeadlineMissed = 0x4,
     // Either App or GPU took too long on the frame
     AppDeadlineMissed = 0x8,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 4cd9a56..759fcc6 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <android/gui/IWindowInfosReportedListener.h>
 #include <android/native_window.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/ITransactionCompletedListener.h>
@@ -155,7 +156,7 @@
         eLayerStackChanged = 0x00000080,
         eDimmingEnabledChanged = 0x00000400,
         eShadowRadiusChanged = 0x00000800,
-        /* unused 0x00001000, */
+        eRenderBorderChanged = 0x00001000,
         eBufferCropChanged = 0x00002000,
         eRelativeLayerChanged = 0x00004000,
         eReparent = 0x00008000,
@@ -165,7 +166,7 @@
         eTransformToDisplayInverseChanged = 0x00080000,
         eCropChanged = 0x00100000,
         eBufferChanged = 0x00200000,
-        /* unused 0x00400000, */
+        eDefaultFrameRateCompatibilityChanged = 0x00400000,
         eDataspaceChanged = 0x00800000,
         eHdrMetadataChanged = 0x01000000,
         eSurfaceDamageRegionChanged = 0x02000000,
@@ -249,7 +250,7 @@
     mat4 colorTransform;
     std::vector<BlurRegion> blurRegions;
 
-    sp<gui::WindowInfoHandle> windowInfoHandle = new gui::WindowInfoHandle();
+    sp<gui::WindowInfoHandle> windowInfoHandle = sp<gui::WindowInfoHandle>::make();
 
     LayerMetadata metadata;
 
@@ -275,6 +276,9 @@
     int8_t frameRateCompatibility;
     int8_t changeFrameRateStrategy;
 
+    // Default frame rate compatibility used to set the layer refresh rate votetype.
+    int8_t defaultFrameRateCompatibility;
+
     // Set by window manager indicating the layer and all its children are
     // in a different orientation than the display. The hint suggests that
     // the graphic producers should receive a transform hint as if the
@@ -293,6 +297,11 @@
     // should be trusted for input occlusion detection purposes
     bool isTrustedOverlay;
 
+    // Flag to indicate if border needs to be enabled on the layer
+    bool borderEnabled;
+    float borderWidth;
+    half4 borderColor;
+
     // Stretch effect to be applied to this layer
     StretchEffect stretchEffect;
 
@@ -354,7 +363,9 @@
 
 struct InputWindowCommands {
     std::vector<gui::FocusRequest> focusRequests;
-    bool syncInputWindows{false};
+    std::unordered_set<sp<gui::IWindowInfosReportedListener>,
+                       SpHash<gui::IWindowInfosReportedListener>>
+            windowInfosReportedListeners;
 
     // Merges the passed in commands and returns true if there were any changes.
     bool merge(const InputWindowCommands& other);
diff --git a/libs/gui/include/gui/ScreenCaptureResults.h b/libs/gui/include/gui/ScreenCaptureResults.h
index 99c35c1..724c11c 100644
--- a/libs/gui/include/gui/ScreenCaptureResults.h
+++ b/libs/gui/include/gui/ScreenCaptureResults.h
@@ -33,6 +33,7 @@
     sp<GraphicBuffer> buffer;
     sp<Fence> fence = Fence::NO_FENCE;
     bool capturedSecureLayers{false};
+    bool capturedHdrLayers{false};
     ui::Dataspace capturedDataspace{ui::Dataspace::V0_SRGB};
     status_t result = OK;
 };
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 267c28f..634acb6 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -285,6 +285,10 @@
     int dispatchGetLastQueuedBuffer2(va_list args);
     int dispatchSetFrameTimelineInfo(va_list args);
 
+    std::mutex mNameMutex;
+    std::string mName;
+    const char* getDebugName();
+
 protected:
     virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
     virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index dc96242..20c38d8 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -341,6 +341,8 @@
     //      B               B'
     sp<SurfaceControl> mirrorSurface(SurfaceControl* mirrorFromSurface);
 
+    sp<SurfaceControl> mirrorDisplay(DisplayId displayId);
+
     //! Create a virtual display
     static sp<IBinder> createDisplay(const String8& displayName, bool secure);
 
@@ -349,7 +351,6 @@
 
     //! Get stable IDs for connected physical displays
     static std::vector<PhysicalDisplayId> getPhysicalDisplayIds();
-    static status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*);
     static std::optional<PhysicalDisplayId> getInternalDisplayId();
 
     //! Get token for a physical display given its stable ID
@@ -457,6 +458,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.
@@ -566,7 +571,9 @@
 
         Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const gui::WindowInfo& info);
         Transaction& setFocusedWindow(const gui::FocusRequest& request);
-        Transaction& syncInputWindows();
+
+        Transaction& addWindowInfosReportedListener(
+                sp<gui::IWindowInfosReportedListener> windowInfosReportedListener);
 
         // Set a color transform matrix on the given layer on the built-in display.
         Transaction& setColorTransform(const sp<SurfaceControl>& sc, const mat3& matrix,
@@ -579,6 +586,9 @@
         Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate,
                                   int8_t compatibility, int8_t changeFrameRateStrategy);
 
+        Transaction& setDefaultFrameRateCompatibility(const sp<SurfaceControl>& sc,
+                                                      int8_t compatibility);
+
         // Set by window manager indicating the layer and all its children are
         // in a different orientation than the display. The hint suggests that
         // the graphic producers should receive a transform hint as if the
@@ -625,6 +635,9 @@
                                          const Rect& destinationFrame);
         Transaction& setDropInputMode(const sp<SurfaceControl>& sc, gui::DropInputMode mode);
 
+        Transaction& enableBorder(const sp<SurfaceControl>& sc, bool shouldEnable, float width,
+                                  const half4& color);
+
         status_t setDisplaySurface(const sp<IBinder>& token,
                 const sp<IGraphicBufferProducer>& bufferProducer);
 
@@ -768,6 +781,7 @@
     // This is protected by mSurfaceStatsListenerMutex, but GUARDED_BY isn't supported for
     // std::recursive_mutex
     std::multimap<int32_t, SurfaceStatsCallbackEntry> mSurfaceStatsListeners;
+    std::unordered_map<void*, std::function<void()>> mQueueStallListeners;
 
 public:
     static sp<TransactionCompletedListener> getInstance();
@@ -785,6 +799,9 @@
             const sp<SurfaceControl>& surfaceControl,
             const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds);
 
+    void addQueueStallListener(std::function<void()> stallListener, void* id);
+    void removeQueueStallListener(void *id);
+
     /*
      * Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific
      * surface. Jank classifications arrive as part of the transaction callbacks about previous
@@ -813,6 +830,8 @@
     // For Testing Only
     static void setInstance(const sp<TransactionCompletedListener>&);
 
+    void onTransactionQueueStalled() override;
+
 private:
     ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&);
     static sp<TransactionCompletedListener> sInstance;
diff --git a/libs/gui/include/gui/TraceUtils.h b/libs/gui/include/gui/TraceUtils.h
index e5d2684..4c01683 100644
--- a/libs/gui/include/gui/TraceUtils.h
+++ b/libs/gui/include/gui/TraceUtils.h
@@ -21,11 +21,14 @@
 #include <cutils/trace.h>
 #include <utils/Trace.h>
 
-#define ATRACE_FORMAT(fmt, ...)           \
-    TraceUtils::TraceEnder __traceEnder = \
-            (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), TraceUtils::TraceEnder())
+#define ATRACE_FORMAT(fmt, ...)                                                 \
+    TraceUtils::TraceEnder traceEnder =                                         \
+            (CC_UNLIKELY(ATRACE_ENABLED()) &&                                   \
+                     (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), true), \
+             TraceUtils::TraceEnder())
 
-#define ATRACE_FORMAT_BEGIN(fmt, ...) TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__)
+#define ATRACE_FORMAT_INSTANT(fmt, ...) \
+    (CC_UNLIKELY(ATRACE_ENABLED()) && (TraceUtils::instantFormat(fmt, ##__VA_ARGS__), true))
 
 namespace android {
 
@@ -37,8 +40,6 @@
     };
 
     static void atraceFormatBegin(const char* fmt, ...) {
-        if (CC_LIKELY(!ATRACE_ENABLED())) return;
-
         const int BUFFER_SIZE = 256;
         va_list ap;
         char buf[BUFFER_SIZE];
@@ -50,6 +51,17 @@
         ATRACE_BEGIN(buf);
     }
 
-}; // class TraceUtils
+    static void instantFormat(const char* fmt, ...) {
+        const int BUFFER_SIZE = 256;
+        va_list ap;
+        char buf[BUFFER_SIZE];
 
-} /* namespace android */
+        va_start(ap, fmt);
+        vsnprintf(buf, BUFFER_SIZE, fmt, ap);
+        va_end(ap);
+
+        ATRACE_INSTANT(buf);
+    }
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 0e1d258..ac74c8a 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -171,6 +171,8 @@
                 static_cast<uint32_t>(os::InputConfig::SPY),
         INTERCEPTS_STYLUS =
                 static_cast<uint32_t>(os::InputConfig::INTERCEPTS_STYLUS),
+        CLONE =
+                static_cast<uint32_t>(os::InputConfig::CLONE),
         // clang-format on
     };
 
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index e58543a..7b37b25 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -15,7 +15,6 @@
     name: "libgui_test",
     test_suites: ["device-tests"],
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -25,6 +24,7 @@
         "BLASTBufferQueue_test.cpp",
         "BufferItemConsumer_test.cpp",
         "BufferQueue_test.cpp",
+        "CompositorTiming_test.cpp",
         "CpuConsumer_test.cpp",
         "EndToEndNativeInputTest.cpp",
         "DisplayInfo_test.cpp",
@@ -75,7 +75,6 @@
     name: "libgui_multilib_test",
     test_suites: ["device-tests"],
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -102,7 +101,6 @@
     name: "SurfaceParcelable_test",
     test_suites: ["device-tests"],
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -131,7 +129,6 @@
 cc_test {
     name: "SamplingDemo",
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 3a9b2b8..3e563b2 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -162,6 +162,10 @@
         ASSERT_EQ(numFramesSubmitted, mBlastBufferQueueAdapter->mSubmitted.size());
     }
 
+    void mergeWithNextTransaction(Transaction* merge, uint64_t frameNumber) {
+        mBlastBufferQueueAdapter->mergeWithNextTransaction(merge, frameNumber);
+    }
+
 private:
     sp<TestBLASTBufferQueue> mBlastBufferQueueAdapter;
 };
@@ -1113,6 +1117,40 @@
     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}));
+    sync.apply();
+}
+
 // 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/CompositorTiming_test.cpp b/libs/gui/tests/CompositorTiming_test.cpp
new file mode 100644
index 0000000..d8bb21d
--- /dev/null
+++ b/libs/gui/tests/CompositorTiming_test.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+#include <gui/CompositorTiming.h>
+
+namespace android::test {
+namespace {
+
+constexpr nsecs_t kMillisecond = 1'000'000;
+constexpr nsecs_t kVsyncPeriod = 8'333'333;
+constexpr nsecs_t kVsyncPhase = -2'166'667;
+constexpr nsecs_t kIdealLatency = -kVsyncPhase;
+
+} // namespace
+
+TEST(CompositorTimingTest, InvalidVsyncPeriod) {
+    const nsecs_t vsyncDeadline = systemTime();
+    constexpr nsecs_t kInvalidVsyncPeriod = -1;
+
+    const gui::CompositorTiming timing(vsyncDeadline, kInvalidVsyncPeriod, kVsyncPhase,
+                                       kIdealLatency);
+
+    EXPECT_EQ(timing.deadline, 0);
+    EXPECT_EQ(timing.interval, gui::CompositorTiming::kDefaultVsyncPeriod);
+    EXPECT_EQ(timing.presentLatency, gui::CompositorTiming::kDefaultVsyncPeriod);
+}
+
+TEST(CompositorTimingTest, PresentLatencySnapping) {
+    for (nsecs_t presentDelay = 0, compositeTime = systemTime(); presentDelay < 10 * kVsyncPeriod;
+         presentDelay += kMillisecond, compositeTime += kVsyncPeriod) {
+        const nsecs_t presentLatency = kIdealLatency + presentDelay;
+        const nsecs_t vsyncDeadline = compositeTime + presentLatency + kVsyncPeriod;
+
+        const gui::CompositorTiming timing(vsyncDeadline, kVsyncPeriod, kVsyncPhase,
+                                           presentLatency);
+
+        EXPECT_EQ(timing.deadline, compositeTime + presentDelay + kVsyncPeriod);
+        EXPECT_EQ(timing.interval, kVsyncPeriod);
+
+        // The presentDelay should be rounded to a multiple of the VSYNC period, such that the
+        // remainder (presentLatency % interval) always evaluates to the VSYNC phase offset.
+        EXPECT_GE(timing.presentLatency, kIdealLatency);
+        EXPECT_EQ(timing.presentLatency % timing.interval, kIdealLatency);
+    }
+}
+
+} // namespace android::test
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 262987f..2637f59 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -566,6 +566,55 @@
     bgSurface->expectTap(12, 24);
 }
 
+TEST_F(InputSurfacesTest, touchable_region) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+
+    surface->mInputInfo.touchableRegion.set(Rect{19, 29, 21, 31});
+
+    surface->showAt(11, 22);
+
+    // A tap within the surface but outside the touchable region should not be sent to the surface.
+    injectTap(20, 30);
+    EXPECT_EQ(surface->consumeEvent(200 /*timeoutMs*/), nullptr);
+
+    injectTap(31, 52);
+    surface->expectTap(20, 30);
+}
+
+TEST_F(InputSurfacesTest, input_respects_touchable_region_offset_overflow) {
+    std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+    bgSurface->showAt(100, 100);
+
+    // Set the touchable region to the values at the limit of its corresponding type.
+    // Since the surface is offset from the origin, the touchable region will be transformed into
+    // display space, which would trigger an overflow or an underflow. Ensure that we are protected
+    // against such a situation.
+    fgSurface->mInputInfo.touchableRegion.orSelf(Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX});
+
+    fgSurface->showAt(100, 100);
+
+    // Expect no crash for overflow. The overflowed touchable region is ignored, so the background
+    // surface receives touch.
+    injectTap(112, 124);
+    bgSurface->expectTap(12, 24);
+}
+
+TEST_F(InputSurfacesTest, input_respects_scaled_touchable_region_overflow) {
+    std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+    bgSurface->showAt(0, 0);
+
+    fgSurface->mInputInfo.touchableRegion.orSelf(Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX});
+    fgSurface->showAt(0, 0);
+
+    fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); });
+
+    // Expect no crash for overflow.
+    injectTap(12, 24);
+    fgSurface->expectTap(6, 12);
+}
+
 // Ensure we ignore transparent region when getting screen bounds when positioning input frame.
 TEST_F(InputSurfacesTest, input_ignores_transparent_region) {
     std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
@@ -1135,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/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 4ab380c..71f2ad4 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -692,10 +692,6 @@
         mSupportsPresent = supportsPresent;
     }
 
-    sp<IDisplayEventConnection> createDisplayEventConnection(
-            ISurfaceComposer::VsyncSource, ISurfaceComposer::EventRegistrationFlags) override {
-        return nullptr;
-    }
     status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/,
                                  const Vector<ComposerState>& /*state*/,
                                  const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
@@ -709,8 +705,6 @@
         return NO_ERROR;
     }
 
-    void bootFinished() override {}
-
 protected:
     IBinder* onAsBinder() override { return nullptr; }
 
@@ -724,6 +718,15 @@
 
     void setSupportsPresent(bool supportsPresent) { mSupportsPresent = supportsPresent; }
 
+    binder::Status bootFinished() override { return binder::Status::ok(); }
+
+    binder::Status createDisplayEventConnection(
+            VsyncSource /*vsyncSource*/, EventRegistration /*eventRegistration*/,
+            sp<gui::IDisplayEventConnection>* outConnection) override {
+        *outConnection = nullptr;
+        return binder::Status::ok();
+    }
+
     binder::Status createConnection(sp<gui::ISurfaceComposerClient>* outClient) override {
         *outClient = nullptr;
         return binder::Status::ok();
@@ -742,10 +745,6 @@
         return binder::Status::ok();
     }
 
-    binder::Status getPrimaryPhysicalDisplayId(int64_t* /*outDisplayId*/) override {
-        return binder::Status::ok();
-    }
-
     binder::Status getPhysicalDisplayToken(int64_t /*displayId*/,
                                            sp<IBinder>* /*outDisplay*/) override {
         return binder::Status::ok();
@@ -1084,20 +1083,30 @@
 protected:
     struct FenceAndFenceTime {
         explicit FenceAndFenceTime(FenceToFenceTimeMap& fenceMap)
-           : mFence(new Fence),
-             mFenceTime(fenceMap.createFenceTimeForTest(mFence)) {}
-        sp<Fence> mFence { nullptr };
-        std::shared_ptr<FenceTime> mFenceTime { nullptr };
+              : mFenceTime(fenceMap.createFenceTimeForTest(mFence)) {}
+
+        sp<Fence> mFence = sp<Fence>::make();
+        std::shared_ptr<FenceTime> mFenceTime;
     };
 
+    static CompositorTiming makeCompositorTiming(nsecs_t deadline = 1'000'000'000,
+                                                 nsecs_t interval = 16'666'667,
+                                                 nsecs_t presentLatency = 50'000'000) {
+        CompositorTiming timing;
+        timing.deadline = deadline;
+        timing.interval = interval;
+        timing.presentLatency = presentLatency;
+        return timing;
+    }
+
     struct RefreshEvents {
         RefreshEvents(FenceToFenceTimeMap& fenceMap, nsecs_t refreshStart)
-          : mFenceMap(fenceMap),
-            kCompositorTiming(
-                {refreshStart, refreshStart + 1, refreshStart + 2 }),
-            kStartTime(refreshStart + 3),
-            kGpuCompositionDoneTime(refreshStart + 4),
-            kPresentTime(refreshStart + 5) {}
+              : mFenceMap(fenceMap),
+                kCompositorTiming(
+                        makeCompositorTiming(refreshStart, refreshStart + 1, refreshStart + 2)),
+                kStartTime(refreshStart + 3),
+                kGpuCompositionDoneTime(refreshStart + 4),
+                kPresentTime(refreshStart + 5) {}
 
         void signalPostCompositeFences() {
             mFenceMap.signalAllForTest(
@@ -1107,8 +1116,8 @@
 
         FenceToFenceTimeMap& mFenceMap;
 
-        FenceAndFenceTime mGpuCompositionDone { mFenceMap };
-        FenceAndFenceTime mPresent { mFenceMap };
+        FenceAndFenceTime mGpuCompositionDone{mFenceMap};
+        FenceAndFenceTime mPresent{mFenceMap};
 
         const CompositorTiming kCompositorTiming;
 
@@ -1374,11 +1383,7 @@
 // This test verifies that the frame timestamps are retrieved if explicitly
 // enabled via native_window_enable_frame_timestamps.
 TEST_F(GetFrameTimestampsTest, EnabledSimple) {
-    CompositorTiming initialCompositorTiming {
-        1000000000, // 1s deadline
-        16666667, // 16ms interval
-        50000000, // 50ms present latency
-    };
+    const CompositorTiming initialCompositorTiming = makeCompositorTiming();
     mCfeh->initializeCompositorTiming(initialCompositorTiming);
 
     enableFrameTimestamps();
@@ -1517,11 +1522,7 @@
 // This verifies the compositor timing is updated by refresh events
 // and piggy backed on a queue, dequeue, and enabling of timestamps..
 TEST_F(GetFrameTimestampsTest, CompositorTimingUpdatesBasic) {
-    CompositorTiming initialCompositorTiming {
-        1000000000, // 1s deadline
-        16666667, // 16ms interval
-        50000000, // 50ms present latency
-    };
+    const CompositorTiming initialCompositorTiming = makeCompositorTiming();
     mCfeh->initializeCompositorTiming(initialCompositorTiming);
 
     enableFrameTimestamps();
@@ -1602,11 +1603,7 @@
 // This verifies the compositor deadline properly snaps to the the next
 // deadline based on the current time.
 TEST_F(GetFrameTimestampsTest, CompositorTimingDeadlineSnaps) {
-    CompositorTiming initialCompositorTiming {
-        1000000000, // 1s deadline
-        16666667, // 16ms interval
-        50000000, // 50ms present latency
-    };
+    const CompositorTiming initialCompositorTiming = makeCompositorTiming();
     mCfeh->initializeCompositorTiming(initialCompositorTiming);
 
     enableFrameTimestamps();
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 1d4fc1f..5030d60 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -26,7 +26,6 @@
 filegroup {
     name: "inputconstants_aidl",
     srcs: [
-        "android/os/BlockUntrustedTouchesMode.aidl",
         "android/os/IInputConstants.aidl",
         "android/os/InputEventInjectionResult.aidl",
         "android/os/InputEventInjectionSync.aidl",
@@ -58,8 +57,6 @@
         "VirtualKeyMap.cpp",
     ],
 
-    clang: true,
-
     header_libs: ["jni_headers"],
     export_header_lib_headers: ["jni_headers"],
 
@@ -67,6 +64,7 @@
         "libbase",
         "liblog",
         "libcutils",
+        "libvintf",
     ],
 
     static_libs: [
@@ -103,9 +101,6 @@
 
             sanitize: {
                 misc_undefined: ["integer"],
-                diag: {
-                    misc_undefined: ["integer"],
-                },
             },
         },
         host: {
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index fe1754c..155cb04 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -22,7 +22,9 @@
 #include <inttypes.h>
 #include <string.h>
 
+#include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <cutils/compiler.h>
 #include <gui/constants.h>
 #include <input/DisplayViewport.h>
 #include <input/Input.h>
@@ -62,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) {
@@ -87,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) {}
 
@@ -542,7 +564,14 @@
 }
 
 const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
-    return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
+    if (CC_UNLIKELY(pointerIndex < 0 || pointerIndex >= getPointerCount())) {
+        LOG(FATAL) << __func__ << ": Invalid pointer index " << pointerIndex << " for " << *this;
+    }
+    const size_t position = getHistorySize() * getPointerCount() + pointerIndex;
+    if (CC_UNLIKELY(position < 0 || position >= mSamplePointerCoords.size())) {
+        LOG(FATAL) << __func__ << ": Invalid array index " << position << " for " << *this;
+    }
+    return &mSamplePointerCoords[position];
 }
 
 float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const {
@@ -555,7 +584,18 @@
 
 const PointerCoords* MotionEvent::getHistoricalRawPointerCoords(
         size_t pointerIndex, size_t historicalIndex) const {
-    return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex];
+    if (CC_UNLIKELY(pointerIndex < 0 || pointerIndex >= getPointerCount())) {
+        LOG(FATAL) << __func__ << ": Invalid pointer index " << pointerIndex << " for " << *this;
+    }
+    if (CC_UNLIKELY(historicalIndex < 0 || historicalIndex > getHistorySize())) {
+        LOG(FATAL) << __func__ << ": Invalid historical index " << historicalIndex << " for "
+                   << *this;
+    }
+    const size_t position = historicalIndex * getPointerCount() + pointerIndex;
+    if (CC_UNLIKELY(position < 0 || position >= mSamplePointerCoords.size())) {
+        LOG(FATAL) << __func__ << ": Invalid array index " << position << " for " << *this;
+    }
+    return &mSamplePointerCoords[position];
 }
 
 float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
@@ -903,6 +943,53 @@
     return out;
 }
 
+std::ostream& operator<<(std::ostream& out, const MotionEvent& event) {
+    out << "MotionEvent { action=" << MotionEvent::actionToString(event.getAction());
+    if (event.getActionButton() != 0) {
+        out << ", actionButton=" << std::to_string(event.getActionButton());
+    }
+    const size_t pointerCount = event.getPointerCount();
+    for (size_t i = 0; i < pointerCount; i++) {
+        out << ", id[" << i << "]=" << event.getPointerId(i);
+        float x = event.getX(i);
+        float y = event.getY(i);
+        if (x != 0 || y != 0) {
+            out << ", x[" << i << "]=" << x;
+            out << ", y[" << i << "]=" << y;
+        }
+        int toolType = event.getToolType(i);
+        if (toolType != AMOTION_EVENT_TOOL_TYPE_FINGER) {
+            out << ", toolType[" << i << "]=" << toolType;
+        }
+    }
+    if (event.getButtonState() != 0) {
+        out << ", buttonState=" << event.getButtonState();
+    }
+    if (event.getClassification() != MotionClassification::NONE) {
+        out << ", classification=" << motionClassificationToString(event.getClassification());
+    }
+    if (event.getMetaState() != 0) {
+        out << ", metaState=" << event.getMetaState();
+    }
+    if (event.getEdgeFlags() != 0) {
+        out << ", edgeFlags=" << event.getEdgeFlags();
+    }
+    if (pointerCount != 1) {
+        out << ", pointerCount=" << pointerCount;
+    }
+    if (event.getHistorySize() != 0) {
+        out << ", historySize=" << event.getHistorySize();
+    }
+    out << ", eventTime=" << event.getEventTime();
+    out << ", downTime=" << event.getDownTime();
+    out << ", deviceId=" << event.getDeviceId();
+    out << ", source=" << inputEventSourceToString(event.getSource());
+    out << ", displayId=" << event.getDisplayId();
+    out << ", eventId=" << event.getId();
+    out << "}";
+    return out;
+}
+
 // --- FocusEvent ---
 
 void FocusEvent::initialize(int32_t id, bool hasFocus) {
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 0bee1b6..a908969 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -53,33 +53,39 @@
 }
 
 std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
-        const InputDeviceIdentifier& deviceIdentifier,
-        InputDeviceConfigurationFileType type) {
+        const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type,
+        const char* suffix) {
     if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
         if (deviceIdentifier.version != 0) {
             // Try vendor product version.
-            std::string versionPath = getInputDeviceConfigurationFilePathByName(
-                    StringPrintf("Vendor_%04x_Product_%04x_Version_%04x",
-                            deviceIdentifier.vendor, deviceIdentifier.product,
-                            deviceIdentifier.version),
-                    type);
+            std::string versionPath =
+                    getInputDeviceConfigurationFilePathByName(StringPrintf("Vendor_%04x_Product_%"
+                                                                           "04x_Version_%04x%s",
+                                                                           deviceIdentifier.vendor,
+                                                                           deviceIdentifier.product,
+                                                                           deviceIdentifier.version,
+                                                                           suffix),
+                                                              type);
             if (!versionPath.empty()) {
                 return versionPath;
             }
         }
 
         // Try vendor product.
-        std::string productPath = getInputDeviceConfigurationFilePathByName(
-                StringPrintf("Vendor_%04x_Product_%04x",
-                        deviceIdentifier.vendor, deviceIdentifier.product),
-                type);
+        std::string productPath =
+                getInputDeviceConfigurationFilePathByName(StringPrintf("Vendor_%04x_Product_%04x%s",
+                                                                       deviceIdentifier.vendor,
+                                                                       deviceIdentifier.product,
+                                                                       suffix),
+                                                          type);
         if (!productPath.empty()) {
             return productPath;
         }
     }
 
     // Try device name.
-    return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName(), type);
+    return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName() + suffix,
+                                                     type);
 }
 
 std::string getInputDeviceConfigurationFilePathByName(
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 6195052..8d8433b 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -51,7 +51,7 @@
 
 // Latency added during resampling.  A few milliseconds doesn't hurt much but
 // reduces the impact of mispredicted touch positions.
-static const nsecs_t RESAMPLE_LATENCY = 5 * NANOS_PER_MS;
+const std::chrono::duration RESAMPLE_LATENCY = 5ms;
 
 // Minimum time difference between consecutive samples before attempting to resample.
 static const nsecs_t RESAMPLE_MIN_DELTA = 2 * NANOS_PER_MS;
@@ -721,7 +721,11 @@
 // --- InputConsumer ---
 
 InputConsumer::InputConsumer(const std::shared_ptr<InputChannel>& channel)
-      : mResampleTouch(isTouchResamplingEnabled()), mChannel(channel), mMsgDeferred(false) {}
+      : InputConsumer(channel, isTouchResamplingEnabled()) {}
+
+InputConsumer::InputConsumer(const std::shared_ptr<InputChannel>& channel,
+                             bool enableTouchResampling)
+      : mResampleTouch(enableTouchResampling), mChannel(channel), mMsgDeferred(false) {}
 
 InputConsumer::~InputConsumer() {
 }
@@ -751,7 +755,10 @@
             // Receive a fresh message.
             status_t result = mChannel->receiveMessage(&mMsg);
             if (result == OK) {
-                mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC));
+                const auto [_, inserted] =
+                        mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC));
+                LOG_ALWAYS_FATAL_IF(!inserted, "Already have a consume time for seq=%" PRIu32,
+                                    mMsg.header.seq);
             }
             if (result) {
                 // Consume the next batched event unless batches are being held for later.
@@ -918,7 +925,7 @@
 
         nsecs_t sampleTime = frameTime;
         if (mResampleTouch) {
-            sampleTime -= RESAMPLE_LATENCY;
+            sampleTime -= std::chrono::nanoseconds(RESAMPLE_LATENCY).count();
         }
         ssize_t split = findSampleNoLaterThan(batch, sampleTime);
         if (split < 0) {
@@ -1166,6 +1173,11 @@
         return;
     }
 
+    if (current->eventTime == sampleTime) {
+        // Prevents having 2 events with identical times and coordinates.
+        return;
+    }
+
     // Resample touch coordinates.
     History oldLastResample;
     oldLastResample.initializeFrom(touchState.lastResample);
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 2039fa6..422e6e0 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -304,9 +304,8 @@
 
 char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
     char16_t result = 0;
-    const Key* key;
-    const Behavior* behavior;
-    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
+    const Behavior* behavior = getKeyBehavior(keyCode, metaState);
+    if (behavior != nullptr) {
         result = behavior->character;
     }
 #if DEBUG_MAPPING
@@ -321,9 +320,8 @@
     outFallbackAction->metaState = 0;
 
     bool result = false;
-    const Key* key;
-    const Behavior* behavior;
-    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
+    const Behavior* behavior = getKeyBehavior(keyCode, metaState);
+    if (behavior != nullptr) {
         if (behavior->fallbackKeyCode) {
             outFallbackAction->keyCode = behavior->fallbackKeyCode;
             outFallbackAction->metaState = metaState & ~behavior->metaState;
@@ -347,12 +345,12 @@
         // Try to find the most general behavior that maps to this character.
         // For example, the base key behavior will usually be last in the list.
         // However, if we find a perfect meta state match for one behavior then use that one.
-        for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
-            if (behavior->character) {
+        for (const Behavior& behavior : key->behaviors) {
+            if (behavior.character) {
                 for (size_t i = 0; i < numChars; i++) {
-                    if (behavior->character == chars[i]) {
-                        result = behavior->character;
-                        if ((behavior->metaState & metaState) == behavior->metaState) {
+                    if (behavior.character == chars[i]) {
+                        result = behavior.character;
+                        if ((behavior.metaState & metaState) == behavior.metaState) {
                             goto ExactMatch;
                         }
                         break;
@@ -438,9 +436,8 @@
     *outKeyCode = keyCode;
     *outMetaState = metaState;
 
-    const Key* key;
-    const Behavior* behavior;
-    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
+    const Behavior* behavior = getKeyBehavior(keyCode, metaState);
+    if (behavior != nullptr) {
         if (behavior->replacementKeyCode) {
             *outKeyCode = behavior->replacementKeyCode;
             int32_t newMetaState = metaState & ~behavior->metaState;
@@ -484,21 +481,17 @@
     return false;
 }
 
-bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
-        const Key** outKey, const Behavior** outBehavior) const {
+const KeyCharacterMap::Behavior* KeyCharacterMap::getKeyBehavior(int32_t keyCode,
+                                                                 int32_t metaState) const {
     const Key* key;
     if (getKey(keyCode, &key)) {
-        const Behavior* behavior = key->firstBehavior;
-        while (behavior) {
-            if (matchesMetaState(metaState, behavior->metaState)) {
-                *outKey = key;
-                *outBehavior = behavior;
-                return true;
+        for (const Behavior& behavior : key->behaviors) {
+            if (matchesMetaState(metaState, behavior.metaState)) {
+                return &behavior;
             }
-            behavior = behavior->next;
         }
     }
-    return false;
+    return nullptr;
 }
 
 bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
@@ -543,12 +536,12 @@
         // Try to find the most general behavior that maps to this character.
         // For example, the base key behavior will usually be last in the list.
         const Behavior* found = nullptr;
-        for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
-            if (behavior->character == ch) {
-                found = behavior;
+        for (const Behavior& behavior : key->behaviors) {
+            if (behavior.character == ch) {
+                found = &behavior;
             }
         }
-        if (found) {
+        if (found != nullptr) {
             *outKeyCode = mKeys.keyAt(i);
             *outMetaState = found->metaState;
             return true;
@@ -706,7 +699,6 @@
         key->number = number;
         map->mKeys.add(keyCode, key);
 
-        Behavior* lastBehavior = nullptr;
         while (parcel->readInt32()) {
             int32_t metaState = parcel->readInt32();
             char16_t character = parcel->readInt32();
@@ -716,17 +708,12 @@
                 return nullptr;
             }
 
-            Behavior* behavior = new Behavior();
-            behavior->metaState = metaState;
-            behavior->character = character;
-            behavior->fallbackKeyCode = fallbackKeyCode;
-            behavior->replacementKeyCode = replacementKeyCode;
-            if (lastBehavior) {
-                lastBehavior->next = behavior;
-            } else {
-                key->firstBehavior = behavior;
-            }
-            lastBehavior = behavior;
+            key->behaviors.push_back({
+                    .metaState = metaState,
+                    .character = character,
+                    .fallbackKeyCode = fallbackKeyCode,
+                    .replacementKeyCode = replacementKeyCode,
+            });
         }
 
         if (parcel->errorCheck()) {
@@ -777,13 +764,12 @@
         parcel->writeInt32(keyCode);
         parcel->writeInt32(key->label);
         parcel->writeInt32(key->number);
-        for (const Behavior* behavior = key->firstBehavior; behavior != nullptr;
-                behavior = behavior->next) {
+        for (const Behavior& behavior : key->behaviors) {
             parcel->writeInt32(1);
-            parcel->writeInt32(behavior->metaState);
-            parcel->writeInt32(behavior->character);
-            parcel->writeInt32(behavior->fallbackKeyCode);
-            parcel->writeInt32(behavior->replacementKeyCode);
+            parcel->writeInt32(behavior.metaState);
+            parcel->writeInt32(behavior.character);
+            parcel->writeInt32(behavior.fallbackKeyCode);
+            parcel->writeInt32(behavior.replacementKeyCode);
         }
         parcel->writeInt32(0);
     }
@@ -804,38 +790,10 @@
 
 // --- KeyCharacterMap::Key ---
 
-KeyCharacterMap::Key::Key() :
-        label(0), number(0), firstBehavior(nullptr) {
-}
+KeyCharacterMap::Key::Key() : label(0), number(0) {}
 
-KeyCharacterMap::Key::Key(const Key& other) :
-        label(other.label), number(other.number),
-        firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : nullptr) {
-}
-
-KeyCharacterMap::Key::~Key() {
-    Behavior* behavior = firstBehavior;
-    while (behavior) {
-        Behavior* next = behavior->next;
-        delete behavior;
-        behavior = next;
-    }
-}
-
-
-// --- KeyCharacterMap::Behavior ---
-
-KeyCharacterMap::Behavior::Behavior() :
-        next(nullptr), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
-}
-
-KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
-        next(other.next ? new Behavior(*other.next) : nullptr),
-        metaState(other.metaState), character(other.character),
-        fallbackKeyCode(other.fallbackKeyCode),
-        replacementKeyCode(other.replacementKeyCode) {
-}
-
+KeyCharacterMap::Key::Key(const Key& other)
+      : label(other.label), number(other.number), behaviors(other.behaviors) {}
 
 // --- KeyCharacterMap::Parser ---
 
@@ -1213,23 +1171,21 @@
 #endif
             break;
         case PROPERTY_META: {
-            for (Behavior* b = key->firstBehavior; b; b = b->next) {
-                if (b->metaState == property.metaState) {
+            for (const Behavior& b : key->behaviors) {
+                if (b.metaState == property.metaState) {
                     ALOGE("%s: Duplicate key behavior for modifier.",
                             mTokenizer->getLocation().string());
                     return BAD_VALUE;
                 }
             }
-            Behavior* newBehavior = new Behavior(behavior);
-            newBehavior->metaState = property.metaState;
-            newBehavior->next = key->firstBehavior;
-            key->firstBehavior = newBehavior;
-#if DEBUG_PARSER
-            ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
-                    mKeyCode,
-                    newBehavior->metaState, newBehavior->character,
-                    newBehavior->fallbackKeyCode, newBehavior->replacementKeyCode);
-#endif
+            Behavior newBehavior = behavior;
+            newBehavior.metaState = property.metaState;
+            key->behaviors.push_front(newBehavior);
+            ALOGD_IF(DEBUG_PARSER,
+                     "Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
+                     mKeyCode, key->behaviors.front().metaState, key->behaviors.front().character,
+                     key->behaviors.front().fallbackKeyCode,
+                     key->behaviors.front().replacementKeyCode);
             break;
         }
         }
@@ -1242,8 +1198,8 @@
     if (!key->number) {
         char16_t digit = 0;
         char16_t symbol = 0;
-        for (Behavior* b = key->firstBehavior; b; b = b->next) {
-            char16_t ch = b->character;
+        for (const Behavior& b : key->behaviors) {
+            char16_t ch = b.character;
             if (ch) {
                 if (ch >= '0' && ch <= '9') {
                     digit = ch;
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index 7c25cda..59cc7d1 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -21,24 +21,33 @@
 #include <input/InputEventLabels.h>
 #include <input/KeyLayoutMap.h>
 #include <input/Keyboard.h>
+#include <log/log.h>
 #include <utils/Errors.h>
-#include <utils/Log.h>
 #include <utils/Timers.h>
 #include <utils/Tokenizer.h>
+#include <vintf/RuntimeInfo.h>
+#include <vintf/VintfObject.h>
 
 #include <cstdlib>
 #include <string_view>
 #include <unordered_map>
 
-// Enables debug output for the parser.
-#define DEBUG_PARSER 0
+/**
+ * Log debug output for the parser.
+ * Enable this via "adb shell setprop log.tag.KeyLayoutMapParser DEBUG" (requires restart)
+ */
+const bool DEBUG_PARSER =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Parser", ANDROID_LOG_INFO);
 
 // Enables debug output for parser performance.
 #define DEBUG_PARSER_PERFORMANCE 0
 
-// Enables debug output for mapping.
-#define DEBUG_MAPPING 0
-
+/**
+ * Log debug output for mapping.
+ * Enable this via "adb shell setprop log.tag.KeyLayoutMapMapping DEBUG" (requires restart)
+ */
+const bool DEBUG_MAPPING =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Mapping", ANDROID_LOG_INFO);
 
 namespace android {
 namespace {
@@ -69,6 +78,29 @@
          sensorPair<InputDeviceSensorType::GYROSCOPE_UNCALIBRATED>(),
          sensorPair<InputDeviceSensorType::SIGNIFICANT_MOTION>()};
 
+bool kernelConfigsArePresent(const std::set<std::string>& configs) {
+    std::shared_ptr<const android::vintf::RuntimeInfo> runtimeInfo =
+            android::vintf::VintfObject::GetInstance()->getRuntimeInfo(
+                    vintf::RuntimeInfo::FetchFlag::CONFIG_GZ);
+    LOG_ALWAYS_FATAL_IF(runtimeInfo == nullptr, "Kernel configs could not be fetched");
+
+    const std::map<std::string, std::string>& kernelConfigs = runtimeInfo->kernelConfigs();
+    for (const std::string& requiredConfig : configs) {
+        const auto configIt = kernelConfigs.find(requiredConfig);
+        if (configIt == kernelConfigs.end()) {
+            ALOGI("Required kernel config %s is not found", requiredConfig.c_str());
+            return false;
+        }
+        const std::string& option = configIt->second;
+        if (option != "y" && option != "m") {
+            ALOGI("Required kernel config %s has option %s", requiredConfig.c_str(),
+                  option.c_str());
+            return false;
+        }
+    }
+    return true;
+}
+
 } // namespace
 
 KeyLayoutMap::KeyLayoutMap() = default;
@@ -76,32 +108,34 @@
 
 base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::loadContents(const std::string& filename,
                                                                        const char* contents) {
-    Tokenizer* tokenizer;
-    status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
-    if (status) {
-        ALOGE("Error %d opening key layout map.", status);
-        return Errorf("Error {} opening key layout map file {}.", status, filename.c_str());
-    }
-    std::unique_ptr<Tokenizer> t(tokenizer);
-    auto ret = load(t.get());
-    if (ret.ok()) {
-        (*ret)->mLoadFileName = filename;
-    }
-    return ret;
+    return load(filename, contents);
 }
 
-base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(const std::string& filename) {
+base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(const std::string& filename,
+                                                               const char* contents) {
     Tokenizer* tokenizer;
-    status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
+    status_t status;
+    if (contents == nullptr) {
+        status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
+    } else {
+        status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
+    }
     if (status) {
         ALOGE("Error %d opening key layout map file %s.", status, filename.c_str());
         return Errorf("Error {} opening key layout map file {}.", status, filename.c_str());
     }
     std::unique_ptr<Tokenizer> t(tokenizer);
     auto ret = load(t.get());
-    if (ret.ok()) {
-        (*ret)->mLoadFileName = filename;
+    if (!ret.ok()) {
+        return ret;
     }
+    const std::shared_ptr<KeyLayoutMap>& map = *ret;
+    LOG_ALWAYS_FATAL_IF(map == nullptr, "Returned map should not be null if there's no error");
+    if (!kernelConfigsArePresent(map->mRequiredKernelConfigs)) {
+        ALOGI("Not loading %s because the required kernel configs are not set", filename.c_str());
+        return Errorf("Missing kernel config");
+    }
+    map->mLoadFileName = filename;
     return ret;
 }
 
@@ -134,9 +168,8 @@
         int32_t* outKeyCode, uint32_t* outFlags) const {
     const Key* key = getKey(scanCode, usageCode);
     if (!key) {
-#if DEBUG_MAPPING
-        ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
-#endif
+        ALOGD_IF(DEBUG_MAPPING, "mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode,
+                 usageCode);
         *outKeyCode = AKEYCODE_UNKNOWN;
         *outFlags = 0;
         return NAME_NOT_FOUND;
@@ -145,10 +178,9 @@
     *outKeyCode = key->keyCode;
     *outFlags = key->flags;
 
-#if DEBUG_MAPPING
-    ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.",
-            scanCode, usageCode, *outKeyCode, *outFlags);
-#endif
+    ALOGD_IF(DEBUG_MAPPING,
+             "mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.",
+             scanCode, usageCode, *outKeyCode, *outFlags);
     return NO_ERROR;
 }
 
@@ -156,103 +188,79 @@
 base::Result<std::pair<InputDeviceSensorType, int32_t>> KeyLayoutMap::mapSensor(int32_t absCode) {
     auto it = mSensorsByAbsCode.find(absCode);
     if (it == mSensorsByAbsCode.end()) {
-#if DEBUG_MAPPING
-        ALOGD("mapSensor: absCode=%d, ~ Failed.", absCode);
-#endif
+        ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, ~ Failed.", absCode);
         return Errorf("Can't find abs code {}.", absCode);
     }
     const Sensor& sensor = it->second;
-
-#if DEBUG_MAPPING
-    ALOGD("mapSensor: absCode=%d, sensorType=%s, sensorDataIndex=0x%x.", absCode,
-          ftl::enum_string(sensor.sensorType).c_str(), sensor.sensorDataIndex);
-#endif
+    ALOGD_IF(DEBUG_MAPPING, "mapSensor: absCode=%d, sensorType=%s, sensorDataIndex=0x%x.", absCode,
+             ftl::enum_string(sensor.sensorType).c_str(), sensor.sensorDataIndex);
     return std::make_pair(sensor.sensorType, sensor.sensorDataIndex);
 }
 
 const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
     if (usageCode) {
-        ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
-        if (index >= 0) {
-            return &mKeysByUsageCode.valueAt(index);
+        auto it = mKeysByUsageCode.find(usageCode);
+        if (it != mKeysByUsageCode.end()) {
+            return &it->second;
         }
     }
     if (scanCode) {
-        ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
-        if (index >= 0) {
-            return &mKeysByScanCode.valueAt(index);
+        auto it = mKeysByScanCode.find(scanCode);
+        if (it != mKeysByScanCode.end()) {
+            return &it->second;
         }
     }
     return nullptr;
 }
 
-status_t KeyLayoutMap::findScanCodesForKey(
-        int32_t keyCode, std::vector<int32_t>* outScanCodes) const {
-    const size_t N = mKeysByScanCode.size();
-    for (size_t i=0; i<N; i++) {
-        if (mKeysByScanCode.valueAt(i).keyCode == keyCode) {
-            outScanCodes->push_back(mKeysByScanCode.keyAt(i));
+std::vector<int32_t> KeyLayoutMap::findScanCodesForKey(int32_t keyCode) const {
+    std::vector<int32_t> scanCodes;
+    for (const auto& [scanCode, key] : mKeysByScanCode) {
+        if (keyCode == key.keyCode) {
+            scanCodes.push_back(scanCode);
         }
     }
-    return NO_ERROR;
+    return scanCodes;
 }
 
-status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
-    ssize_t index = mAxes.indexOfKey(scanCode);
-    if (index < 0) {
-#if DEBUG_MAPPING
-        ALOGD("mapAxis: scanCode=%d ~ Failed.", scanCode);
-#endif
-        return NAME_NOT_FOUND;
+std::optional<AxisInfo> KeyLayoutMap::mapAxis(int32_t scanCode) const {
+    auto it = mAxes.find(scanCode);
+    if (it == mAxes.end()) {
+        ALOGD_IF(DEBUG_MAPPING, "mapAxis: scanCode=%d ~ Failed.", scanCode);
+        return std::nullopt;
     }
 
-    *outAxisInfo = mAxes.valueAt(index);
-
-#if DEBUG_MAPPING
-    ALOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
-            "splitValue=%d, flatOverride=%d.",
-            scanCode,
-            outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis,
-            outAxisInfo->splitValue, outAxisInfo->flatOverride);
-#endif
-    return NO_ERROR;
+    const AxisInfo& axisInfo = it->second;
+    ALOGD_IF(DEBUG_MAPPING,
+             "mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
+             "splitValue=%d, flatOverride=%d.",
+             scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
+             axisInfo.flatOverride);
+    return axisInfo;
 }
 
-status_t KeyLayoutMap::findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const {
-    const size_t N = mLedsByScanCode.size();
-    for (size_t i = 0; i < N; i++) {
-        if (mLedsByScanCode.valueAt(i).ledCode == ledCode) {
-            *outScanCode = mLedsByScanCode.keyAt(i);
-#if DEBUG_MAPPING
-            ALOGD("findScanCodeForLed: ledCode=%d, scanCode=%d.", ledCode, *outScanCode);
-#endif
-            return NO_ERROR;
+std::optional<int32_t> KeyLayoutMap::findScanCodeForLed(int32_t ledCode) const {
+    for (const auto& [scanCode, led] : mLedsByScanCode) {
+        if (led.ledCode == ledCode) {
+            ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, scanCode=%d.", __func__, ledCode, scanCode);
+            return scanCode;
         }
     }
-#if DEBUG_MAPPING
-            ALOGD("findScanCodeForLed: ledCode=%d ~ Not found.", ledCode);
-#endif
-    return NAME_NOT_FOUND;
+    ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
+    return std::nullopt;
 }
 
-status_t KeyLayoutMap::findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const {
-    const size_t N = mLedsByUsageCode.size();
-    for (size_t i = 0; i < N; i++) {
-        if (mLedsByUsageCode.valueAt(i).ledCode == ledCode) {
-            *outUsageCode = mLedsByUsageCode.keyAt(i);
-#if DEBUG_MAPPING
-            ALOGD("findUsageForLed: ledCode=%d, usage=%x.", ledCode, *outUsageCode);
-#endif
-            return NO_ERROR;
+std::optional<int32_t> KeyLayoutMap::findUsageCodeForLed(int32_t ledCode) const {
+    for (const auto& [usageCode, led] : mLedsByUsageCode) {
+        if (led.ledCode == ledCode) {
+            ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d, usage=%x.", __func__, ledCode, usageCode);
+            return usageCode;
         }
     }
-#if DEBUG_MAPPING
-            ALOGD("findUsageForLed: ledCode=%d ~ Not found.", ledCode);
-#endif
-    return NAME_NOT_FOUND;
+    ALOGD_IF(DEBUG_MAPPING, "%s: ledCode=%d ~ Not found.", __func__, ledCode);
+    return std::nullopt;
 }
 
-
 // --- KeyLayoutMap::Parser ---
 
 KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
@@ -264,10 +272,8 @@
 
 status_t KeyLayoutMap::Parser::parse() {
     while (!mTokenizer->isEof()) {
-#if DEBUG_PARSER
-        ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
-                mTokenizer->peekRemainderOfLine().string());
-#endif
+        ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().string(),
+                 mTokenizer->peekRemainderOfLine().string());
 
         mTokenizer->skipDelimiters(WHITESPACE);
 
@@ -289,6 +295,10 @@
                 mTokenizer->skipDelimiters(WHITESPACE);
                 status_t status = parseSensor();
                 if (status) return status;
+            } else if (keywordToken == "requires_kernel_config") {
+                mTokenizer->skipDelimiters(WHITESPACE);
+                status_t status = parseRequiredKernelConfig();
+                if (status) return status;
             } else {
                 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
                         keywordToken.string());
@@ -325,8 +335,9 @@
                 mapUsage ? "usage" : "scan code", codeToken.string());
         return BAD_VALUE;
     }
-    KeyedVector<int32_t, Key>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
-    if (map.indexOfKey(code) >= 0) {
+    std::unordered_map<int32_t, Key>& map =
+            mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
+    if (map.find(code) != map.end()) {
         ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
                 mapUsage ? "usage" : "scan code", codeToken.string());
         return BAD_VALUE;
@@ -361,14 +372,13 @@
         flags |= flag;
     }
 
-#if DEBUG_PARSER
-    ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
-            mapUsage ? "usage" : "scan code", code, keyCode, flags);
-#endif
+    ALOGD_IF(DEBUG_PARSER, "Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
+             mapUsage ? "usage" : "scan code", code, keyCode, flags);
+
     Key key;
     key.keyCode = keyCode;
     key.flags = flags;
-    map.add(code, key);
+    map.insert({code, key});
     return NO_ERROR;
 }
 
@@ -381,7 +391,7 @@
                 scanCodeToken.string());
         return BAD_VALUE;
     }
-    if (mMap->mAxes.indexOfKey(scanCode) >= 0) {
+    if (mMap->mAxes.find(scanCode) != mMap->mAxes.end()) {
         ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
                 scanCodeToken.string());
         return BAD_VALUE;
@@ -462,14 +472,12 @@
         }
     }
 
-#if DEBUG_PARSER
-    ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
-            "splitValue=%d, flatOverride=%d.",
-            scanCode,
-            axisInfo.mode, axisInfo.axis, axisInfo.highAxis,
-            axisInfo.splitValue, axisInfo.flatOverride);
-#endif
-    mMap->mAxes.add(scanCode, axisInfo);
+    ALOGD_IF(DEBUG_PARSER,
+             "Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
+             "splitValue=%d, flatOverride=%d.",
+             scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue,
+             axisInfo.flatOverride);
+    mMap->mAxes.insert({scanCode, axisInfo});
     return NO_ERROR;
 }
 
@@ -489,8 +497,9 @@
         return BAD_VALUE;
     }
 
-    KeyedVector<int32_t, Led>& map = mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode;
-    if (map.indexOfKey(code) >= 0) {
+    std::unordered_map<int32_t, Led>& map =
+            mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode;
+    if (map.find(code) != map.end()) {
         ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(),
                 mapUsage ? "usage" : "scan code", codeToken.string());
         return BAD_VALUE;
@@ -505,14 +514,12 @@
         return BAD_VALUE;
     }
 
-#if DEBUG_PARSER
-    ALOGD("Parsed led %s: code=%d, ledCode=%d.",
-            mapUsage ? "usage" : "scan code", code, ledCode);
-#endif
+    ALOGD_IF(DEBUG_PARSER, "Parsed led %s: code=%d, ledCode=%d.", mapUsage ? "usage" : "scan code",
+             code, ledCode);
 
     Led led;
     led.ledCode = ledCode;
-    map.add(code, led);
+    map.insert({code, led});
     return NO_ERROR;
 }
 
@@ -584,10 +591,8 @@
     }
     int32_t sensorDataIndex = indexOpt.value();
 
-#if DEBUG_PARSER
-    ALOGD("Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", code,
-          ftl::enum_string(sensorType).c_str(), sensorDataIndex);
-#endif
+    ALOGD_IF(DEBUG_PARSER, "Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", code,
+             ftl::enum_string(sensorType).c_str(), sensorDataIndex);
 
     Sensor sensor;
     sensor.sensorType = sensorType;
@@ -596,4 +601,23 @@
     return NO_ERROR;
 }
 
+// Parse the name of a required kernel config.
+// The layout won't be used if the specified kernel config is not present
+// Examples:
+// requires_kernel_config CONFIG_HID_PLAYSTATION
+status_t KeyLayoutMap::Parser::parseRequiredKernelConfig() {
+    String8 codeToken = mTokenizer->nextToken(WHITESPACE);
+    std::string configName = codeToken.string();
+
+    const auto result = mMap->mRequiredKernelConfigs.emplace(configName);
+    if (!result.second) {
+        ALOGE("%s: Duplicate entry for required kernel config %s.",
+              mTokenizer->getLocation().string(), configName.c_str());
+        return BAD_VALUE;
+    }
+
+    ALOGD_IF(DEBUG_PARSER, "Parsed required kernel config: name=%s", configName.c_str());
+    return NO_ERROR;
+}
+
 } // namespace android
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index f0895b3..3f8467d 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -20,16 +20,23 @@
 #include <unistd.h>
 #include <limits.h>
 
-#include <input/Keyboard.h>
-#include <input/InputEventLabels.h>
-#include <input/KeyLayoutMap.h>
-#include <input/KeyCharacterMap.h>
 #include <input/InputDevice.h>
+#include <input/InputEventLabels.h>
+#include <input/KeyCharacterMap.h>
+#include <input/KeyLayoutMap.h>
+#include <input/Keyboard.h>
+#include <log/log.h>
 #include <utils/Errors.h>
-#include <utils/Log.h>
 
 namespace android {
 
+static std::string getPath(const InputDeviceIdentifier& deviceIdentifier, const std::string& name,
+                           InputDeviceConfigurationFileType type) {
+    return name.empty()
+            ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
+            : getInputDeviceConfigurationFilePathByName(name, type);
+}
+
 // --- KeyMap ---
 
 KeyMap::KeyMap() {
@@ -42,25 +49,23 @@
         const PropertyMap* deviceConfiguration) {
     // Use the configured key layout if available.
     if (deviceConfiguration) {
-        String8 keyLayoutName;
-        if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
-                keyLayoutName)) {
+        std::string keyLayoutName;
+        if (deviceConfiguration->tryGetProperty("keyboard.layout", keyLayoutName)) {
             status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str());
             if (status == NAME_NOT_FOUND) {
                 ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
-                        "it was not found.",
-                        deviceIdentifier.name.c_str(), keyLayoutName.string());
+                      "it was not found.",
+                      deviceIdentifier.name.c_str(), keyLayoutName.c_str());
             }
         }
 
-        String8 keyCharacterMapName;
-        if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
-                keyCharacterMapName)) {
+        std::string keyCharacterMapName;
+        if (deviceConfiguration->tryGetProperty("keyboard.characterMap", keyCharacterMapName)) {
             status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str());
             if (status == NAME_NOT_FOUND) {
                 ALOGE("Configuration for keyboard device '%s' requested keyboard character "
-                        "map '%s' but it was not found.",
-                        deviceIdentifier.name.c_str(), keyCharacterMapName.string());
+                      "map '%s' but it was not found.",
+                      deviceIdentifier.name.c_str(), keyCharacterMapName.c_str());
             }
         }
 
@@ -111,11 +116,25 @@
     }
 
     base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(path);
+    if (ret.ok()) {
+        keyLayoutMap = *ret;
+        keyLayoutFile = path;
+        return OK;
+    }
+
+    // Try to load fallback layout if the regular layout could not be loaded due to missing
+    // kernel modules
+    std::string fallbackPath(
+            getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier,
+                                                                  InputDeviceConfigurationFileType::
+                                                                          KEY_LAYOUT,
+                                                                  "_fallback"));
+    ret = KeyLayoutMap::load(fallbackPath);
     if (!ret.ok()) {
         return ret.error().code();
     }
     keyLayoutMap = *ret;
-    keyLayoutFile = path;
+    keyLayoutFile = fallbackPath;
     return OK;
 }
 
@@ -137,14 +156,6 @@
     return OK;
 }
 
-std::string KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
-        const std::string& name, InputDeviceConfigurationFileType type) {
-    return name.empty()
-            ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
-            : getInputDeviceConfigurationFilePathByName(name, type);
-}
-
-
 // --- Global functions ---
 
 bool isKeyboardSpecialFunction(const PropertyMap* config) {
@@ -152,7 +163,7 @@
         return false;
     }
     bool isSpecialFunction = false;
-    config->tryGetProperty(String8("keyboard.specialFunction"), isSpecialFunction);
+    config->tryGetProperty("keyboard.specialFunction", isSpecialFunction);
     return isSpecialFunction;
 }
 
@@ -167,8 +178,7 @@
 
     if (deviceConfiguration) {
         bool builtIn = false;
-        if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn)
-                && builtIn) {
+        if (deviceConfiguration->tryGetProperty("keyboard.builtIn", builtIn) && builtIn) {
             return true;
         }
     }
diff --git a/libs/input/PrintTools.cpp b/libs/input/PrintTools.cpp
index 5d6ae4e..01f6bf5 100644
--- a/libs/input/PrintTools.cpp
+++ b/libs/input/PrintTools.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "PrintTools"
 
 #include <input/PrintTools.h>
+#include <sstream>
 
 namespace android {
 
@@ -24,4 +25,20 @@
     return value ? "true" : "false";
 }
 
+std::string addLinePrefix(std::string str, const std::string& prefix) {
+    std::stringstream ss;
+    bool newLineStarted = true;
+    for (const auto& ch : str) {
+        if (newLineStarted) {
+            ss << prefix;
+            newLineStarted = false;
+        }
+        if (ch == '\n') {
+            newLineStarted = true;
+        }
+        ss << ch;
+    }
+    return ss.str();
+}
+
 } // namespace android
diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp
index a842166..662e568 100644
--- a/libs/input/PropertyMap.cpp
+++ b/libs/input/PropertyMap.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "PropertyMap"
 
 #include <input/PropertyMap.h>
+#include <log/log.h>
 
 // Enables debug output for the parser.
 #define DEBUG_PARSER 0
@@ -39,25 +40,25 @@
     mProperties.clear();
 }
 
-void PropertyMap::addProperty(const String8& key, const String8& value) {
-    mProperties.add(key, value);
+void PropertyMap::addProperty(const std::string& key, const std::string& value) {
+    mProperties.emplace(key, value);
 }
 
-bool PropertyMap::hasProperty(const String8& key) const {
-    return mProperties.indexOfKey(key) >= 0;
+bool PropertyMap::hasProperty(const std::string& key) const {
+    return mProperties.find(key) != mProperties.end();
 }
 
-bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const {
-    ssize_t index = mProperties.indexOfKey(key);
-    if (index < 0) {
+bool PropertyMap::tryGetProperty(const std::string& key, std::string& outValue) const {
+    auto it = mProperties.find(key);
+    if (it == mProperties.end()) {
         return false;
     }
 
-    outValue = mProperties.valueAt(index);
+    outValue = it->second;
     return true;
 }
 
-bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const {
+bool PropertyMap::tryGetProperty(const std::string& key, bool& outValue) const {
     int32_t intValue;
     if (!tryGetProperty(key, intValue)) {
         return false;
@@ -67,34 +68,34 @@
     return true;
 }
 
-bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const {
-    String8 stringValue;
+bool PropertyMap::tryGetProperty(const std::string& key, int32_t& outValue) const {
+    std::string stringValue;
     if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) {
         return false;
     }
 
     char* end;
-    int value = strtol(stringValue.string(), &end, 10);
+    int value = strtol(stringValue.c_str(), &end, 10);
     if (*end != '\0') {
-        ALOGW("Property key '%s' has invalid value '%s'.  Expected an integer.", key.string(),
-              stringValue.string());
+        ALOGW("Property key '%s' has invalid value '%s'.  Expected an integer.", key.c_str(),
+              stringValue.c_str());
         return false;
     }
     outValue = value;
     return true;
 }
 
-bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const {
-    String8 stringValue;
+bool PropertyMap::tryGetProperty(const std::string& key, float& outValue) const {
+    std::string stringValue;
     if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) {
         return false;
     }
 
     char* end;
-    float value = strtof(stringValue.string(), &end);
+    float value = strtof(stringValue.c_str(), &end);
     if (*end != '\0') {
-        ALOGW("Property key '%s' has invalid value '%s'.  Expected a float.", key.string(),
-              stringValue.string());
+        ALOGW("Property key '%s' has invalid value '%s'.  Expected a float.", key.c_str(),
+              stringValue.c_str());
         return false;
     }
     outValue = value;
@@ -102,8 +103,8 @@
 }
 
 void PropertyMap::addAll(const PropertyMap* map) {
-    for (size_t i = 0; i < map->mProperties.size(); i++) {
-        mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i));
+    for (const auto& [key, value] : map->mProperties) {
+        mProperties.emplace(key, value);
     }
 }
 
@@ -184,13 +185,13 @@
                 return BAD_VALUE;
             }
 
-            if (mMap->hasProperty(keyToken)) {
+            if (mMap->hasProperty(keyToken.string())) {
                 ALOGE("%s: Duplicate property value for key '%s'.",
                       mTokenizer->getLocation().string(), keyToken.string());
                 return BAD_VALUE;
             }
 
-            mMap->addProperty(keyToken, valueToken);
+            mMap->addProperty(keyToken.string(), valueToken.string());
         }
 
         mTokenizer->nextLine();
diff --git a/libs/input/PropertyMap_fuzz.cpp b/libs/input/PropertyMap_fuzz.cpp
index afb97a1..d985dc1 100755
--- a/libs/input/PropertyMap_fuzz.cpp
+++ b/libs/input/PropertyMap_fuzz.cpp
@@ -17,32 +17,22 @@
 #include "android-base/file.h"
 #include "fuzzer/FuzzedDataProvider.h"
 #include "input/PropertyMap.h"
-#include "utils/String8.h"
 
 static constexpr int MAX_FILE_SIZE = 256;
 static constexpr int MAX_STR_LEN = 2048;
 static constexpr int MAX_OPERATIONS = 1000;
 
-static const std::vector<std::function<void(FuzzedDataProvider*, android::PropertyMap)>>
+static const std::vector<std::function<void(FuzzedDataProvider*, android::PropertyMap&)>>
         operations = {
-                [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void {
-                    propertyMap.getProperties();
-                },
-                [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void {
+                [](FuzzedDataProvider*, android::PropertyMap& propertyMap) -> void {
                     propertyMap.clear();
                 },
-                [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
-                    std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
-                    android::String8 key = android::String8(keyStr.c_str());
-                    propertyMap.hasProperty(key);
-                },
-                [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
-                    std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
-                    android::String8 key = android::String8(keyStr.c_str());
-                    android::String8 out;
+                [](FuzzedDataProvider* dataProvider, android::PropertyMap& propertyMap) -> void {
+                    std::string key = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
+                    std::string out;
                     propertyMap.tryGetProperty(key, out);
                 },
-                [](FuzzedDataProvider* dataProvider, android::PropertyMap /*unused*/) -> void {
+                [](FuzzedDataProvider* dataProvider, android::PropertyMap& /*unused*/) -> void {
                     TemporaryFile tf;
                     // Generate file contents
                     std::string contents = dataProvider->ConsumeRandomLengthString(MAX_FILE_SIZE);
@@ -54,17 +44,15 @@
                     }
                     android::PropertyMap::load(tf.path);
                 },
-                [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
-                    std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
-                    std::string valStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
-                    android::String8 key = android::String8(keyStr.c_str());
-                    android::String8 val = android::String8(valStr.c_str());
+                [](FuzzedDataProvider* dataProvider, android::PropertyMap& propertyMap) -> void {
+                    std::string key = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
+                    std::string val = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
                     propertyMap.addProperty(key, val);
                 },
 };
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     FuzzedDataProvider dataProvider(data, size);
-    android::PropertyMap propertyMap = android::PropertyMap();
+    android::PropertyMap propertyMap;
 
     int opsRun = 0;
     while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 7f427f2..76aaf61 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -27,6 +27,8 @@
 #include <utils/BitSet.h>
 #include <utils/Timers.h>
 
+using std::literals::chrono_literals::operator""ms;
+
 namespace android {
 
 /**
@@ -57,8 +59,14 @@
 // Some input devices do not send ACTION_MOVE events in the case where a pointer has
 // stopped.  We need to detect this case so that we can accurately predict the
 // velocity after the pointer starts moving again.
-static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS;
+static const std::chrono::duration ASSUME_POINTER_STOPPED_TIME = 40ms;
 
+static std::string toString(std::chrono::nanoseconds t) {
+    std::stringstream stream;
+    stream.precision(1);
+    stream << std::fixed << std::chrono::duration<float, std::milli>(t).count() << " ms";
+    return stream.str();
+}
 
 static float vectorDot(const float* a, const float* b, uint32_t m) {
     float r = 0;
@@ -146,18 +154,14 @@
         VelocityTracker::Strategy strategy) {
     switch (strategy) {
         case VelocityTracker::Strategy::IMPULSE:
-            if (DEBUG_STRATEGY) {
-                ALOGI("Initializing impulse strategy");
-            }
+            ALOGI_IF(DEBUG_STRATEGY, "Initializing impulse strategy");
             return std::make_unique<ImpulseVelocityTrackerStrategy>();
 
         case VelocityTracker::Strategy::LSQ1:
             return std::make_unique<LeastSquaresVelocityTrackerStrategy>(1);
 
         case VelocityTracker::Strategy::LSQ2:
-            if (DEBUG_STRATEGY && !DEBUG_IMPULSE) {
-                ALOGI("Initializing lsq2 strategy");
-            }
+            ALOGI_IF(DEBUG_STRATEGY && !DEBUG_IMPULSE, "Initializing lsq2 strategy");
             return std::make_unique<LeastSquaresVelocityTrackerStrategy>(2);
 
         case VelocityTracker::Strategy::LSQ3:
@@ -221,12 +225,11 @@
         idBits.clearLastMarkedBit();
     }
 
-    if ((mCurrentPointerIdBits.value & idBits.value)
-            && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) {
-        if (DEBUG_VELOCITY) {
-            ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.",
-                  (eventTime - mLastEventTime) * 0.000001f);
-        }
+    if ((mCurrentPointerIdBits.value & idBits.value) &&
+        std::chrono::nanoseconds(eventTime - mLastEventTime) > ASSUME_POINTER_STOPPED_TIME) {
+        ALOGD_IF(DEBUG_VELOCITY, "VelocityTracker: stopped for %s, clearing state.",
+                 toString(std::chrono::nanoseconds(eventTime - mLastEventTime)).c_str());
+
         // We have not received any movements for too long.  Assume that all pointers
         // have stopped.
         mStrategy->clear();
@@ -281,8 +284,18 @@
     case AMOTION_EVENT_ACTION_MOVE:
     case AMOTION_EVENT_ACTION_HOVER_MOVE:
         break;
-    default:
-        // Ignore all other actions because they do not convey any new information about
+    case AMOTION_EVENT_ACTION_POINTER_UP:
+    case AMOTION_EVENT_ACTION_UP: {
+        std::chrono::nanoseconds delaySinceLastEvent(event->getEventTime() - mLastEventTime);
+        if (delaySinceLastEvent > ASSUME_POINTER_STOPPED_TIME) {
+            ALOGD_IF(DEBUG_VELOCITY,
+                     "VelocityTracker: stopped for %s, clearing state upon pointer liftoff.",
+                     toString(delaySinceLastEvent).c_str());
+            // We have not received any movements for too long.  Assume that all pointers
+            // have stopped.
+            mStrategy->clear();
+        }
+        // These actions because they do not convey any new information about
         // pointer movement.  We also want to preserve the last known velocity of the pointers.
         // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position
         // of the pointers that went up.  ACTION_POINTER_UP does include the new position of
@@ -292,6 +305,10 @@
         // before adding the movement.
         return;
     }
+    default:
+        // Ignore all other actions.
+        return;
+    }
 
     size_t pointerCount = event->getPointerCount();
     if (pointerCount > MAX_POINTERS) {
@@ -438,10 +455,10 @@
 static bool solveLeastSquares(const std::vector<float>& x, const std::vector<float>& y,
                               const std::vector<float>& w, uint32_t n, float* outB, float* outDet) {
     const size_t m = x.size();
-    if (DEBUG_STRATEGY) {
-        ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
-              vectorToString(x).c_str(), vectorToString(y).c_str(), vectorToString(w).c_str());
-    }
+
+    ALOGD_IF(DEBUG_STRATEGY, "solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
+             vectorToString(x).c_str(), vectorToString(y).c_str(), vectorToString(w).c_str());
+
     LOG_ALWAYS_FATAL_IF(m != y.size() || m != w.size(), "Mismatched vector sizes");
 
     // Expand the X vector to a matrix A, pre-multiplied by the weights.
@@ -452,9 +469,9 @@
             a[i][h] = a[i - 1][h] * x[h];
         }
     }
-    if (DEBUG_STRATEGY) {
-        ALOGD("  - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str());
-    }
+
+    ALOGD_IF(DEBUG_STRATEGY, "  - a=%s",
+             matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str());
 
     // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
     float q[n][m]; // orthonormal basis, column-major order
@@ -473,9 +490,7 @@
         float norm = vectorNorm(&q[j][0], m);
         if (norm < 0.000001f) {
             // vectors are linearly dependent or zero so no solution
-            if (DEBUG_STRATEGY) {
-                ALOGD("  - no solution, norm=%f", norm);
-            }
+            ALOGD_IF(DEBUG_STRATEGY, "  - no solution, norm=%f", norm);
             return false;
         }
 
@@ -518,9 +533,8 @@
         }
         outB[i] /= r[i][i];
     }
-    if (DEBUG_STRATEGY) {
-        ALOGD("  - b=%s", vectorToString(outB, n).c_str());
-    }
+
+    ALOGD_IF(DEBUG_STRATEGY, "  - b=%s", vectorToString(outB, n).c_str());
 
     // Calculate the coefficient of determination as 1 - (SSerr / SStot) where
     // SSerr is the residual sum of squares (variance of the error),
@@ -546,11 +560,11 @@
         sstot += w[h] * w[h] * var * var;
     }
     *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1;
-    if (DEBUG_STRATEGY) {
-        ALOGD("  - sserr=%f", sserr);
-        ALOGD("  - sstot=%f", sstot);
-        ALOGD("  - det=%f", *outDet);
-    }
+
+    ALOGD_IF(DEBUG_STRATEGY, "  - sserr=%f", sserr);
+    ALOGD_IF(DEBUG_STRATEGY, "  - sstot=%f", sstot);
+    ALOGD_IF(DEBUG_STRATEGY, "  - det=%f", *outDet);
+
     return true;
 }
 
@@ -673,11 +687,11 @@
             outEstimator->time = newestMovement.eventTime;
             outEstimator->degree = degree;
             outEstimator->confidence = xdet * ydet;
-            if (DEBUG_STRATEGY) {
-                ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
-                      int(outEstimator->degree), vectorToString(outEstimator->xCoeff, n).c_str(),
-                      vectorToString(outEstimator->yCoeff, n).c_str(), outEstimator->confidence);
-            }
+
+            ALOGD_IF(DEBUG_STRATEGY, "estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
+                     int(outEstimator->degree), vectorToString(outEstimator->xCoeff, n).c_str(),
+                     vectorToString(outEstimator->yCoeff, n).c_str(), outEstimator->confidence);
+
             return true;
         }
     }
@@ -1185,9 +1199,10 @@
     outEstimator->time = newestMovement.eventTime;
     outEstimator->degree = 2; // similar results to 2nd degree fit
     outEstimator->confidence = 1;
-    if (DEBUG_STRATEGY) {
-        ALOGD("velocity: (%.1f, %.1f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
-    }
+
+    ALOGD_IF(DEBUG_STRATEGY, "velocity: (%.1f, %.1f)", outEstimator->xCoeff[1],
+             outEstimator->yCoeff[1]);
+
     if (DEBUG_IMPULSE) {
         // TODO(b/134179997): delete this block once the switch to 'impulse' is complete.
         // Calculate the lsq2 velocity for the same inputs to allow runtime comparisons
diff --git a/libs/input/android/os/BlockUntrustedTouchesMode.aidl b/libs/input/android/os/BlockUntrustedTouchesMode.aidl
deleted file mode 100644
index 9504e99..0000000
--- a/libs/input/android/os/BlockUntrustedTouchesMode.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Copyright (c) 2020, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-
-/**
-  * Block untrusted touches feature mode.
-  *
-  * @hide
-  */
-@Backing(type="int")
-enum BlockUntrustedTouchesMode {
-    /** Feature is off. */
-    DISABLED,
-
-    /** Untrusted touches are flagged but not blocked. */
-    PERMISSIVE,
-
-    /** Untrusted touches are blocked. */
-    BLOCK
-}
diff --git a/libs/input/android/os/InputConfig.aidl b/libs/input/android/os/InputConfig.aidl
index 6d1b396..4e644ff 100644
--- a/libs/input/android/os/InputConfig.aidl
+++ b/libs/input/android/os/InputConfig.aidl
@@ -144,4 +144,10 @@
      * It is not valid to set this configuration if {@link #TRUSTED_OVERLAY} is not set.
      */
     INTERCEPTS_STYLUS            = 1 << 15,
+
+    /**
+     * The window is a clone of another window. This may be treated differently since there's
+     * likely a duplicate window with the same client token, but different bounds.
+     */
+    CLONE                        = 1 << 16,
 }
diff --git a/libs/input/android/os/InputEventInjectionResult.aidl b/libs/input/android/os/InputEventInjectionResult.aidl
index 34f10ec..3bc7068 100644
--- a/libs/input/android/os/InputEventInjectionResult.aidl
+++ b/libs/input/android/os/InputEventInjectionResult.aidl
@@ -29,9 +29,8 @@
     /* Injection succeeded. */
     SUCCEEDED = 0,
 
-    /* Injection failed because the injector did not have permission to inject
-     * into the application with input focus. */
-    PERMISSION_DENIED = 1,
+    /* Injection failed because the injected event did not target the appropriate window. */
+    TARGET_MISMATCH = 1,
 
     /* Injection failed because there were no available input targets. */
     FAILED = 2,
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 6ffe851..c53811a 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -16,6 +16,7 @@
         "InputDevice_test.cpp",
         "InputEvent_test.cpp",
         "InputPublisherAndConsumer_test.cpp",
+        "TouchResampling_test.cpp",
         "TouchVideoFrame_test.cpp",
         "VelocityTracker_test.cpp",
         "VerifiedInputEvent_test.cpp",
@@ -36,8 +37,9 @@
         "liblog",
         "libui",
         "libutils",
+        "libvintf",
     ],
-    data: ["data/*.kcm"],
+    data: ["data/*"],
     test_suites: ["device-tests"],
 }
 
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
index 61e88df..e872fa4 100644
--- a/libs/input/tests/InputDevice_test.cpp
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -64,13 +64,11 @@
         mKeyMap.keyCharacterMapFile = path;
     }
 
-    virtual void SetUp() override {
+    void SetUp() override {
         loadKeyLayout("Generic");
         loadKeyCharacterMap("Generic");
     }
 
-    virtual void TearDown() override {}
-
     KeyMap mKeyMap;
 };
 
@@ -132,4 +130,20 @@
     ASSERT_EQ(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
 }
 
+TEST(InputDeviceKeyLayoutTest, DoesNotLoadWhenRequiredKernelConfigIsMissing) {
+    std::string klPath = base::GetExecutableDirectory() + "/data/kl_with_required_fake_config.kl";
+    base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
+    ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath;
+    // We assert error message here because it's used by 'validatekeymaps' tool
+    ASSERT_EQ("Missing kernel config", ret.error().message());
+}
+
+TEST(InputDeviceKeyLayoutTest, LoadsWhenRequiredKernelConfigIsPresent) {
+    std::string klPath = base::GetExecutableDirectory() + "/data/kl_with_required_real_config.kl";
+    base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
+    ASSERT_TRUE(ret.ok()) << "Cannot load KeyLayout at " << klPath;
+    const std::shared_ptr<KeyLayoutMap>& map = *ret;
+    ASSERT_NE(nullptr, map) << "Map should be valid because CONFIG_UHID should always be present";
+}
+
 } // namespace android
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/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 05bc0bc..70e4fda 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -16,17 +16,10 @@
 
 #include "TestHelpers.h"
 
-#include <unistd.h>
-#include <sys/mman.h>
-#include <time.h>
-
 #include <attestation/HmacKeyManager.h>
-#include <cutils/ashmem.h>
 #include <gtest/gtest.h>
 #include <gui/constants.h>
 #include <input/InputTransport.h>
-#include <utils/StopWatch.h>
-#include <utils/Timers.h>
 
 using android::base::Result;
 
diff --git a/libs/input/tests/TouchResampling_test.cpp b/libs/input/tests/TouchResampling_test.cpp
new file mode 100644
index 0000000..c09a8e9
--- /dev/null
+++ b/libs/input/tests/TouchResampling_test.cpp
@@ -0,0 +1,562 @@
+/*
+ * 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 "TestHelpers.h"
+
+#include <chrono>
+#include <vector>
+
+#include <attestation/HmacKeyManager.h>
+#include <gtest/gtest.h>
+#include <input/InputTransport.h>
+
+using namespace std::chrono_literals;
+
+namespace android {
+
+struct Pointer {
+    int32_t id;
+    float x;
+    float y;
+};
+
+struct InputEventEntry {
+    std::chrono::nanoseconds eventTime;
+    std::vector<Pointer> pointers;
+    int32_t action;
+};
+
+class TouchResamplingTest : public testing::Test {
+protected:
+    std::unique_ptr<InputPublisher> mPublisher;
+    std::unique_ptr<InputConsumer> mConsumer;
+    PreallocatedInputEventFactory mEventFactory;
+
+    uint32_t mSeq = 1;
+
+    void SetUp() override {
+        std::unique_ptr<InputChannel> serverChannel, clientChannel;
+        status_t result =
+                InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel);
+        ASSERT_EQ(OK, result);
+
+        mPublisher = std::make_unique<InputPublisher>(std::move(serverChannel));
+        mConsumer = std::make_unique<InputConsumer>(std::move(clientChannel),
+                                                    true /* enableTouchResampling */);
+    }
+
+    status_t publishSimpleMotionEventWithCoords(int32_t action, nsecs_t eventTime,
+                                                const std::vector<PointerProperties>& properties,
+                                                const std::vector<PointerCoords>& coords);
+    void publishSimpleMotionEvent(int32_t action, nsecs_t eventTime,
+                                  const std::vector<Pointer>& pointers);
+    void publishInputEventEntries(const std::vector<InputEventEntry>& entries);
+    void consumeInputEventEntries(const std::vector<InputEventEntry>& entries,
+                                  std::chrono::nanoseconds frameTime);
+    void receiveResponseUntilSequence(uint32_t seq);
+};
+
+status_t TouchResamplingTest::publishSimpleMotionEventWithCoords(
+        int32_t action, nsecs_t eventTime, const std::vector<PointerProperties>& properties,
+        const std::vector<PointerCoords>& coords) {
+    const ui::Transform identityTransform;
+    const nsecs_t downTime = 0;
+
+    if (action == AMOTION_EVENT_ACTION_DOWN && eventTime != 0) {
+        ADD_FAILURE() << "Downtime should be equal to 0 (hardcoded for convenience)";
+    }
+    return mPublisher->publishMotionEvent(mSeq++, InputEvent::nextId(), 1 /*deviceId*/,
+                                          AINPUT_SOURCE_TOUCHSCREEN, 0 /*displayId*/, INVALID_HMAC,
+                                          action, 0 /*actionButton*/, 0 /*flags*/, 0 /*edgeFlags*/,
+                                          AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+                                          identityTransform, 0 /*xPrecision*/, 0 /*yPrecision*/,
+                                          AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                          AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform,
+                                          downTime, eventTime, properties.size(), properties.data(),
+                                          coords.data());
+}
+
+void TouchResamplingTest::publishSimpleMotionEvent(int32_t action, nsecs_t eventTime,
+                                                   const std::vector<Pointer>& pointers) {
+    std::vector<PointerProperties> properties;
+    std::vector<PointerCoords> coords;
+
+    for (const Pointer& pointer : pointers) {
+        properties.push_back({});
+        properties.back().clear();
+        properties.back().id = pointer.id;
+        properties.back().toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+        coords.push_back({});
+        coords.back().clear();
+        coords.back().setAxisValue(AMOTION_EVENT_AXIS_X, pointer.x);
+        coords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, pointer.y);
+    }
+
+    status_t result = publishSimpleMotionEventWithCoords(action, eventTime, properties, coords);
+    ASSERT_EQ(OK, result);
+}
+
+/**
+ * Each entry is published separately, one entry at a time. As a result, action is used here
+ * on a per-entry basis.
+ */
+void TouchResamplingTest::publishInputEventEntries(const std::vector<InputEventEntry>& entries) {
+    for (const InputEventEntry& entry : entries) {
+        publishSimpleMotionEvent(entry.action, entry.eventTime.count(), entry.pointers);
+    }
+}
+
+/**
+ * Inside the publisher, read responses repeatedly until the desired sequence number is returned.
+ *
+ * Sometimes, when you call 'sendFinishedSignal', you would be finishing a batch which is comprised
+ * of several input events. As a result, consumer will generate multiple 'finish' signals on your
+ * behalf.
+ *
+ * In this function, we call 'receiveConsumerResponse' in a loop until the desired sequence number
+ * is returned.
+ */
+void TouchResamplingTest::receiveResponseUntilSequence(uint32_t seq) {
+    size_t consumedEvents = 0;
+    while (consumedEvents < 100) {
+        android::base::Result<InputPublisher::ConsumerResponse> response =
+                mPublisher->receiveConsumerResponse();
+        ASSERT_TRUE(response.ok());
+        ASSERT_TRUE(std::holds_alternative<InputPublisher::Finished>(*response));
+        const InputPublisher::Finished& finish = std::get<InputPublisher::Finished>(*response);
+        ASSERT_TRUE(finish.handled)
+                << "publisher receiveFinishedSignal should have set handled to consumer's reply";
+        if (finish.seq == seq) {
+            return;
+        }
+        consumedEvents++;
+    }
+    FAIL() << "Got " << consumedEvents << "events, but still no event with seq=" << seq;
+}
+
+/**
+ * All entries are compared against a single MotionEvent, but the same data structure
+ * InputEventEntry is used here for simpler code. As a result, the entire array of InputEventEntry
+ * must contain identical values for the action field.
+ */
+void TouchResamplingTest::consumeInputEventEntries(const std::vector<InputEventEntry>& entries,
+                                                   std::chrono::nanoseconds frameTime) {
+    ASSERT_GE(entries.size(), 1U) << "Must have at least 1 InputEventEntry to compare against";
+
+    uint32_t consumeSeq;
+    InputEvent* event;
+
+    status_t status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, frameTime.count(),
+                                         &consumeSeq, &event);
+    ASSERT_EQ(OK, status);
+    MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
+
+    ASSERT_EQ(entries.size() - 1, motionEvent->getHistorySize());
+    for (size_t i = 0; i < entries.size(); i++) { // most recent sample is last
+        SCOPED_TRACE(i);
+        const InputEventEntry& entry = entries[i];
+        ASSERT_EQ(entry.action, motionEvent->getAction());
+        ASSERT_EQ(entry.eventTime.count(), motionEvent->getHistoricalEventTime(i));
+        ASSERT_EQ(entry.pointers.size(), motionEvent->getPointerCount());
+
+        for (size_t p = 0; p < motionEvent->getPointerCount(); p++) {
+            SCOPED_TRACE(p);
+            // The pointers can be in any order, both in MotionEvent as well as InputEventEntry
+            ssize_t motionEventPointerIndex = motionEvent->findPointerIndex(entry.pointers[p].id);
+            ASSERT_GE(motionEventPointerIndex, 0) << "Pointer must be present in MotionEvent";
+            ASSERT_EQ(entry.pointers[p].x,
+                      motionEvent->getHistoricalAxisValue(AMOTION_EVENT_AXIS_X,
+                                                          motionEventPointerIndex, i));
+            ASSERT_EQ(entry.pointers[p].x,
+                      motionEvent->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_X,
+                                                             motionEventPointerIndex, i));
+            ASSERT_EQ(entry.pointers[p].y,
+                      motionEvent->getHistoricalAxisValue(AMOTION_EVENT_AXIS_Y,
+                                                          motionEventPointerIndex, i));
+            ASSERT_EQ(entry.pointers[p].y,
+                      motionEvent->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y,
+                                                             motionEventPointerIndex, i));
+        }
+    }
+
+    status = mConsumer->sendFinishedSignal(consumeSeq, true);
+    ASSERT_EQ(OK, status);
+
+    receiveResponseUntilSequence(consumeSeq);
+}
+
+/**
+ * Timeline
+ * ---------+------------------+------------------+--------+-----------------+----------------------
+ *          0 ms               10 ms              20 ms    25 ms            35 ms
+ *          ACTION_DOWN       ACTION_MOVE      ACTION_MOVE  ^                ^
+ *                                                          |                |
+ *                                                         resampled value   |
+ *                                                                          frameTime
+ * Typically, the prediction is made for time frameTime - RESAMPLE_LATENCY, or 30 ms in this case
+ * However, that would be 10 ms later than the last real sample (which came in at 20 ms).
+ * Therefore, the resampling should happen at 20 ms + RESAMPLE_MAX_PREDICTION = 28 ms.
+ * In this situation, though, resample time is further limited by taking half of the difference
+ * between the last two real events, which would put this time at:
+ * 20 ms + (20 ms - 10 ms) / 2 = 25 ms.
+ */
+TEST_F(TouchResamplingTest, EventIsResampled) {
+    std::chrono::nanoseconds frameTime;
+    std::vector<InputEventEntry> entries, expectedEntries;
+
+    // Initial ACTION_DOWN should be separate, because the first consume event will only return
+    // InputEvent with a single action.
+    entries = {
+            //      id  x   y
+            {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 5ms;
+    expectedEntries = {
+            //      id  x   y
+            {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+
+    // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
+    entries = {
+            //      id  x   y
+            {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 35ms;
+    expectedEntries = {
+            //      id  x   y
+            {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {25ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+}
+
+/**
+ * Same as above test, but use pointer id=1 instead of 0 to make sure that system does not
+ * have these hardcoded.
+ */
+TEST_F(TouchResamplingTest, EventIsResampledWithDifferentId) {
+    std::chrono::nanoseconds frameTime;
+    std::vector<InputEventEntry> entries, expectedEntries;
+
+    // Initial ACTION_DOWN should be separate, because the first consume event will only return
+    // InputEvent with a single action.
+    entries = {
+            //      id  x   y
+            {0ms, {{1, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 5ms;
+    expectedEntries = {
+            //      id  x   y
+            {0ms, {{1, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+
+    // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
+    entries = {
+            //      id  x   y
+            {10ms, {{1, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {20ms, {{1, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 35ms;
+    expectedEntries = {
+            //      id  x   y
+            {10ms, {{1, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {20ms, {{1, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {25ms, {{1, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+}
+
+/**
+ * Event should not be resampled when sample time is equal to event time.
+ */
+TEST_F(TouchResamplingTest, SampleTimeEqualsEventTime) {
+    std::chrono::nanoseconds frameTime;
+    std::vector<InputEventEntry> entries, expectedEntries;
+
+    // Initial ACTION_DOWN should be separate, because the first consume event will only return
+    // InputEvent with a single action.
+    entries = {
+            //      id  x   y
+            {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 5ms;
+    expectedEntries = {
+            //      id  x   y
+            {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+
+    // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
+    entries = {
+            //      id  x   y
+            {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 20ms + 5ms /*RESAMPLE_LATENCY*/;
+    expectedEntries = {
+            //      id  x   y
+            {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            // no resampled event because the time of resample falls exactly on the existing event
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+}
+
+/**
+ * Once we send a resampled value to the app, we should continue to "lie" if the pointer
+ * does not move. So, if the pointer keeps the same coordinates, resampled value should continue
+ * to be used.
+ */
+TEST_F(TouchResamplingTest, ResampledValueIsUsedForIdenticalCoordinates) {
+    std::chrono::nanoseconds frameTime;
+    std::vector<InputEventEntry> entries, expectedEntries;
+
+    // Initial ACTION_DOWN should be separate, because the first consume event will only return
+    // InputEvent with a single action.
+    entries = {
+            //      id  x   y
+            {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 5ms;
+    expectedEntries = {
+            //      id  x   y
+            {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+
+    // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
+    entries = {
+            //      id  x   y
+            {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 35ms;
+    expectedEntries = {
+            //      id  x   y
+            {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {25ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+
+    // Coordinate value 30 has been resampled to 35. When a new event comes in with value 30 again,
+    // the system should still report 35.
+    entries = {
+            //      id  x   y
+            {40ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 45ms + 5ms /*RESAMPLE_LATENCY*/;
+    expectedEntries = {
+            //      id  x   y
+            {40ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // original event, rewritten
+            {45ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled event, rewritten
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+}
+
+TEST_F(TouchResamplingTest, OldEventReceivedAfterResampleOccurs) {
+    std::chrono::nanoseconds frameTime;
+    std::vector<InputEventEntry> entries, expectedEntries;
+
+    // Initial ACTION_DOWN should be separate, because the first consume event will only return
+    // InputEvent with a single action.
+    entries = {
+            //      id  x   y
+            {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 5ms;
+    expectedEntries = {
+            //      id  x   y
+            {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN},
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+
+    // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y
+    entries = {
+            //      id  x   y
+            {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 35ms;
+    expectedEntries = {
+            //      id  x   y
+            {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE},
+            {25ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+    // Above, the resampled event is at 25ms rather than at 30 ms = 35ms - RESAMPLE_LATENCY
+    // because we are further bound by how far we can extrapolate by the "last time delta".
+    // That's 50% of (20 ms - 10ms) => 5ms. So we can't predict more than 5 ms into the future
+    // from the event at 20ms, which is why the resampled event is at t = 25 ms.
+
+    // We resampled the event to 25 ms. Now, an older 'real' event comes in.
+    entries = {
+            //      id  x   y
+            {24ms, {{0, 40, 30}}, AMOTION_EVENT_ACTION_MOVE},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 50ms;
+    expectedEntries = {
+            //      id  x   y
+            {24ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // original event, rewritten
+            {26ms, {{0, 45, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled event, rewritten
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+}
+
+TEST_F(TouchResamplingTest, TwoPointersAreResampledIndependently) {
+    std::chrono::nanoseconds frameTime;
+    std::vector<InputEventEntry> entries, expectedEntries;
+
+    // full action for when a pointer with id=1 appears (some other pointer must already be present)
+    constexpr int32_t actionPointer1Down =
+            AMOTION_EVENT_ACTION_POINTER_DOWN + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+
+    // full action for when a pointer with id=0 disappears (some other pointer must still remain)
+    constexpr int32_t actionPointer0Up =
+            AMOTION_EVENT_ACTION_POINTER_UP + (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+
+    // Initial ACTION_DOWN should be separate, because the first consume event will only return
+    // InputEvent with a single action.
+    entries = {
+            //      id  x   y
+            {0ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_DOWN},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 5ms;
+    expectedEntries = {
+            //      id  x   y
+            {0ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_DOWN},
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+
+    entries = {
+            //       id  x   y
+            {10ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_MOVE},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 10ms + 5ms /*RESAMPLE_LATENCY*/;
+    expectedEntries = {
+            //       id  x   y
+            {10ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_MOVE},
+            // no resampled value because frameTime - RESAMPLE_LATENCY == eventTime
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+
+    // Second pointer id=1 appears
+    entries = {
+            //      id  x    y
+            {15ms, {{0, 100, 100}, {1, 500, 500}}, actionPointer1Down},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 20ms + 5ms /*RESAMPLE_LATENCY*/;
+    expectedEntries = {
+            //      id  x    y
+            {15ms, {{0, 100, 100}, {1, 500, 500}}, actionPointer1Down},
+            // no resampled value because frameTime - RESAMPLE_LATENCY == eventTime
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+
+    // Both pointers move
+    entries = {
+            //      id  x    y
+            {30ms, {{0, 100, 100}, {1, 500, 500}}, AMOTION_EVENT_ACTION_MOVE},
+            {40ms, {{0, 120, 120}, {1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 45ms + 5ms /*RESAMPLE_LATENCY*/;
+    expectedEntries = {
+            //      id  x    y
+            {30ms, {{0, 100, 100}, {1, 500, 500}}, AMOTION_EVENT_ACTION_MOVE},
+            {40ms, {{0, 120, 120}, {1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE},
+            {45ms, {{0, 130, 130}, {1, 650, 650}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+
+    // Both pointers move again
+    entries = {
+            //      id  x    y
+            {60ms, {{0, 120, 120}, {1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE},
+            {70ms, {{0, 130, 130}, {1, 700, 700}}, AMOTION_EVENT_ACTION_MOVE},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 75ms + 5ms /*RESAMPLE_LATENCY*/;
+    /**
+     * The sample at t = 60, pointer id 0 is not equal to 120, because this value of 120 was
+     * received twice, and resampled to 130. So if we already reported it as "130", we continue
+     * to report it as such. Similar with pointer id 1.
+     */
+    expectedEntries = {
+            {60ms,
+             {{0, 130, 130}, // not 120! because it matches previous real event
+              {1, 650, 650}},
+             AMOTION_EVENT_ACTION_MOVE},
+            {70ms, {{0, 130, 130}, {1, 700, 700}}, AMOTION_EVENT_ACTION_MOVE},
+            {75ms, {{0, 135, 135}, {1, 750, 750}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+
+    // First pointer id=0 leaves the screen
+    entries = {
+            //      id  x    y
+            {80ms, {{1, 600, 600}}, actionPointer0Up},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 90ms;
+    expectedEntries = {
+            //      id  x    y
+            {80ms, {{1, 600, 600}}, actionPointer0Up},
+            // no resampled event for ACTION_POINTER_UP
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+
+    // Remaining pointer id=1 is still present, but doesn't move
+    entries = {
+            //      id  x    y
+            {90ms, {{1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE},
+    };
+    publishInputEventEntries(entries);
+    frameTime = 100ms;
+    expectedEntries = {
+            //      id  x    y
+            {90ms, {{1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE},
+            /**
+             * The latest event with ACTION_MOVE was at t = 70, coord = 700.
+             * Use that value for resampling here: (600 - 700) / (90 - 70) * 5 + 600
+             */
+            {95ms, {{1, 575, 575}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value
+    };
+    consumeInputEventEntries(expectedEntries, frameTime);
+}
+
+} // namespace android
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index a87b187..4a445de 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -26,7 +26,9 @@
 #include <gui/constants.h>
 #include <input/VelocityTracker.h>
 
-using namespace std::chrono_literals;
+using std::literals::chrono_literals::operator""ms;
+using std::literals::chrono_literals::operator""ns;
+using std::literals::chrono_literals::operator""us;
 using android::base::StringPrintf;
 
 namespace android {
@@ -149,8 +151,7 @@
         if (i == 0) {
             action = AMOTION_EVENT_ACTION_DOWN;
             EXPECT_EQ(1U, pointerCount) << "First event should only have 1 pointer";
-        } else if (i == motions.size() - 1) {
-            EXPECT_EQ(1U, pointerCount) << "Last event should only have 1 pointer";
+        } else if ((i == motions.size() - 1) && pointerCount == 1) {
             action = AMOTION_EVENT_ACTION_UP;
         } else {
             const MotionEventEntry& previousEntry = motions[i-1];
@@ -195,7 +196,7 @@
 
 static void computeAndCheckVelocity(const VelocityTracker::Strategy strategy,
                                     const std::vector<MotionEventEntry>& motions, int32_t axis,
-                                    float targetVelocity) {
+                                    float targetVelocity, uint32_t pointerId = DEFAULT_POINTER_ID) {
     VelocityTracker vt(strategy);
     float Vx, Vy;
 
@@ -204,7 +205,7 @@
         vt.addMovement(&event);
     }
 
-    vt.getVelocity(DEFAULT_POINTER_ID, &Vx, &Vy);
+    vt.getVelocity(pointerId, &Vx, &Vy);
 
     switch (axis) {
     case AMOTION_EVENT_AXIS_X:
@@ -846,13 +847,71 @@
 
     // Velocity should actually be zero, but we expect 0.016 here instead.
     // This is close enough to zero, and is likely caused by division by a very small number.
-    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, -0.016);
-    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y, -0.016);
+    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0);
+    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y, 0);
     computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0);
     computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y, 0);
 }
 
 /**
+ * ================= Pointer liftoff ===============================================================
+ */
+
+/**
+ * The last movement of a pointer is always ACTION_POINTER_UP or ACTION_UP. If there's a short delay
+ * between the last ACTION_MOVE and the next ACTION_POINTER_UP or ACTION_UP, velocity should not be
+ * affected by the liftoff.
+ */
+TEST_F(VelocityTrackerTest, ShortDelayBeforeActionUp) {
+    std::vector<MotionEventEntry> motions = {
+            {0ms, {{10, 0}}}, {10ms, {{20, 0}}}, {20ms, {{30, 0}}}, {30ms, {{30, 0}}}, // ACTION_UP
+    };
+    computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+                            1000);
+    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 1000);
+}
+
+/**
+ * The last movement of a single pointer is ACTION_UP. If there's a long delay between the last
+ * ACTION_MOVE and the final ACTION_UP, velocity should be reported as zero because the pointer
+ * should be assumed to have stopped.
+ */
+TEST_F(VelocityTrackerTest, LongDelayBeforeActionUp) {
+    std::vector<MotionEventEntry> motions = {
+            {0ms, {{10, 0}}},
+            {10ms, {{20, 0}}},
+            {20ms, {{30, 0}}},
+            {3000ms, {{30, 0}}}, // ACTION_UP
+    };
+    computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0);
+    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0);
+}
+
+/**
+ * The last movement of a pointer is always ACTION_POINTER_UP or ACTION_UP. If there's a long delay
+ * before ACTION_POINTER_UP event, the movement should be assumed to have stopped.
+ * The final velocity should be reported as zero for all pointers.
+ */
+TEST_F(VelocityTrackerTest, LongDelayBeforeActionPointerUp) {
+    std::vector<MotionEventEntry> motions = {
+            {0ms, {{10, 0}}},
+            {10ms, {{20, 0}, {100, 0}}},
+            {20ms, {{30, 0}, {200, 0}}},
+            {30ms, {{30, 0}, {300, 0}}},
+            {40ms, {{30, 0}, {400, 0}}},
+            {3000ms, {{30, 0}}}, // ACTION_POINTER_UP
+    };
+    computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0,
+                            /*pointerId*/ 0);
+    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0,
+                            /*pointerId*/ 0);
+    computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0,
+                            /*pointerId*/ 1);
+    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0,
+                            /*pointerId*/ 1);
+}
+
+/**
  * ================== Tests for least squares fitting ==============================================
  *
  * Special care must be taken when constructing tests for LeastSquaresVelocityTrackerStrategy
diff --git a/libs/input/tests/data/kl_with_required_fake_config.kl b/libs/input/tests/data/kl_with_required_fake_config.kl
new file mode 100644
index 0000000..2d0a507
--- /dev/null
+++ b/libs/input/tests/data/kl_with_required_fake_config.kl
@@ -0,0 +1,20 @@
+# 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.
+
+# This KL should not be loaded unless the below config is present in the kernel
+# This config will never exist, and therefore this KL should never be loaded
+requires_kernel_config CONFIG_HID_FAKEMODULE
+
+# An arbitrary mapping taken from another file
+key 0x130    BUTTON_X
\ No newline at end of file
diff --git a/libs/input/tests/data/kl_with_required_real_config.kl b/libs/input/tests/data/kl_with_required_real_config.kl
new file mode 100644
index 0000000..303b23e
--- /dev/null
+++ b/libs/input/tests/data/kl_with_required_real_config.kl
@@ -0,0 +1,21 @@
+# 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.
+
+# This KL should not be loaded unless the below config is present in the kernel
+# The CONFIG_UHID option has been required for a while, and therefore it's safe
+# to assume that this will always be loaded
+requires_kernel_config CONFIG_UHID
+
+# An arbitrary mapping taken from another file
+key 0x130    BUTTON_X
\ No newline at end of file
diff --git a/libs/math/OWNERS b/libs/math/OWNERS
index 72d33bc..82ae422 100644
--- a/libs/math/OWNERS
+++ b/libs/math/OWNERS
@@ -1,3 +1,5 @@
 mathias@google.com
 randolphs@google.com
 romainguy@google.com
+sumir@google.com
+jreck@google.com
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 8240b08..539cbaa 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -18,8 +18,8 @@
 //#define LOG_NDEBUG 0
 
 #include <android-base/thread_annotations.h>
+#include <android/gui/ISurfaceComposer.h>
 #include <gui/DisplayEventDispatcher.h>
-#include <gui/ISurfaceComposer.h>
 #include <jni.h>
 #include <private/android/choreographer.h>
 #include <utils/Looper.h>
@@ -198,7 +198,7 @@
 }
 
 Choreographer::Choreographer(const sp<Looper>& looper)
-      : DisplayEventDispatcher(looper, ISurfaceComposer::VsyncSource::eVsyncSourceApp),
+      : DisplayEventDispatcher(looper, gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp),
         mLooper(looper),
         mThreadId(std::this_thread::get_id()) {
     std::lock_guard<std::mutex> _l(gChoreographers.lock);
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index e3fad3d..8d8a2bc 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -43,8 +43,6 @@
         "include-private",
     ],
 
-    clang: true,
-
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 969d937..9172d5e 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -1,25 +1,25 @@
 LIBNATIVEDISPLAY {
   global:
-    AChoreographer_getInstance; # apex # introduced=30
-    AChoreographer_postFrameCallback; # apex # introduced=30
-    AChoreographer_postFrameCallbackDelayed; # apex # introduced=30
-    AChoreographer_postFrameCallback64; # apex # introduced=30
-    AChoreographer_postFrameCallbackDelayed64; # apex # introduced=30
-    AChoreographer_registerRefreshRateCallback; # apex # introduced=30
-    AChoreographer_unregisterRefreshRateCallback; # apex # introduced=30
-    AChoreographer_postVsyncCallback; # apex # introduced=33
-    AChoreographerFrameCallbackData_getFrameTimeNanos; # apex # introduced=33
-    AChoreographerFrameCallbackData_getFrameTimelinesLength; # apex # introduced=33
-    AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex; # apex # introduced=33
-    AChoreographerFrameCallbackData_getFrameTimelineVsyncId; # apex # introduced=33
-    AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos; # apex # introduced=33
-    AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos; # apex # introduced=33
-    AChoreographer_create; # apex # introduced=30
-    AChoreographer_destroy; # apex # introduced=30
-    AChoreographer_getFd; # apex # introduced=30
-    AChoreographer_handlePendingEvents; # apex # introduced=30
-    ASurfaceTexture_fromSurfaceTexture; # apex # introduced=30
-    ASurfaceTexture_release; # apex # introduced=30
+    AChoreographer_getInstance; # systemapi # introduced=30
+    AChoreographer_postFrameCallback; # systemapi # introduced=30
+    AChoreographer_postFrameCallbackDelayed; # systemapi # introduced=30
+    AChoreographer_postFrameCallback64; # systemapi # introduced=30
+    AChoreographer_postFrameCallbackDelayed64; # systemapi # introduced=30
+    AChoreographer_registerRefreshRateCallback; # systemapi # introduced=30
+    AChoreographer_unregisterRefreshRateCallback; # systemapi # introduced=30
+    AChoreographer_postVsyncCallback; # systemapi # introduced=33
+    AChoreographerFrameCallbackData_getFrameTimeNanos; # systemapi # introduced=33
+    AChoreographerFrameCallbackData_getFrameTimelinesLength; # systemapi # introduced=33
+    AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex; # systemapi # introduced=33
+    AChoreographerFrameCallbackData_getFrameTimelineVsyncId; # systemapi # introduced=33
+    AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos; # systemapi # introduced=33
+    AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos; # systemapi # introduced=33
+    AChoreographer_create; # systemapi # introduced=30
+    AChoreographer_destroy; # systemapi # introduced=30
+    AChoreographer_getFd; # systemapi # introduced=30
+    AChoreographer_handlePendingEvents; # systemapi # introduced=30
+    ASurfaceTexture_fromSurfaceTexture; # systemapi # introduced=30
+    ASurfaceTexture_release; # systemapi # introduced=30
   local:
     *;
 };
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 18a4b2d..731f989 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -176,8 +176,8 @@
         static_cast<int>(HAL_DATASPACE_BT2020_HLG));
     static_assert(static_cast<int>(ADATASPACE_BT2020_ITU_HLG) ==
         static_cast<int>(HAL_DATASPACE_BT2020_ITU_HLG));
-    static_assert(static_cast<int>(DEPTH) == static_cast<int>(HAL_DATASPACE_DEPTH));
-    static_assert(static_cast<int>(DYNAMIC_DEPTH) == static_cast<int>(HAL_DATASPACE_DYNAMIC_DEPTH));
+    static_assert(static_cast<int>(ADATASPACE_DEPTH) == static_cast<int>(HAL_DATASPACE_DEPTH));
+    static_assert(static_cast<int>(ADATASPACE_DYNAMIC_DEPTH) == static_cast<int>(HAL_DATASPACE_DYNAMIC_DEPTH));
 
     if (!window || !query(window, NATIVE_WINDOW_IS_VALID) ||
             !isDataSpaceValid(window, dataSpace)) {
@@ -193,6 +193,13 @@
     return query(window, NATIVE_WINDOW_DATASPACE);
 }
 
+int32_t ANativeWindow_getBuffersDefaultDataSpace(ANativeWindow* window) {
+    if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) {
+        return -EINVAL;
+    }
+    return query(window, NATIVE_WINDOW_DEFAULT_DATASPACE);
+}
+
 int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) {
     return ANativeWindow_setFrameRateWithChangeStrategy(window, frameRate, compatibility,
         ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index d30efa1..dd07319 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -77,8 +77,6 @@
         "include-private",
     ],
 
-    clang: true,
-
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 771844f..ad4cc4a 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -548,14 +548,14 @@
      *
      * This value is valid with formats HAL_PIXEL_FORMAT_Y16 and HAL_PIXEL_FORMAT_BLOB.
      */
-    DEPTH = 4096,
+    ADATASPACE_DEPTH = 4096,
 
     /**
      * ISO 16684-1:2011(E) Dynamic Depth:
      *
      * Embedded depth metadata following the dynamic depth specification.
      */
-    DYNAMIC_DEPTH = 4098
+    ADATASPACE_DYNAMIC_DEPTH = 4098
 };
 
 __END_DECLS
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index f0e1c4d..20f4b52 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -227,6 +227,16 @@
  */
 int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN(28);
 
+/**
+ * Get the default dataspace of the buffers in window as set by the consumer.
+ *
+ * Available since API level 34.
+ *
+ * \return the dataspace of buffers in window, ADATASPACE_UNKNOWN is returned if
+ * dataspace is unknown, or -EINVAL if window is invalid.
+ */
+int32_t ANativeWindow_getBuffersDefaultDataSpace(ANativeWindow* window) __INTRODUCED_IN(34);
+
 /** Compatibility value for ANativeWindow_setFrameRate. */
 enum ANativeWindow_FrameRateCompatibility {
     /**
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index a54af1f..79f49e1 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1034,6 +1034,11 @@
      * This surface is ignored while choosing the refresh rate.
      */
     ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
+
+    /**
+     * This surface will vote for the minimum refresh rate.
+     */
+    ANATIVEWINDOW_FRAME_RATE_MIN
 };
 
 static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate,
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 988132c..6296f9a 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -2,10 +2,10 @@
   global:
     AHardwareBuffer_acquire;
     AHardwareBuffer_allocate;
-    AHardwareBuffer_createFromHandle; # llndk # apex
+    AHardwareBuffer_createFromHandle; # llndk # systemapi
     AHardwareBuffer_describe;
     AHardwareBuffer_getId; # introduced=31
-    AHardwareBuffer_getNativeHandle; # llndk # apex
+    AHardwareBuffer_getNativeHandle; # llndk # systemapi
     AHardwareBuffer_isSupported; # introduced=29
     AHardwareBuffer_lock;
     AHardwareBuffer_lockAndGetInfo; # introduced=29
@@ -21,20 +21,21 @@
     ANativeWindow_cancelBuffer; # llndk
     ANativeWindow_dequeueBuffer; # llndk
     ANativeWindow_getBuffersDataSpace; # introduced=28
+    ANativeWindow_getBuffersDefaultDataSpace; # introduced=34
     ANativeWindow_getFormat;
     ANativeWindow_getHeight;
-    ANativeWindow_getLastDequeueDuration; # apex # introduced=30
-    ANativeWindow_getLastDequeueStartTime; # apex # introduced=30
-    ANativeWindow_getLastQueueDuration; # apex # introduced=30
+    ANativeWindow_getLastDequeueDuration; # systemapi # introduced=30
+    ANativeWindow_getLastDequeueStartTime; # systemapi # introduced=30
+    ANativeWindow_getLastQueueDuration; # systemapi # introduced=30
     ANativeWindow_getWidth;
     ANativeWindow_lock;
     ANativeWindow_query; # llndk
     ANativeWindow_queryf; # llndk
     ANativeWindow_queueBuffer; # llndk
-    ANativeWindow_setCancelBufferInterceptor; # apex # introduced=30
-    ANativeWindow_setDequeueBufferInterceptor; # apex # introduced=30
-    ANativeWindow_setPerformInterceptor; # apex # introduced=30
-    ANativeWindow_setQueueBufferInterceptor; # apex # introduced=30
+    ANativeWindow_setCancelBufferInterceptor; # systemapi # introduced=30
+    ANativeWindow_setDequeueBufferInterceptor; # systemapi # introduced=30
+    ANativeWindow_setPerformInterceptor; # systemapi # introduced=30
+    ANativeWindow_setQueueBufferInterceptor; # systemapi # introduced=30
     ANativeWindow_release;
     ANativeWindow_setAutoPrerotation; # llndk
     ANativeWindow_setAutoRefresh; # llndk
@@ -45,7 +46,7 @@
     ANativeWindow_setBuffersGeometry;
     ANativeWindow_setBuffersTimestamp; # llndk
     ANativeWindow_setBuffersTransform;
-    ANativeWindow_setDequeueTimeout; # apex # introduced=30
+    ANativeWindow_setDequeueTimeout; # systemapi # introduced=30
     ANativeWindow_setFrameRate; # introduced=30
     ANativeWindow_setFrameRateWithChangeStrategy; # introduced=31
     ANativeWindow_setSharedBufferMode; # llndk
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index cb92df3..f6f57dd 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -111,7 +111,6 @@
     name: "librenderengine",
     defaults: ["librenderengine_defaults"],
     double_loadable: true,
-    clang: true,
     cflags: [
         "-fvisibility=hidden",
         "-Werror=format",
diff --git a/libs/renderengine/TEST_MAPPING b/libs/renderengine/TEST_MAPPING
index 995dba1..db00118 100644
--- a/libs/renderengine/TEST_MAPPING
+++ b/libs/renderengine/TEST_MAPPING
@@ -3,5 +3,11 @@
     {
       "name": "librenderengine_test"
     }
+  ],
+
+  "imports": [
+    {
+      "path": "frameworks/native/services/surfaceflinger"
+    }
   ]
 }
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index ead97cf..7bcfff5 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -117,11 +117,12 @@
                                                        uint64_t extraUsageFlags = 0,
                                                        std::string name = "output") {
     return std::make_shared<
-            impl::ExternalTexture>(new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1,
-                                                     GRALLOC_USAGE_HW_RENDER |
-                                                             GRALLOC_USAGE_HW_TEXTURE |
-                                                             extraUsageFlags,
-                                                     std::move(name)),
+            impl::ExternalTexture>(sp<GraphicBuffer>::make(width, height,
+                                                           HAL_PIXEL_FORMAT_RGBA_8888, 1u,
+                                                           GRALLOC_USAGE_HW_RENDER |
+                                                                   GRALLOC_USAGE_HW_TEXTURE |
+                                                                   extraUsageFlags,
+                                                           std::move(name)),
                                    re,
                                    impl::ExternalTexture::Usage::READABLE |
                                            impl::ExternalTexture::Usage::WRITEABLE);
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 22dd866..9a5ff54 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -454,8 +454,9 @@
     mImageManager->initThread();
     mDrawingBuffer = createFramebuffer();
     sp<GraphicBuffer> buf =
-            new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888, 1,
-                              GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, "placeholder");
+            sp<GraphicBuffer>::make(1, 1, PIXEL_FORMAT_RGBA_8888, 1,
+                                    GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE,
+                                    "placeholder");
 
     const status_t err = buf->initCheck();
     if (err != OK) {
@@ -921,7 +922,8 @@
 
     // Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners
     // and the middle part without rounded corners.
-    const int32_t radius = ceil(layer.geometry.roundedCornersRadius);
+    const int32_t radius = ceil(
+            (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) / 2.0);
     const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius);
     setScissor(topRect);
     drawMesh(mesh);
@@ -1266,23 +1268,24 @@
 
         const half3 solidColor = layer.source.solidColor;
         const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
+        const float radius =
+                (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) /
+                2.0f;
         // Buffer sources will have a black solid color ignored in the shader,
         // so in that scenario the solid color passed here is arbitrary.
-        setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color,
-                           layer.geometry.roundedCornersRadius);
+        setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, radius);
         if (layer.disableBlending) {
             glDisable(GL_BLEND);
         }
         setSourceDataSpace(layer.sourceDataspace);
 
         if (layer.shadow.length > 0.0f) {
-            handleShadow(layer.geometry.boundaries, layer.geometry.roundedCornersRadius,
-                         layer.shadow);
+            handleShadow(layer.geometry.boundaries, radius, layer.shadow);
         }
         // We only want to do a special handling for rounded corners when having rounded corners
         // is the only reason it needs to turn on blending, otherwise, we handle it like the
         // usual way since it needs to turn on blending anyway.
-        else if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
+        else if (radius > 0.0 && color.a >= 1.0f && isOpaque) {
             handleRoundedCorners(display, layer, mesh);
         } else {
             drawMesh(mesh);
diff --git a/libs/renderengine/include/renderengine/BorderRenderInfo.h b/libs/renderengine/include/renderengine/BorderRenderInfo.h
new file mode 100644
index 0000000..0ee6661
--- /dev/null
+++ b/libs/renderengine/include/renderengine/BorderRenderInfo.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#pragma once
+#include <math/mat4.h>
+#include <ui/Region.h>
+
+namespace android {
+namespace renderengine {
+
+struct BorderRenderInfo {
+    float width = 0;
+    half4 color;
+    Region combinedRegion;
+
+    bool operator==(const BorderRenderInfo& rhs) const {
+        return (width == rhs.width && color == rhs.color &&
+                combinedRegion.hasSameRects(rhs.combinedRegion));
+    }
+};
+
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index a5e0879..25fe9f2 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -21,6 +21,8 @@
 #include <iosfwd>
 
 #include <math/mat4.h>
+#include <renderengine/PrintMatrix.h>
+#include <renderengine/BorderRenderInfo.h>
 #include <ui/GraphicTypes.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -78,15 +80,45 @@
     // Configures the rendering intent of the output display. This is used for tonemapping.
     aidl::android::hardware::graphics::composer3::RenderIntent renderIntent =
             aidl::android::hardware::graphics::composer3::RenderIntent::TONE_MAP_COLORIMETRIC;
+
+    std::vector<renderengine::BorderRenderInfo> borderInfoList;
 };
 
 static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) {
     return lhs.physicalDisplay == rhs.physicalDisplay && lhs.clip == rhs.clip &&
-            lhs.maxLuminance == rhs.maxLuminance && lhs.outputDataspace == rhs.outputDataspace &&
-            lhs.colorTransform == rhs.colorTransform && lhs.orientation == rhs.orientation;
+            lhs.maxLuminance == rhs.maxLuminance &&
+            lhs.currentLuminanceNits == rhs.currentLuminanceNits &&
+            lhs.outputDataspace == rhs.outputDataspace &&
+            lhs.colorTransform == rhs.colorTransform &&
+            lhs.deviceHandlesColorTransform == rhs.deviceHandlesColorTransform &&
+            lhs.orientation == rhs.orientation &&
+            lhs.targetLuminanceNits == rhs.targetLuminanceNits &&
+            lhs.dimmingStage == rhs.dimmingStage && lhs.renderIntent == rhs.renderIntent &&
+            lhs.borderInfoList == rhs.borderInfoList;
 }
 
-// Defining PrintTo helps with Google Tests.
+static const char* orientation_to_string(uint32_t orientation) {
+    switch (orientation) {
+        case ui::Transform::ROT_0:
+            return "ROT_0";
+        case ui::Transform::FLIP_H:
+            return "FLIP_H";
+        case ui::Transform::FLIP_V:
+            return "FLIP_V";
+        case ui::Transform::ROT_90:
+            return "ROT_90";
+        case ui::Transform::ROT_180:
+            return "ROT_180";
+        case ui::Transform::ROT_270:
+            return "ROT_270";
+        case ui::Transform::ROT_INVALID:
+            return "ROT_INVALID";
+        default:
+            ALOGE("invalid orientation!");
+            return "invalid orientation";
+    }
+}
+
 static inline void PrintTo(const DisplaySettings& settings, ::std::ostream* os) {
     *os << "DisplaySettings {";
     *os << "\n    .physicalDisplay = ";
@@ -94,10 +126,19 @@
     *os << "\n    .clip = ";
     PrintTo(settings.clip, os);
     *os << "\n    .maxLuminance = " << settings.maxLuminance;
+    *os << "\n    .currentLuminanceNits = " << settings.currentLuminanceNits;
     *os << "\n    .outputDataspace = ";
     PrintTo(settings.outputDataspace, os);
-    *os << "\n    .colorTransform = " << settings.colorTransform;
-    *os << "\n    .clearRegion = ";
+    *os << "\n    .colorTransform = ";
+    PrintMatrix(settings.colorTransform, os);
+    *os << "\n    .deviceHandlesColorTransform = " << settings.deviceHandlesColorTransform;
+    *os << "\n    .orientation = " << orientation_to_string(settings.orientation);
+    *os << "\n    .targetLuminanceNits = " << settings.targetLuminanceNits;
+    *os << "\n    .dimmingStage = "
+        << aidl::android::hardware::graphics::composer3::toString(settings.dimmingStage).c_str();
+    *os << "\n    .renderIntent = "
+        << aidl::android::hardware::graphics::composer3::toString(settings.renderIntent).c_str();
+    *os << "\n}";
 }
 
 } // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 171cbaa..b3a617c 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -19,7 +19,9 @@
 #include <math/mat4.h>
 #include <math/vec3.h>
 #include <renderengine/ExternalTexture.h>
+#include <renderengine/PrintMatrix.h>
 #include <ui/BlurRegion.h>
+#include <ui/DebugUtils.h>
 #include <ui/Fence.h>
 #include <ui/FloatRect.h>
 #include <ui/GraphicBuffer.h>
@@ -85,7 +87,7 @@
     // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be
     // in local layer coordinate space, so we have to take the layer transform into account when
     // walking up the tree.
-    float roundedCornersRadius = 0.0;
+    vec2 roundedCornersRadius = vec2(0.0f, 0.0f);
 
     // Rectangle within which corners will be rounded.
     FloatRect roundedCornersCrop = FloatRect();
@@ -208,6 +210,10 @@
             lhs.casterIsTranslucent == rhs.casterIsTranslucent;
 }
 
+static inline bool operator!=(const ShadowSettings& lhs, const ShadowSettings& rhs) {
+    return !(operator==(lhs, rhs));
+}
+
 static inline bool operator==(const LayerSettings& lhs, const LayerSettings& rhs) {
     if (lhs.blurRegions.size() != rhs.blurRegions.size()) {
         return false;
@@ -226,18 +232,19 @@
             lhs.skipContentDraw == rhs.skipContentDraw && lhs.shadow == rhs.shadow &&
             lhs.backgroundBlurRadius == rhs.backgroundBlurRadius &&
             lhs.blurRegionTransform == rhs.blurRegionTransform &&
-            lhs.stretchEffect == rhs.stretchEffect;
+            lhs.stretchEffect == rhs.stretchEffect && lhs.whitePointNits == rhs.whitePointNits;
 }
 
-// Defining PrintTo helps with Google Tests.
-
 static inline void PrintTo(const Buffer& settings, ::std::ostream* os) {
     *os << "Buffer {";
-    *os << "\n    .buffer = " << settings.buffer.get();
+    *os << "\n    .buffer = " << settings.buffer.get() << " "
+        << (settings.buffer.get() ? decodePixelFormat(settings.buffer->getPixelFormat()).c_str()
+                                  : "");
     *os << "\n    .fence = " << settings.fence.get();
     *os << "\n    .textureName = " << settings.textureName;
     *os << "\n    .useTextureFiltering = " << settings.useTextureFiltering;
-    *os << "\n    .textureTransform = " << settings.textureTransform;
+    *os << "\n    .textureTransform = ";
+    PrintMatrix(settings.textureTransform, os);
     *os << "\n    .usePremultipliedAlpha = " << settings.usePremultipliedAlpha;
     *os << "\n    .isOpaque = " << settings.isOpaque;
     *os << "\n    .isY410BT2020 = " << settings.isY410BT2020;
@@ -249,8 +256,10 @@
     *os << "Geometry {";
     *os << "\n    .boundaries = ";
     PrintTo(settings.boundaries, os);
-    *os << "\n    .positionTransform = " << settings.positionTransform;
-    *os << "\n    .roundedCornersRadius = " << settings.roundedCornersRadius;
+    *os << "\n    .positionTransform = ";
+    PrintMatrix(settings.positionTransform, os);
+    *os << "\n    .roundedCornersRadiusX = " << settings.roundedCornersRadius.x;
+    *os << "\n    .roundedCornersRadiusY = " << settings.roundedCornersRadius.y;
     *os << "\n    .roundedCornersCrop = ";
     PrintTo(settings.roundedCornersCrop, os);
     *os << "\n}";
@@ -258,10 +267,14 @@
 
 static inline void PrintTo(const PixelSource& settings, ::std::ostream* os) {
     *os << "PixelSource {";
-    *os << "\n    .buffer = ";
-    PrintTo(settings.buffer, os);
-    *os << "\n    .solidColor = " << settings.solidColor;
-    *os << "\n}";
+    if (settings.buffer.buffer) {
+        *os << "\n    .buffer = ";
+        PrintTo(settings.buffer, os);
+        *os << "\n}";
+    } else {
+        *os << "\n    .solidColor = " << settings.solidColor;
+        *os << "\n}";
+    }
 }
 
 static inline void PrintTo(const ShadowSettings& settings, ::std::ostream* os) {
@@ -301,18 +314,28 @@
     *os << "\n    .alpha = " << settings.alpha;
     *os << "\n    .sourceDataspace = ";
     PrintTo(settings.sourceDataspace, os);
-    *os << "\n    .colorTransform = " << settings.colorTransform;
+    *os << "\n    .colorTransform = ";
+    PrintMatrix(settings.colorTransform, os);
     *os << "\n    .disableBlending = " << settings.disableBlending;
     *os << "\n    .skipContentDraw = " << settings.skipContentDraw;
-    *os << "\n    .backgroundBlurRadius = " << settings.backgroundBlurRadius;
-    for (auto blurRegion : settings.blurRegions) {
-        *os << "\n";
-        PrintTo(blurRegion, os);
+    if (settings.shadow != ShadowSettings()) {
+        *os << "\n    .shadow = ";
+        PrintTo(settings.shadow, os);
     }
-    *os << "\n    .shadow = ";
-    PrintTo(settings.shadow, os);
-    *os << "\n    .stretchEffect = ";
-    PrintTo(settings.stretchEffect, os);
+    *os << "\n    .backgroundBlurRadius = " << settings.backgroundBlurRadius;
+    if (settings.blurRegions.size()) {
+        *os << "\n    .blurRegions =";
+        for (auto blurRegion : settings.blurRegions) {
+            *os << "\n";
+            PrintTo(blurRegion, os);
+        }
+    }
+    *os << "\n    .blurRegionTransform = ";
+    PrintMatrix(settings.blurRegionTransform, os);
+    if (settings.stretchEffect != StretchEffect()) {
+        *os << "\n    .stretchEffect = ";
+        PrintTo(settings.stretchEffect, os);
+    }
     *os << "\n    .whitePointNits = " << settings.whitePointNits;
     *os << "\n}";
 }
diff --git a/libs/renderengine/include/renderengine/PrintMatrix.h b/libs/renderengine/include/renderengine/PrintMatrix.h
new file mode 100644
index 0000000..11a5c21
--- /dev/null
+++ b/libs/renderengine/include/renderengine/PrintMatrix.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <math/mat4.h>
+#include <iosfwd>
+
+namespace android::renderengine {
+
+// This method simplifies printing the identity matrix, so it can be easily
+// skipped over visually.
+inline void PrintMatrix(const mat4& matrix, ::std::ostream* os) {
+    if (matrix == mat4()) {
+        *os << "I";
+    } else {
+        // Print the matrix starting on a new line. This ensures that all lines
+        // are aligned.
+        *os << "\n" << matrix;
+    }
+}
+
+} // namespace android::renderengine
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index a3a1969..f6b9183 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -66,7 +66,7 @@
                     Geometry{
                             .boundaries = rect,
                             .roundedCornersCrop = rect,
-                            .roundedCornersRadius = 50.f,
+                            .roundedCornersRadius = {50.f, 50.f},
                     },
             // drawShadow ignores alpha
             .shadow =
@@ -87,7 +87,7 @@
                     Geometry{
                             .boundaries = smallerRect,
                             .roundedCornersCrop = rect,
-                            .roundedCornersRadius = 50.f,
+                            .roundedCornersRadius = {50.f, 50.f},
                     },
             .source =
                     PixelSource{
@@ -96,7 +96,6 @@
             .alpha = 1,
     };
 
-    auto layers = std::vector<LayerSettings>{layer, caster};
     // Four combinations of settings are used (two transforms here, and drawShadowLayers is
     // called with two different destination data spaces) They're all rounded rect.
     // Three of these are cache misses that generate new shaders.
@@ -115,6 +114,8 @@
     for (auto transform : {mat4(), kFlip}) {
         layer.geometry.positionTransform = transform;
         caster.geometry.positionTransform = transform;
+
+        auto layers = std::vector<LayerSettings>{layer, caster};
         renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
                                  base::unique_fd());
     }
@@ -141,18 +142,18 @@
                                           }},
     };
 
-    auto layers = std::vector<LayerSettings>{layer};
     for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
         layer.sourceDataspace = dataspace;
         // Cache shaders for both rects and round rects.
         // In reduced shader mode, all non-zero round rect radii get the same code path.
         for (float roundedCornersRadius : {0.0f, 50.0f}) {
             // roundedCornersCrop is always set, but the radius triggers the behavior
-            layer.geometry.roundedCornersRadius = roundedCornersRadius;
+            layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius};
             for (bool isOpaque : {true, false}) {
                 layer.source.buffer.isOpaque = isOpaque;
                 for (auto alpha : {half(.2f), half(1.0f)}) {
                     layer.alpha = alpha;
+                    auto layers = std::vector<LayerSettings>{layer};
                     renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
                                              base::unique_fd());
                 }
@@ -177,11 +178,11 @@
             .alpha = 0.5,
     };
 
-    auto layers = std::vector<LayerSettings>{layer};
     for (auto transform : {mat4(), kScaleAndTranslate}) {
         layer.geometry.positionTransform = transform;
         for (float roundedCornersRadius : {0.0f, 50.f}) {
-            layer.geometry.roundedCornersRadius = roundedCornersRadius;
+            layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius};
+            auto layers = std::vector<LayerSettings>{layer};
             renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
                                      base::unique_fd());
         }
@@ -202,10 +203,10 @@
             .skipContentDraw = true,
     };
 
-    auto layers = std::vector<LayerSettings>{layer};
     // Different blur code is invoked for radii less and greater than 30 pixels
     for (int radius : {9, 60}) {
         layer.backgroundBlurRadius = radius;
+        auto layers = std::vector<LayerSettings>{layer};
         renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
                                  base::unique_fd());
     }
@@ -237,13 +238,12 @@
             .geometry =
                     Geometry{
                             .boundaries = rect,
-                            .roundedCornersRadius = 27, // larger than the 20 above.
+                            .roundedCornersRadius = {27.f, 27.f},
                             .roundedCornersCrop =
                                     FloatRect(0, 0, displayRect.width(), displayRect.height()),
                     },
     };
 
-    auto layers = std::vector<LayerSettings>{layer};
     for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) {
         layer.source = pixelSource;
         for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
@@ -252,7 +252,8 @@
             for (auto transform : {kScaleAndTranslate, kScaleAsymmetric}) {
                 layer.geometry.positionTransform = transform;
                 for (float alpha : {0.5f, 1.f}) {
-                    layer.alpha = alpha,
+                    layer.alpha = alpha;
+                    auto layers = std::vector<LayerSettings>{layer};
                     renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
                                              base::unique_fd());
                 }
@@ -274,9 +275,9 @@
                             // larger than the layer bounds.
                             .positionTransform = kFlip,
                             .boundaries = rect,
-                            .roundedCornersRadius = 94.2551,
-                            .roundedCornersCrop = FloatRect(
-                                -93.75, 0, displayRect.width() + 93.75, displayRect.height()),
+                            .roundedCornersRadius = {94.2551f, 94.2551f},
+                            .roundedCornersCrop = FloatRect(-93.75, 0, displayRect.width() + 93.75,
+                                                            displayRect.height()),
                     },
             .source = PixelSource{.buffer =
                                           Buffer{
@@ -306,10 +307,11 @@
                             // the boundaries have to be smaller than the rounded crop so that
                             // clipRRect is used instead of drawRRect
                             .boundaries = small,
-                            .roundedCornersRadius = 50.f,
+                            .roundedCornersRadius = {50.f, 50.f},
                             .roundedCornersCrop = rect,
                     },
-            .source = PixelSource{
+            .source =
+                    PixelSource{
                             .solidColor = half3(0.f, 0.f, 0.f),
                     },
             .sourceDataspace = kDestDataSpace,
@@ -362,8 +364,8 @@
         const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
 
         sp<GraphicBuffer> dstBuffer =
-                new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
-                                  1, usage, "primeShaderCache_dst");
+                sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
+                                        PIXEL_FORMAT_RGBA_8888, 1, usage, "primeShaderCache_dst");
 
         const auto dstTexture =
                 std::make_shared<impl::ExternalTexture>(dstBuffer, *renderengine,
@@ -373,8 +375,8 @@
         // something, but the details are not important. Make use of the shadow layer drawing step
         // to populate it.
         sp<GraphicBuffer> srcBuffer =
-                new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
-                                  1, usage, "drawImageLayer_src");
+                sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
+                                        PIXEL_FORMAT_RGBA_8888, 1, usage, "drawImageLayer_src");
 
         const auto srcTexture = std::make_shared<
                 impl::ExternalTexture>(srcBuffer, *renderengine,
@@ -396,8 +398,9 @@
         // GRALLOC_USAGE_HW_TEXTURE should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE.
         const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE;
         sp<GraphicBuffer> externalBuffer =
-                new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
-                                  1, usageExternal, "primeShaderCache_external");
+                sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
+                                        PIXEL_FORMAT_RGBA_8888, 1, usageExternal,
+                                        "primeShaderCache_external");
         const auto externalTexture =
                 std::make_shared<impl::ExternalTexture>(externalBuffer, *renderengine,
                                                         impl::ExternalTexture::Usage::READABLE);
@@ -407,8 +410,9 @@
         // Another external texture with a different pixel format triggers useIsOpaqueWorkaround.
         // It doesn't have to be f16, but it can't be the usual 8888.
         sp<GraphicBuffer> f16ExternalBuffer =
-                new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_FP16,
-                                  1, usageExternal, "primeShaderCache_external_f16");
+                sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
+                                        PIXEL_FORMAT_RGBA_FP16, 1, usageExternal,
+                                        "primeShaderCache_external_f16");
         // The F16 texture may not be usable on all devices, so check first that it was created.
         status_t error = f16ExternalBuffer->initCheck();
         if (!error) {
@@ -438,7 +442,7 @@
 
         const nsecs_t timeAfter = systemTime();
         const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
-        const int shadersCompiled = renderengine->reportShadersCompiled();
+        const int shadersCompiled = renderengine->reportShadersCompiled() - previousCount;
         ALOGD("Shader cache generated %d shaders in %f ms\n", shadersCompiled, compileTimeMs);
     }
 }
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index c482fa4..347b8b7 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -24,42 +24,11 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <GrContextOptions.h>
-#include <SkBlendMode.h>
-#include <SkCanvas.h>
-#include <SkColor.h>
-#include <SkColorFilter.h>
-#include <SkColorMatrix.h>
-#include <SkColorSpace.h>
-#include <SkData.h>
-#include <SkGraphics.h>
-#include <SkImage.h>
-#include <SkImageFilters.h>
-#include <SkImageInfo.h>
-#include <SkM44.h>
-#include <SkMatrix.h>
-#include <SkPaint.h>
-#include <SkPath.h>
-#include <SkPoint.h>
-#include <SkRect.h>
-#include <SkRefCnt.h>
-#include <SkRegion.h>
-#include <SkRRect.h>
-#include <SkRuntimeEffect.h>
-#include <SkSamplingOptions.h>
-#include <SkScalar.h>
-#include <SkShader.h>
-#include <SkShadowUtils.h>
-#include <SkString.h>
-#include <SkSurface.h>
-#include <SkTileMode.h>
 #include <android-base/stringprintf.h>
 #include <gl/GrGLInterface.h>
 #include <gui/TraceUtils.h>
 #include <sync/sync.h>
-#include <ui/BlurRegion.h>
-#include <ui/DataspaceUtils.h>
 #include <ui/DebugUtils.h>
-#include <ui/GraphicBuffer.h>
 #include <utils/Trace.h>
 
 #include <cmath>
@@ -68,23 +37,7 @@
 #include <numeric>
 
 #include "../gl/GLExtensions.h"
-#include "Cache.h"
-#include "ColorSpaces.h"
-#include "filters/BlurFilter.h"
-#include "filters/GaussianBlurFilter.h"
-#include "filters/KawaseBlurFilter.h"
-#include "filters/LinearEffect.h"
 #include "log/log_main.h"
-#include "skia/debug/SkiaCapture.h"
-#include "skia/debug/SkiaMemoryReporter.h"
-#include "skia/filters/StretchShaderFactory.h"
-#include "system/graphics-base-v1.0.h"
-
-namespace {
-// Debugging settings
-static const bool kPrintLayerSettings = false;
-static const bool kFlushAfterEveryLayer = false;
-} // namespace
 
 bool checkGlError(const char* op, int lineNumber);
 
@@ -243,6 +196,7 @@
     std::unique_ptr<SkiaGLRenderEngine> engine =
             std::make_unique<SkiaGLRenderEngine>(args, display, ctxt, placeholder, protectedContext,
                                                  protectedPlaceholder);
+    engine->ensureGrContextsCreated();
 
     ALOGI("OpenGL ES informations:");
     ALOGI("vendor    : %s", extensions.getVendor());
@@ -255,11 +209,6 @@
     return engine;
 }
 
-std::future<void> SkiaGLRenderEngine::primeCache() {
-    Cache::primeShaderCache(this);
-    return {};
-}
-
 EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
     status_t err;
     EGLConfig config;
@@ -299,76 +248,20 @@
     return config;
 }
 
-sk_sp<SkData> SkiaGLRenderEngine::SkSLCacheMonitor::load(const SkData& key) {
-    // This "cache" does not actually cache anything. It just allows us to
-    // monitor Skia's internal cache. So this method always returns null.
-    return nullptr;
-}
-
-void SkiaGLRenderEngine::SkSLCacheMonitor::store(const SkData& key, const SkData& data,
-                                                 const SkString& description) {
-    mShadersCachedSinceLastCall++;
-}
-
-void SkiaGLRenderEngine::assertShadersCompiled(int numShaders) {
-    const int cached = mSkSLCacheMonitor.shadersCachedSinceLastCall();
-    LOG_ALWAYS_FATAL_IF(cached != numShaders, "Attempted to cache %i shaders; cached %i",
-                        numShaders, cached);
-}
-
-int SkiaGLRenderEngine::reportShadersCompiled() {
-    return mSkSLCacheMonitor.shadersCachedSinceLastCall();
-}
-
 SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
                                        EGLContext ctxt, EGLSurface placeholder,
                                        EGLContext protectedContext, EGLSurface protectedPlaceholder)
-      : SkiaRenderEngine(args.renderEngineType),
+      : SkiaRenderEngine(args.renderEngineType,
+                         static_cast<PixelFormat>(args.pixelFormat),
+                         args.useColorManagement, args.supportsBackgroundBlur),
         mEGLDisplay(display),
         mEGLContext(ctxt),
         mPlaceholderSurface(placeholder),
         mProtectedEGLContext(protectedContext),
-        mProtectedPlaceholderSurface(protectedPlaceholder),
-        mDefaultPixelFormat(static_cast<PixelFormat>(args.pixelFormat)),
-        mUseColorManagement(args.useColorManagement) {
-    sk_sp<const GrGLInterface> glInterface = GrGLMakeNativeInterface();
-    LOG_ALWAYS_FATAL_IF(!glInterface.get());
-
-    GrContextOptions options;
-    options.fDisableDriverCorrectnessWorkarounds = true;
-    options.fDisableDistanceFieldPaths = true;
-    options.fReducedShaderVariations = true;
-    options.fPersistentCache = &mSkSLCacheMonitor;
-    mGrContext = GrDirectContext::MakeGL(glInterface, options);
-    if (supportsProtectedContent()) {
-        useProtectedContext(true);
-        mProtectedGrContext = GrDirectContext::MakeGL(glInterface, options);
-        useProtectedContext(false);
-    }
-
-    if (args.supportsBackgroundBlur) {
-        ALOGD("Background Blurs Enabled");
-        mBlurFilter = new KawaseBlurFilter();
-    }
-    mCapture = std::make_unique<SkiaCapture>();
-}
+        mProtectedPlaceholderSurface(protectedPlaceholder) { }
 
 SkiaGLRenderEngine::~SkiaGLRenderEngine() {
-    std::lock_guard<std::mutex> lock(mRenderingMutex);
-    if (mBlurFilter) {
-        delete mBlurFilter;
-    }
-
-    mCapture = nullptr;
-
-    mGrContext->flushAndSubmit(true);
-    mGrContext->abandonContext();
-
-    if (mProtectedGrContext) {
-        mProtectedGrContext->flushAndSubmit(true);
-        mProtectedGrContext->abandonContext();
-    }
-
+    finishRenderingAndAbandonContext();
     if (mPlaceholderSurface != EGL_NO_SURFACE) {
         eglDestroySurface(mEGLDisplay, mPlaceholderSurface);
     }
@@ -386,71 +279,69 @@
     eglReleaseThread();
 }
 
-bool SkiaGLRenderEngine::supportsProtectedContent() const {
+SkiaRenderEngine::Contexts SkiaGLRenderEngine::createDirectContexts(
+    const GrContextOptions& options) {
+
+    LOG_ALWAYS_FATAL_IF(isProtected(),
+                        "Cannot setup contexts while already in protected mode");
+
+    sk_sp<const GrGLInterface> glInterface = GrGLMakeNativeInterface();
+
+    LOG_ALWAYS_FATAL_IF(!glInterface.get(), "GrGLMakeNativeInterface() failed");
+
+    SkiaRenderEngine::Contexts contexts;
+    contexts.first = GrDirectContext::MakeGL(glInterface, options);
+    if (supportsProtectedContentImpl()) {
+        useProtectedContextImpl(GrProtected::kYes);
+        contexts.second = GrDirectContext::MakeGL(glInterface, options);
+        useProtectedContextImpl(GrProtected::kNo);
+    }
+
+    return contexts;
+}
+
+bool SkiaGLRenderEngine::supportsProtectedContentImpl() const {
     return mProtectedEGLContext != EGL_NO_CONTEXT;
 }
 
-GrDirectContext* SkiaGLRenderEngine::getActiveGrContext() const {
-    return mInProtectedContext ? mProtectedGrContext.get() : mGrContext.get();
-}
-
-void SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) {
-    if (useProtectedContext == mInProtectedContext ||
-        (useProtectedContext && !supportsProtectedContent())) {
-        return;
-    }
-
-    // release any scratch resources before switching into a new mode
-    if (getActiveGrContext()) {
-        getActiveGrContext()->purgeUnlockedResources(true);
-    }
-
+bool SkiaGLRenderEngine::useProtectedContextImpl(GrProtected isProtected) {
     const EGLSurface surface =
-            useProtectedContext ? mProtectedPlaceholderSurface : mPlaceholderSurface;
-    const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
+        (isProtected == GrProtected::kYes) ?
+        mProtectedPlaceholderSurface : mPlaceholderSurface;
+    const EGLContext context = (isProtected == GrProtected::kYes) ?
+        mProtectedEGLContext : mEGLContext;
 
-    if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) {
-        mInProtectedContext = useProtectedContext;
-        // given that we are sharing the same thread between two GrContexts we need to
-        // make sure that the thread state is reset when switching between the two.
-        if (getActiveGrContext()) {
-            getActiveGrContext()->resetContext();
-        }
-    }
+    return eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
 }
 
-base::unique_fd SkiaGLRenderEngine::flush() {
-    ATRACE_CALL();
-    if (!gl::GLExtensions::getInstance().hasNativeFenceSync()) {
-        return base::unique_fd();
-    }
-
-    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
-    if (sync == EGL_NO_SYNC_KHR) {
-        ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
-        return base::unique_fd();
-    }
-
-    // native fence fd will not be populated until flush() is done.
-    glFlush();
-
-    // get the fence fd
-    base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
-    eglDestroySyncKHR(mEGLDisplay, sync);
-    if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
-        ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
-    }
-
-    return fenceFd;
-}
-
-void SkiaGLRenderEngine::waitFence(base::borrowed_fd fenceFd) {
+void SkiaGLRenderEngine::waitFence(GrDirectContext*, base::borrowed_fd fenceFd) {
     if (fenceFd.get() >= 0 && !waitGpuFence(fenceFd)) {
         ATRACE_NAME("SkiaGLRenderEngine::waitFence");
         sync_wait(fenceFd.get(), -1);
     }
 }
 
+base::unique_fd SkiaGLRenderEngine::flushAndSubmit(GrDirectContext* grContext) {
+    base::unique_fd drawFence = flush();
+
+    bool requireSync = drawFence.get() < 0;
+    if (requireSync) {
+        ATRACE_BEGIN("Submit(sync=true)");
+    } else {
+        ATRACE_BEGIN("Submit(sync=false)");
+    }
+    bool success = grContext->submit(requireSync);
+    ATRACE_END();
+    if (!success) {
+        ALOGE("Failed to flush RenderEngine commands");
+        // Chances are, something illegal happened (Skia's internal GPU object
+        // doesn't exist, or the context was abandoned).
+        return drawFence;
+    }
+
+    return drawFence;
+}
+
 bool SkiaGLRenderEngine::waitGpuFence(base::borrowed_fd fenceFd) {
     if (!gl::GLExtensions::getInstance().hasNativeFenceSync() ||
         !gl::GLExtensions::getInstance().hasWaitSync()) {
@@ -486,943 +377,29 @@
     return true;
 }
 
-static float toDegrees(uint32_t transform) {
-    switch (transform) {
-        case ui::Transform::ROT_90:
-            return 90.0;
-        case ui::Transform::ROT_180:
-            return 180.0;
-        case ui::Transform::ROT_270:
-            return 270.0;
-        default:
-            return 0.0;
-    }
-}
-
-static SkColorMatrix toSkColorMatrix(const mat4& matrix) {
-    return SkColorMatrix(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0], 0, matrix[0][1],
-                         matrix[1][1], matrix[2][1], matrix[3][1], 0, matrix[0][2], matrix[1][2],
-                         matrix[2][2], matrix[3][2], 0, matrix[0][3], matrix[1][3], matrix[2][3],
-                         matrix[3][3], 0);
-}
-
-static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destinationDataspace) {
-    int64_t sourceTransfer = sourceDataspace & HAL_DATASPACE_TRANSFER_MASK;
-    int64_t destTransfer = destinationDataspace & HAL_DATASPACE_TRANSFER_MASK;
-
-    // Treat unsupported dataspaces as srgb
-    if (destTransfer != HAL_DATASPACE_TRANSFER_LINEAR &&
-        destTransfer != HAL_DATASPACE_TRANSFER_HLG &&
-        destTransfer != HAL_DATASPACE_TRANSFER_ST2084) {
-        destTransfer = HAL_DATASPACE_TRANSFER_SRGB;
-    }
-
-    if (sourceTransfer != HAL_DATASPACE_TRANSFER_LINEAR &&
-        sourceTransfer != HAL_DATASPACE_TRANSFER_HLG &&
-        sourceTransfer != HAL_DATASPACE_TRANSFER_ST2084) {
-        sourceTransfer = HAL_DATASPACE_TRANSFER_SRGB;
-    }
-
-    const bool isSourceLinear = sourceTransfer == HAL_DATASPACE_TRANSFER_LINEAR;
-    const bool isSourceSRGB = sourceTransfer == HAL_DATASPACE_TRANSFER_SRGB;
-    const bool isDestLinear = destTransfer == HAL_DATASPACE_TRANSFER_LINEAR;
-    const bool isDestSRGB = destTransfer == HAL_DATASPACE_TRANSFER_SRGB;
-
-    return !(isSourceLinear && isDestSRGB) && !(isSourceSRGB && isDestLinear) &&
-            sourceTransfer != destTransfer;
-}
-
-void SkiaGLRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
-                                                  bool isRenderable) {
-    // Only run this if RE is running on its own thread. This way the access to GL
-    // operations is guaranteed to be happening on the same thread.
-    if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED) {
-        return;
-    }
-    // We currently don't attempt to map a buffer if the buffer contains protected content
-    // because GPU resources for protected buffers is much more limited.
-    const bool isProtectedBuffer = buffer->getUsage() & GRALLOC_USAGE_PROTECTED;
-    if (isProtectedBuffer) {
-        return;
-    }
+base::unique_fd SkiaGLRenderEngine::flush() {
     ATRACE_CALL();
-
-    // If we were to support caching protected buffers then we will need to switch the
-    // currently bound context if we are not already using the protected context (and subsequently
-    // switch back after the buffer is cached).  However, for non-protected content we can bind
-    // the texture in either GL context because they are initialized with the same share_context
-    // which allows the texture state to be shared between them.
-    auto grContext = getActiveGrContext();
-    auto& cache = mTextureCache;
-
-    std::lock_guard<std::mutex> lock(mRenderingMutex);
-    mGraphicBufferExternalRefs[buffer->getId()]++;
-
-    if (const auto& iter = cache.find(buffer->getId()); iter == cache.end()) {
-        std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef =
-                std::make_shared<AutoBackendTexture::LocalRef>(grContext,
-                                                               buffer->toAHardwareBuffer(),
-                                                               isRenderable, mTextureCleanupMgr);
-        cache.insert({buffer->getId(), imageTextureRef});
-    }
-}
-
-void SkiaGLRenderEngine::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
-    ATRACE_CALL();
-    std::lock_guard<std::mutex> lock(mRenderingMutex);
-    if (const auto& iter = mGraphicBufferExternalRefs.find(buffer->getId());
-        iter != mGraphicBufferExternalRefs.end()) {
-        if (iter->second == 0) {
-            ALOGW("Attempted to unmap GraphicBuffer <id: %" PRId64
-                  "> from RenderEngine texture, but the "
-                  "ref count was already zero!",
-                  buffer->getId());
-            mGraphicBufferExternalRefs.erase(buffer->getId());
-            return;
-        }
-
-        iter->second--;
-
-        // Swap contexts if needed prior to deleting this buffer
-        // See Issue 1 of
-        // https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_protected_content.txt: even
-        // when a protected context and an unprotected context are part of the same share group,
-        // protected surfaces may not be accessed by an unprotected context, implying that protected
-        // surfaces may only be freed when a protected context is active.
-        const bool inProtected = mInProtectedContext;
-        useProtectedContext(buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
-
-        if (iter->second == 0) {
-            mTextureCache.erase(buffer->getId());
-            mGraphicBufferExternalRefs.erase(buffer->getId());
-        }
-
-        // Swap back to the previous context so that cached values of isProtected in SurfaceFlinger
-        // are up-to-date.
-        if (inProtected != mInProtectedContext) {
-            useProtectedContext(inProtected);
-        }
-    }
-}
-
-bool SkiaGLRenderEngine::canSkipPostRenderCleanup() const {
-    std::lock_guard<std::mutex> lock(mRenderingMutex);
-    return mTextureCleanupMgr.isEmpty();
-}
-
-void SkiaGLRenderEngine::cleanupPostRender() {
-    ATRACE_CALL();
-    std::lock_guard<std::mutex> lock(mRenderingMutex);
-    mTextureCleanupMgr.cleanup();
-}
-
-// Helper class intended to be used on the stack to ensure that texture cleanup
-// is deferred until after this class goes out of scope.
-class DeferTextureCleanup final {
-public:
-    DeferTextureCleanup(AutoBackendTexture::CleanupManager& mgr) : mMgr(mgr) {
-        mMgr.setDeferredStatus(true);
-    }
-    ~DeferTextureCleanup() { mMgr.setDeferredStatus(false); }
-
-private:
-    DISALLOW_COPY_AND_ASSIGN(DeferTextureCleanup);
-    AutoBackendTexture::CleanupManager& mMgr;
-};
-
-sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(
-        const RuntimeEffectShaderParameters& parameters) {
-    // The given surface will be stretched by HWUI via matrix transformation
-    // which gets similar results for most surfaces
-    // Determine later on if we need to leverage the stertch shader within
-    // surface flinger
-    const auto& stretchEffect = parameters.layer.stretchEffect;
-    auto shader = parameters.shader;
-    if (stretchEffect.hasEffect()) {
-        const auto targetBuffer = parameters.layer.source.buffer.buffer;
-        const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
-        if (graphicBuffer && parameters.shader) {
-            shader = mStretchShaderFactory.createSkShader(shader, stretchEffect);
-        }
+    if (!gl::GLExtensions::getInstance().hasNativeFenceSync()) {
+        return base::unique_fd();
     }
 
-    if (parameters.requiresLinearEffect) {
-        const ui::Dataspace inputDataspace = mUseColorManagement ? parameters.layer.sourceDataspace
-                                                                 : ui::Dataspace::V0_SRGB_LINEAR;
-        const ui::Dataspace outputDataspace = mUseColorManagement
-                ? parameters.display.outputDataspace
-                : ui::Dataspace::V0_SRGB_LINEAR;
-
-        auto effect =
-                shaders::LinearEffect{.inputDataspace = inputDataspace,
-                                      .outputDataspace = outputDataspace,
-                                      .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha};
-
-        auto effectIter = mRuntimeEffects.find(effect);
-        sk_sp<SkRuntimeEffect> runtimeEffect = nullptr;
-        if (effectIter == mRuntimeEffects.end()) {
-            runtimeEffect = buildRuntimeEffect(effect);
-            mRuntimeEffects.insert({effect, runtimeEffect});
-        } else {
-            runtimeEffect = effectIter->second;
-        }
-        mat4 colorTransform = parameters.layer.colorTransform;
-
-        colorTransform *=
-                mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio,
-                                 parameters.layerDimmingRatio, 1.f));
-        const auto targetBuffer = parameters.layer.source.buffer.buffer;
-        const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
-        const auto hardwareBuffer = graphicBuffer ? graphicBuffer->toAHardwareBuffer() : nullptr;
-        return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform,
-                                        parameters.display.maxLuminance,
-                                        parameters.display.currentLuminanceNits,
-                                        parameters.layer.source.buffer.maxLuminanceNits,
-                                        hardwareBuffer, parameters.display.renderIntent);
-    }
-    return parameters.shader;
-}
-
-void SkiaGLRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
-    if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
-        // Record display settings when capture is running.
-        std::stringstream displaySettings;
-        PrintTo(display, &displaySettings);
-        // Store the DisplaySettings in additional information.
-        canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings",
-                               SkData::MakeWithCString(displaySettings.str().c_str()));
+    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
+        return base::unique_fd();
     }
 
-    // Before doing any drawing, let's make sure that we'll start at the origin of the display.
-    // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
-    // displays might have different scaling when compared to the physical screen.
+    // native fence fd will not be populated until flush() is done.
+    glFlush();
 
-    canvas->clipRect(getSkRect(display.physicalDisplay));
-    canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
-
-    const auto clipWidth = display.clip.width();
-    const auto clipHeight = display.clip.height();
-    auto rotatedClipWidth = clipWidth;
-    auto rotatedClipHeight = clipHeight;
-    // Scale is contingent on the rotation result.
-    if (display.orientation & ui::Transform::ROT_90) {
-        std::swap(rotatedClipWidth, rotatedClipHeight);
-    }
-    const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
-            static_cast<SkScalar>(rotatedClipWidth);
-    const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
-            static_cast<SkScalar>(rotatedClipHeight);
-    canvas->scale(scaleX, scaleY);
-
-    // Canvas rotation is done by centering the clip window at the origin, rotating, translating
-    // back so that the top left corner of the clip is at (0, 0).
-    canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
-    canvas->rotate(toDegrees(display.orientation));
-    canvas->translate(-clipWidth / 2, -clipHeight / 2);
-    canvas->translate(-display.clip.left, -display.clip.top);
-}
-
-class AutoSaveRestore {
-public:
-    AutoSaveRestore(SkCanvas* canvas) : mCanvas(canvas) { mSaveCount = canvas->save(); }
-    ~AutoSaveRestore() { restore(); }
-    void replace(SkCanvas* canvas) {
-        mCanvas = canvas;
-        mSaveCount = canvas->save();
-    }
-    void restore() {
-        if (mCanvas) {
-            mCanvas->restoreToCount(mSaveCount);
-            mCanvas = nullptr;
-        }
+    // get the fence fd
+    base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
+    eglDestroySyncKHR(mEGLDisplay, sync);
+    if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+        ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
     }
 
-private:
-    SkCanvas* mCanvas;
-    int mSaveCount;
-};
-
-static SkRRect getBlurRRect(const BlurRegion& region) {
-    const auto rect = SkRect::MakeLTRB(region.left, region.top, region.right, region.bottom);
-    const SkVector radii[4] = {SkVector::Make(region.cornerRadiusTL, region.cornerRadiusTL),
-                               SkVector::Make(region.cornerRadiusTR, region.cornerRadiusTR),
-                               SkVector::Make(region.cornerRadiusBR, region.cornerRadiusBR),
-                               SkVector::Make(region.cornerRadiusBL, region.cornerRadiusBL)};
-    SkRRect roundedRect;
-    roundedRect.setRectRadii(rect, radii);
-    return roundedRect;
-}
-
-// Arbitrary default margin which should be close enough to zero.
-constexpr float kDefaultMargin = 0.0001f;
-static bool equalsWithinMargin(float expected, float value, float margin = kDefaultMargin) {
-    LOG_ALWAYS_FATAL_IF(margin < 0.f, "Margin is negative!");
-    return std::abs(expected - value) < margin;
-}
-
-void SkiaGLRenderEngine::drawLayersInternal(
-        const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
-        const DisplaySettings& display, const std::vector<LayerSettings>& layers,
-        const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/,
-        base::unique_fd&& bufferFence) {
-    ATRACE_NAME("SkiaGL::drawLayers");
-
-    std::lock_guard<std::mutex> lock(mRenderingMutex);
-    if (layers.empty()) {
-        ALOGV("Drawing empty layer stack");
-        resultPromise->set_value({NO_ERROR, base::unique_fd()});
-        return;
-    }
-
-    if (buffer == nullptr) {
-        ALOGE("No output buffer provided. Aborting GPU composition.");
-        resultPromise->set_value({BAD_VALUE, base::unique_fd()});
-        return;
-    }
-
-    validateOutputBufferUsage(buffer->getBuffer());
-
-    auto grContext = getActiveGrContext();
-    auto& cache = mTextureCache;
-
-    // any AutoBackendTexture deletions will now be deferred until cleanupPostRender is called
-    DeferTextureCleanup dtc(mTextureCleanupMgr);
-
-    std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef;
-    if (const auto& it = cache.find(buffer->getBuffer()->getId()); it != cache.end()) {
-        surfaceTextureRef = it->second;
-    } else {
-        surfaceTextureRef =
-                std::make_shared<AutoBackendTexture::LocalRef>(grContext,
-                                                               buffer->getBuffer()
-                                                                       ->toAHardwareBuffer(),
-                                                               true, mTextureCleanupMgr);
-    }
-
-    // wait on the buffer to be ready to use prior to using it
-    waitFence(bufferFence);
-
-    const ui::Dataspace dstDataspace =
-            mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR;
-    sk_sp<SkSurface> dstSurface = surfaceTextureRef->getOrCreateSurface(dstDataspace, grContext);
-
-    SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get());
-    if (dstCanvas == nullptr) {
-        ALOGE("Cannot acquire canvas from Skia.");
-        resultPromise->set_value({BAD_VALUE, base::unique_fd()});
-        return;
-    }
-
-    // setup color filter if necessary
-    sk_sp<SkColorFilter> displayColorTransform;
-    if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
-        displayColorTransform = SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform));
-    }
-    const bool ctModifiesAlpha =
-            displayColorTransform && !displayColorTransform->isAlphaUnchanged();
-
-    // Find the max layer white point to determine the max luminance of the scene...
-    const float maxLayerWhitePoint = std::transform_reduce(
-            layers.cbegin(), layers.cend(), 0.f,
-            [](float left, float right) { return std::max(left, right); },
-            [&](const auto& l) { return l.whitePointNits; });
-
-    // ...and compute the dimming ratio if dimming is requested
-    const float displayDimmingRatio = display.targetLuminanceNits > 0.f &&
-                    maxLayerWhitePoint > 0.f && display.targetLuminanceNits > maxLayerWhitePoint
-            ? maxLayerWhitePoint / display.targetLuminanceNits
-            : 1.f;
-
-    // Find if any layers have requested blur, we'll use that info to decide when to render to an
-    // offscreen buffer and when to render to the native buffer.
-    sk_sp<SkSurface> activeSurface(dstSurface);
-    SkCanvas* canvas = dstCanvas;
-    SkiaCapture::OffscreenState offscreenCaptureState;
-    const LayerSettings* blurCompositionLayer = nullptr;
-    if (mBlurFilter) {
-        bool requiresCompositionLayer = false;
-        for (const auto& layer : layers) {
-            // if the layer doesn't have blur or it is not visible then continue
-            if (!layerHasBlur(layer, ctModifiesAlpha)) {
-                continue;
-            }
-            if (layer.backgroundBlurRadius > 0 &&
-                layer.backgroundBlurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
-                requiresCompositionLayer = true;
-            }
-            for (auto region : layer.blurRegions) {
-                if (region.blurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
-                    requiresCompositionLayer = true;
-                }
-            }
-            if (requiresCompositionLayer) {
-                activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
-                canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState);
-                blurCompositionLayer = &layer;
-                break;
-            }
-        }
-    }
-
-    AutoSaveRestore surfaceAutoSaveRestore(canvas);
-    // Clear the entire canvas with a transparent black to prevent ghost images.
-    canvas->clear(SK_ColorTRANSPARENT);
-    initCanvas(canvas, display);
-
-    for (const auto& layer : layers) {
-        ATRACE_FORMAT("DrawLayer: %s", layer.name.c_str());
-
-        if (kPrintLayerSettings) {
-            std::stringstream ls;
-            PrintTo(layer, &ls);
-            auto debugs = ls.str();
-            int pos = 0;
-            while (pos < debugs.size()) {
-                ALOGD("cache_debug %s", debugs.substr(pos, 1000).c_str());
-                pos += 1000;
-            }
-        }
-
-        sk_sp<SkImage> blurInput;
-        if (blurCompositionLayer == &layer) {
-            LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface);
-            LOG_ALWAYS_FATAL_IF(canvas == dstCanvas);
-
-            // save a snapshot of the activeSurface to use as input to the blur shaders
-            blurInput = activeSurface->makeImageSnapshot();
-
-            // blit the offscreen framebuffer into the destination AHB, but only
-            // if there are blur regions. backgroundBlurRadius blurs the entire
-            // image below, so it can skip this step.
-            if (layer.blurRegions.size()) {
-                SkPaint paint;
-                paint.setBlendMode(SkBlendMode::kSrc);
-                if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
-                    uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState);
-                    dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()),
-                                              String8::format("SurfaceID|%" PRId64, id).c_str(),
-                                              nullptr);
-                    dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint);
-                } else {
-                    activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
-                }
-            }
-
-            // assign dstCanvas to canvas and ensure that the canvas state is up to date
-            canvas = dstCanvas;
-            surfaceAutoSaveRestore.replace(canvas);
-            initCanvas(canvas, display);
-
-            LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getSaveCount() !=
-                                dstSurface->getCanvas()->getSaveCount());
-            LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getTotalMatrix() !=
-                                dstSurface->getCanvas()->getTotalMatrix());
-
-            // assign dstSurface to activeSurface
-            activeSurface = dstSurface;
-        }
-
-        SkAutoCanvasRestore layerAutoSaveRestore(canvas, true);
-        if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
-            // Record the name of the layer if the capture is running.
-            std::stringstream layerSettings;
-            PrintTo(layer, &layerSettings);
-            // Store the LayerSettings in additional information.
-            canvas->drawAnnotation(SkRect::MakeEmpty(), layer.name.c_str(),
-                                   SkData::MakeWithCString(layerSettings.str().c_str()));
-        }
-        // Layers have a local transform that should be applied to them
-        canvas->concat(getSkM44(layer.geometry.positionTransform).asM33());
-
-        const auto [bounds, roundRectClip] =
-                getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop,
-                                 layer.geometry.roundedCornersRadius);
-        if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) {
-            std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
-
-            // if multiple layers have blur, then we need to take a snapshot now because
-            // only the lowest layer will have blurImage populated earlier
-            if (!blurInput) {
-                blurInput = activeSurface->makeImageSnapshot();
-            }
-            // rect to be blurred in the coordinate space of blurInput
-            const auto blurRect = canvas->getTotalMatrix().mapRect(bounds.rect());
-
-            // if the clip needs to be applied then apply it now and make sure
-            // it is restored before we attempt to draw any shadows.
-            SkAutoCanvasRestore acr(canvas, true);
-            if (!roundRectClip.isEmpty()) {
-                canvas->clipRRect(roundRectClip, true);
-            }
-
-            // TODO(b/182216890): Filter out empty layers earlier
-            if (blurRect.width() > 0 && blurRect.height() > 0) {
-                if (layer.backgroundBlurRadius > 0) {
-                    ATRACE_NAME("BackgroundBlur");
-                    auto blurredImage = mBlurFilter->generate(grContext, layer.backgroundBlurRadius,
-                                                              blurInput, blurRect);
-
-                    cachedBlurs[layer.backgroundBlurRadius] = blurredImage;
-
-                    mBlurFilter->drawBlurRegion(canvas, bounds, layer.backgroundBlurRadius, 1.0f,
-                                                blurRect, blurredImage, blurInput);
-                }
-
-                canvas->concat(getSkM44(layer.blurRegionTransform).asM33());
-                for (auto region : layer.blurRegions) {
-                    if (cachedBlurs[region.blurRadius] == nullptr) {
-                        ATRACE_NAME("BlurRegion");
-                        cachedBlurs[region.blurRadius] =
-                                mBlurFilter->generate(grContext, region.blurRadius, blurInput,
-                                                      blurRect);
-                    }
-
-                    mBlurFilter->drawBlurRegion(canvas, getBlurRRect(region), region.blurRadius,
-                                                region.alpha, blurRect,
-                                                cachedBlurs[region.blurRadius], blurInput);
-                }
-            }
-        }
-
-        if (layer.shadow.length > 0) {
-            // This would require a new parameter/flag to SkShadowUtils::DrawShadow
-            LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow");
-
-            SkRRect shadowBounds, shadowClip;
-            if (layer.geometry.boundaries == layer.shadow.boundaries) {
-                shadowBounds = bounds;
-                shadowClip = roundRectClip;
-            } else {
-                std::tie(shadowBounds, shadowClip) =
-                        getBoundsAndClip(layer.shadow.boundaries, layer.geometry.roundedCornersCrop,
-                                         layer.geometry.roundedCornersRadius);
-            }
-
-            // Technically, if bounds is a rect and roundRectClip is not empty,
-            // it means that the bounds and roundedCornersCrop were different
-            // enough that we should intersect them to find the proper shadow.
-            // In practice, this often happens when the two rectangles appear to
-            // not match due to rounding errors. Draw the rounded version, which
-            // looks more like the intent.
-            const auto& rrect =
-                    shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds;
-            drawShadow(canvas, rrect, layer.shadow);
-        }
-
-        const float layerDimmingRatio = layer.whitePointNits <= 0.f
-                ? displayDimmingRatio
-                : (layer.whitePointNits / maxLayerWhitePoint) * displayDimmingRatio;
-
-        const bool dimInLinearSpace = display.dimmingStage !=
-                aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF;
-
-        const bool requiresLinearEffect = layer.colorTransform != mat4() ||
-                (mUseColorManagement &&
-                 needsToneMapping(layer.sourceDataspace, display.outputDataspace)) ||
-                (dimInLinearSpace && !equalsWithinMargin(1.f, layerDimmingRatio));
-
-        // quick abort from drawing the remaining portion of the layer
-        if (layer.skipContentDraw ||
-            (layer.alpha == 0 && !requiresLinearEffect && !layer.disableBlending &&
-             (!displayColorTransform || displayColorTransform->isAlphaUnchanged()))) {
-            continue;
-        }
-
-        // If we need to map to linear space or color management is disabled, then mark the source
-        // image with the same colorspace as the destination surface so that Skia's color
-        // management is a no-op.
-        const ui::Dataspace layerDataspace = (!mUseColorManagement || requiresLinearEffect)
-                ? dstDataspace
-                : layer.sourceDataspace;
-
-        SkPaint paint;
-        if (layer.source.buffer.buffer) {
-            ATRACE_NAME("DrawImage");
-            validateInputBufferUsage(layer.source.buffer.buffer->getBuffer());
-            const auto& item = layer.source.buffer;
-            std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr;
-
-            if (const auto& iter = cache.find(item.buffer->getBuffer()->getId());
-                iter != cache.end()) {
-                imageTextureRef = iter->second;
-            } else {
-                // If we didn't find the image in the cache, then create a local ref but don't cache
-                // it. If we're using skia, we're guaranteed to run on a dedicated GPU thread so if
-                // we didn't find anything in the cache then we intentionally did not cache this
-                // buffer's resources.
-                imageTextureRef = std::make_shared<
-                        AutoBackendTexture::LocalRef>(grContext,
-                                                      item.buffer->getBuffer()->toAHardwareBuffer(),
-                                                      false, mTextureCleanupMgr);
-            }
-
-            // if the layer's buffer has a fence, then we must must respect the fence prior to using
-            // the buffer.
-            if (layer.source.buffer.fence != nullptr) {
-                waitFence(layer.source.buffer.fence->get());
-            }
-
-            // isOpaque means we need to ignore the alpha in the image,
-            // replacing it with the alpha specified by the LayerSettings. See
-            // https://developer.android.com/reference/android/view/SurfaceControl.Builder#setOpaque(boolean)
-            // The proper way to do this is to use an SkColorType that ignores
-            // alpha, like kRGB_888x_SkColorType, and that is used if the
-            // incoming image is kRGBA_8888_SkColorType. However, the incoming
-            // image may be kRGBA_F16_SkColorType, for which there is no RGBX
-            // SkColorType, or kRGBA_1010102_SkColorType, for which we have
-            // kRGB_101010x_SkColorType, but it is not yet supported as a source
-            // on the GPU. (Adding both is tracked in skbug.com/12048.) In the
-            // meantime, we'll use a workaround that works unless we need to do
-            // any color conversion. The workaround requires that we pretend the
-            // image is already premultiplied, so that we do not premultiply it
-            // before applying SkBlendMode::kPlus.
-            const bool useIsOpaqueWorkaround = item.isOpaque &&
-                    (imageTextureRef->colorType() == kRGBA_1010102_SkColorType ||
-                     imageTextureRef->colorType() == kRGBA_F16_SkColorType);
-            const auto alphaType = useIsOpaqueWorkaround ? kPremul_SkAlphaType
-                    : item.isOpaque                      ? kOpaque_SkAlphaType
-                    : item.usePremultipliedAlpha         ? kPremul_SkAlphaType
-                                                         : kUnpremul_SkAlphaType;
-            sk_sp<SkImage> image = imageTextureRef->makeImage(layerDataspace, alphaType, grContext);
-
-            auto texMatrix = getSkM44(item.textureTransform).asM33();
-            // textureTansform was intended to be passed directly into a shader, so when
-            // building the total matrix with the textureTransform we need to first
-            // normalize it, then apply the textureTransform, then scale back up.
-            texMatrix.preScale(1.0f / bounds.width(), 1.0f / bounds.height());
-            texMatrix.postScale(image->width(), image->height());
-
-            SkMatrix matrix;
-            if (!texMatrix.invert(&matrix)) {
-                matrix = texMatrix;
-            }
-            // The shader does not respect the translation, so we add it to the texture
-            // transform for the SkImage. This will make sure that the correct layer contents
-            // are drawn in the correct part of the screen.
-            matrix.postTranslate(bounds.rect().fLeft, bounds.rect().fTop);
-
-            sk_sp<SkShader> shader;
-
-            if (layer.source.buffer.useTextureFiltering) {
-                shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
-                                           SkSamplingOptions(
-                                                   {SkFilterMode::kLinear, SkMipmapMode::kNone}),
-                                           &matrix);
-            } else {
-                shader = image->makeShader(SkSamplingOptions(), matrix);
-            }
-
-            if (useIsOpaqueWorkaround) {
-                shader = SkShaders::Blend(SkBlendMode::kPlus, shader,
-                                          SkShaders::Color(SkColors::kBlack,
-                                                           toSkColorSpace(layerDataspace)));
-            }
-
-            paint.setShader(createRuntimeEffectShader(
-                    RuntimeEffectShaderParameters{.shader = shader,
-                                                  .layer = layer,
-                                                  .display = display,
-                                                  .undoPremultipliedAlpha = !item.isOpaque &&
-                                                          item.usePremultipliedAlpha,
-                                                  .requiresLinearEffect = requiresLinearEffect,
-                                                  .layerDimmingRatio = dimInLinearSpace
-                                                          ? layerDimmingRatio
-                                                          : 1.f}));
-
-            // Turn on dithering when dimming beyond this (arbitrary) threshold...
-            static constexpr float kDimmingThreshold = 0.2f;
-            // ...or we're rendering an HDR layer down to an 8-bit target
-            // Most HDR standards require at least 10-bits of color depth for source content, so we
-            // can just extract the transfer function rather than dig into precise gralloc layout.
-            // Furthermore, we can assume that the only 8-bit target we support is RGBA8888.
-            const bool requiresDownsample = isHdrDataspace(layer.sourceDataspace) &&
-                    buffer->getPixelFormat() == PIXEL_FORMAT_RGBA_8888;
-            if (layerDimmingRatio <= kDimmingThreshold || requiresDownsample) {
-                paint.setDither(true);
-            }
-            paint.setAlphaf(layer.alpha);
-
-            if (imageTextureRef->colorType() == kAlpha_8_SkColorType) {
-                LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with A8");
-
-                // SysUI creates the alpha layer as a coverage layer, which is
-                // appropriate for the DPU. Use a color matrix to convert it to
-                // a mask.
-                // TODO (b/219525258): Handle input as a mask.
-                //
-                // The color matrix will convert A8 pixels with no alpha to
-                // black, as described by this vector. If the display handles
-                // the color transform, we need to invert it to find the color
-                // that will result in black after the DPU applies the transform.
-                SkV4 black{0.0f, 0.0f, 0.0f, 1.0f}; // r, g, b, a
-                if (display.colorTransform != mat4() && display.deviceHandlesColorTransform) {
-                    SkM44 colorSpaceMatrix = getSkM44(display.colorTransform);
-                    if (colorSpaceMatrix.invert(&colorSpaceMatrix)) {
-                        black = colorSpaceMatrix * black;
-                    } else {
-                        // We'll just have to use 0,0,0 as black, which should
-                        // be close to correct.
-                        ALOGI("Could not invert colorTransform!");
-                    }
-                }
-                SkColorMatrix colorMatrix(0, 0, 0, 0, black[0],
-                                          0, 0, 0, 0, black[1],
-                                          0, 0, 0, 0, black[2],
-                                          0, 0, 0, -1, 1);
-                if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
-                    // On the other hand, if the device doesn't handle it, we
-                    // have to apply it ourselves.
-                    colorMatrix.postConcat(toSkColorMatrix(display.colorTransform));
-                }
-                paint.setColorFilter(SkColorFilters::Matrix(colorMatrix));
-            }
-        } else {
-            ATRACE_NAME("DrawColor");
-            const auto color = layer.source.solidColor;
-            sk_sp<SkShader> shader = SkShaders::Color(SkColor4f{.fR = color.r,
-                                                                .fG = color.g,
-                                                                .fB = color.b,
-                                                                .fA = layer.alpha},
-                                                      toSkColorSpace(layerDataspace));
-            paint.setShader(createRuntimeEffectShader(
-                    RuntimeEffectShaderParameters{.shader = shader,
-                                                  .layer = layer,
-                                                  .display = display,
-                                                  .undoPremultipliedAlpha = false,
-                                                  .requiresLinearEffect = requiresLinearEffect,
-                                                  .layerDimmingRatio = layerDimmingRatio}));
-        }
-
-        if (layer.disableBlending) {
-            paint.setBlendMode(SkBlendMode::kSrc);
-        }
-
-        // An A8 buffer will already have the proper color filter attached to
-        // its paint, including the displayColorTransform as needed.
-        if (!paint.getColorFilter()) {
-            if (!dimInLinearSpace && !equalsWithinMargin(1.0, layerDimmingRatio)) {
-                // If we don't dim in linear space, then when we gamma correct the dimming ratio we
-                // can assume a gamma 2.2 transfer function.
-                static constexpr float kInverseGamma22 = 1.f / 2.2f;
-                const auto gammaCorrectedDimmingRatio =
-                        std::pow(layerDimmingRatio, kInverseGamma22);
-                const auto dimmingMatrix =
-                        mat4::scale(vec4(gammaCorrectedDimmingRatio, gammaCorrectedDimmingRatio,
-                                         gammaCorrectedDimmingRatio, 1.f));
-                paint.setColorFilter(SkColorFilters::Matrix(
-                        toSkColorMatrix(display.colorTransform * dimmingMatrix)));
-            } else {
-                paint.setColorFilter(displayColorTransform);
-            }
-        }
-
-        if (!roundRectClip.isEmpty()) {
-            canvas->clipRRect(roundRectClip, true);
-        }
-
-        if (!bounds.isRect()) {
-            paint.setAntiAlias(true);
-            canvas->drawRRect(bounds, paint);
-        } else {
-            canvas->drawRect(bounds.rect(), paint);
-        }
-        if (kFlushAfterEveryLayer) {
-            ATRACE_NAME("flush surface");
-            activeSurface->flush();
-        }
-    }
-    surfaceAutoSaveRestore.restore();
-    mCapture->endCapture();
-    {
-        ATRACE_NAME("flush surface");
-        LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface);
-        activeSurface->flush();
-    }
-
-    base::unique_fd drawFence = flush();
-
-    // If flush failed or we don't support native fences, we need to force the
-    // gl command stream to be executed.
-    bool requireSync = drawFence.get() < 0;
-    if (requireSync) {
-        ATRACE_BEGIN("Submit(sync=true)");
-    } else {
-        ATRACE_BEGIN("Submit(sync=false)");
-    }
-    bool success = grContext->submit(requireSync);
-    ATRACE_END();
-    if (!success) {
-        ALOGE("Failed to flush RenderEngine commands");
-        // Chances are, something illegal happened (either the caller passed
-        // us bad parameters, or we messed up our shader generation).
-        resultPromise->set_value({INVALID_OPERATION, std::move(drawFence)});
-        return;
-    }
-
-    // checkErrors();
-    resultPromise->set_value({NO_ERROR, std::move(drawFence)});
-    return;
-}
-
-inline SkRect SkiaGLRenderEngine::getSkRect(const FloatRect& rect) {
-    return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
-}
-
-inline SkRect SkiaGLRenderEngine::getSkRect(const Rect& rect) {
-    return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
-}
-
-/**
- *  Verifies that common, simple bounds + clip combinations can be converted into
- *  a single RRect draw call returning true if possible. If true the radii parameter
- *  will be filled with the correct radii values that combined with bounds param will
- *  produce the insected roundRect. If false, the returned state of the radii param is undefined.
- */
-static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,
-                                    const SkRect& insetCrop, float cornerRadius,
-                                    SkVector radii[4]) {
-    const bool leftEqual = bounds.fLeft == crop.fLeft;
-    const bool topEqual = bounds.fTop == crop.fTop;
-    const bool rightEqual = bounds.fRight == crop.fRight;
-    const bool bottomEqual = bounds.fBottom == crop.fBottom;
-
-    // In the event that the corners of the bounds only partially align with the crop we
-    // need to ensure that the resulting shape can still be represented as a round rect.
-    // In particular the round rect implementation will scale the value of all corner radii
-    // if the sum of the radius along any edge is greater than the length of that edge.
-    // See https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
-    const bool requiredWidth = bounds.width() > (cornerRadius * 2);
-    const bool requiredHeight = bounds.height() > (cornerRadius * 2);
-    if (!requiredWidth || !requiredHeight) {
-        return false;
-    }
-
-    // Check each cropped corner to ensure that it exactly matches the crop or its corner is
-    // contained within the cropped shape and does not need rounded.
-    // compute the UpperLeft corner radius
-    if (leftEqual && topEqual) {
-        radii[0].set(cornerRadius, cornerRadius);
-    } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) ||
-               (topEqual && bounds.fLeft >= insetCrop.fLeft)) {
-        radii[0].set(0, 0);
-    } else {
-        return false;
-    }
-    // compute the UpperRight corner radius
-    if (rightEqual && topEqual) {
-        radii[1].set(cornerRadius, cornerRadius);
-    } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) ||
-               (topEqual && bounds.fRight <= insetCrop.fRight)) {
-        radii[1].set(0, 0);
-    } else {
-        return false;
-    }
-    // compute the BottomRight corner radius
-    if (rightEqual && bottomEqual) {
-        radii[2].set(cornerRadius, cornerRadius);
-    } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) ||
-               (bottomEqual && bounds.fRight <= insetCrop.fRight)) {
-        radii[2].set(0, 0);
-    } else {
-        return false;
-    }
-    // compute the BottomLeft corner radius
-    if (leftEqual && bottomEqual) {
-        radii[3].set(cornerRadius, cornerRadius);
-    } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) ||
-               (bottomEqual && bounds.fLeft >= insetCrop.fLeft)) {
-        radii[3].set(0, 0);
-    } else {
-        return false;
-    }
-
-    return true;
-}
-
-inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(const FloatRect& boundsRect,
-                                                                        const FloatRect& cropRect,
-                                                                        const float cornerRadius) {
-    const SkRect bounds = getSkRect(boundsRect);
-    const SkRect crop = getSkRect(cropRect);
-
-    SkRRect clip;
-    if (cornerRadius > 0) {
-        // it the crop and the bounds are equivalent or there is no crop then we don't need a clip
-        if (bounds == crop || crop.isEmpty()) {
-            return {SkRRect::MakeRectXY(bounds, cornerRadius, cornerRadius), clip};
-        }
-
-        // This makes an effort to speed up common, simple bounds + clip combinations by
-        // converting them to a single RRect draw. It is possible there are other cases
-        // that can be converted.
-        if (crop.contains(bounds)) {
-            const auto insetCrop = crop.makeInset(cornerRadius, cornerRadius);
-            if (insetCrop.contains(bounds)) {
-                return {SkRRect::MakeRect(bounds), clip}; // clip is empty - no rounding required
-            }
-
-            SkVector radii[4];
-            if (intersectionIsRoundRect(bounds, crop, insetCrop, cornerRadius, radii)) {
-                SkRRect intersectionBounds;
-                intersectionBounds.setRectRadii(bounds, radii);
-                return {intersectionBounds, clip};
-            }
-        }
-
-        // we didn't hit any of our fast paths so set the clip to the cropRect
-        clip.setRectXY(crop, cornerRadius, cornerRadius);
-    }
-
-    // if we hit this point then we either don't have rounded corners or we are going to rely
-    // on the clip to round the corners for us
-    return {SkRRect::MakeRect(bounds), clip};
-}
-
-inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings& layer,
-                                             bool colorTransformModifiesAlpha) {
-    if (layer.backgroundBlurRadius > 0 || layer.blurRegions.size()) {
-        // return false if the content is opaque and would therefore occlude the blur
-        const bool opaqueContent = !layer.source.buffer.buffer || layer.source.buffer.isOpaque;
-        const bool opaqueAlpha = layer.alpha == 1.0f && !colorTransformModifiesAlpha;
-        return layer.skipContentDraw || !(opaqueContent && opaqueAlpha);
-    }
-    return false;
-}
-
-inline SkColor SkiaGLRenderEngine::getSkColor(const vec4& color) {
-    return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255);
-}
-
-inline SkM44 SkiaGLRenderEngine::getSkM44(const mat4& matrix) {
-    return SkM44(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],
-                 matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],
-                 matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2],
-                 matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);
-}
-
-inline SkPoint3 SkiaGLRenderEngine::getSkPoint3(const vec3& vector) {
-    return SkPoint3::Make(vector.x, vector.y, vector.z);
-}
-
-size_t SkiaGLRenderEngine::getMaxTextureSize() const {
-    return mGrContext->maxTextureSize();
-}
-
-size_t SkiaGLRenderEngine::getMaxViewportDims() const {
-    return mGrContext->maxRenderTargetSize();
-}
-
-void SkiaGLRenderEngine::drawShadow(SkCanvas* canvas, const SkRRect& casterRRect,
-                                    const ShadowSettings& settings) {
-    ATRACE_CALL();
-    const float casterZ = settings.length / 2.0f;
-    const auto flags =
-            settings.casterIsTranslucent ? kTransparentOccluder_ShadowFlag : kNone_ShadowFlag;
-
-    SkShadowUtils::DrawShadow(canvas, SkPath::RRect(casterRRect), SkPoint3::Make(0, 0, casterZ),
-                              getSkPoint3(settings.lightPos), settings.lightRadius,
-                              getSkColor(settings.ambientColor), getSkColor(settings.spotColor),
-                              flags);
+    return fenceFd;
 }
 
 EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
@@ -1542,114 +519,14 @@
     return value;
 }
 
-void SkiaGLRenderEngine::onActiveDisplaySizeChanged(ui::Size size) {
-    // This cache multiplier was selected based on review of cache sizes relative
-    // to the screen resolution. Looking at the worst case memory needed by blur (~1.5x),
-    // shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a
-    // conservative default based on that analysis.
-    const float SURFACE_SIZE_MULTIPLIER = 3.5f * bytesPerPixel(mDefaultPixelFormat);
-    const int maxResourceBytes = size.width * size.height * SURFACE_SIZE_MULTIPLIER;
-
-    // start by resizing the current context
-    getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
-
-    // if it is possible to switch contexts then we will resize the other context
-    const bool originalProtectedState = mInProtectedContext;
-    useProtectedContext(!mInProtectedContext);
-    if (mInProtectedContext != originalProtectedState) {
-        getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
-        // reset back to the initial context that was active when this method was called
-        useProtectedContext(originalProtectedState);
-    }
-}
-
-void SkiaGLRenderEngine::dump(std::string& result) {
+void SkiaGLRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
     const gl::GLExtensions& extensions = gl::GLExtensions::getInstance();
-
-    StringAppendF(&result, "\n ------------RE-----------------\n");
+    StringAppendF(&result, "\n ------------RE GLES------------\n");
     StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion());
     StringAppendF(&result, "%s\n", extensions.getEGLExtensions());
     StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
                   extensions.getVersion());
     StringAppendF(&result, "%s\n", extensions.getExtensions());
-    StringAppendF(&result, "RenderEngine supports protected context: %d\n",
-                  supportsProtectedContent());
-    StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext);
-    StringAppendF(&result, "RenderEngine shaders cached since last dump/primeCache: %d\n",
-                  mSkSLCacheMonitor.shadersCachedSinceLastCall());
-
-    std::vector<ResourcePair> cpuResourceMap = {
-            {"skia/sk_resource_cache/bitmap_", "Bitmaps"},
-            {"skia/sk_resource_cache/rrect-blur_", "Masks"},
-            {"skia/sk_resource_cache/rects-blur_", "Masks"},
-            {"skia/sk_resource_cache/tessellated", "Shadows"},
-            {"skia", "Other"},
-    };
-    SkiaMemoryReporter cpuReporter(cpuResourceMap, false);
-    SkGraphics::DumpMemoryStatistics(&cpuReporter);
-    StringAppendF(&result, "Skia CPU Caches: ");
-    cpuReporter.logTotals(result);
-    cpuReporter.logOutput(result);
-
-    {
-        std::lock_guard<std::mutex> lock(mRenderingMutex);
-
-        std::vector<ResourcePair> gpuResourceMap = {
-                {"texture_renderbuffer", "Texture/RenderBuffer"},
-                {"texture", "Texture"},
-                {"gr_text_blob_cache", "Text"},
-                {"skia", "Other"},
-        };
-        SkiaMemoryReporter gpuReporter(gpuResourceMap, true);
-        mGrContext->dumpMemoryStatistics(&gpuReporter);
-        StringAppendF(&result, "Skia's GPU Caches: ");
-        gpuReporter.logTotals(result);
-        gpuReporter.logOutput(result);
-        StringAppendF(&result, "Skia's Wrapped Objects:\n");
-        gpuReporter.logOutput(result, true);
-
-        StringAppendF(&result, "RenderEngine tracked buffers: %zu\n",
-                      mGraphicBufferExternalRefs.size());
-        StringAppendF(&result, "Dumping buffer ids...\n");
-        for (const auto& [id, refCounts] : mGraphicBufferExternalRefs) {
-            StringAppendF(&result, "- 0x%" PRIx64 " - %d refs \n", id, refCounts);
-        }
-        StringAppendF(&result, "RenderEngine AHB/BackendTexture cache size: %zu\n",
-                      mTextureCache.size());
-        StringAppendF(&result, "Dumping buffer ids...\n");
-        // TODO(178539829): It would be nice to know which layer these are coming from and what
-        // the texture sizes are.
-        for (const auto& [id, unused] : mTextureCache) {
-            StringAppendF(&result, "- 0x%" PRIx64 "\n", id);
-        }
-        StringAppendF(&result, "\n");
-
-        SkiaMemoryReporter gpuProtectedReporter(gpuResourceMap, true);
-        if (mProtectedGrContext) {
-            mProtectedGrContext->dumpMemoryStatistics(&gpuProtectedReporter);
-        }
-        StringAppendF(&result, "Skia's GPU Protected Caches: ");
-        gpuProtectedReporter.logTotals(result);
-        gpuProtectedReporter.logOutput(result);
-        StringAppendF(&result, "Skia's Protected Wrapped Objects:\n");
-        gpuProtectedReporter.logOutput(result, true);
-
-        StringAppendF(&result, "\n");
-        StringAppendF(&result, "RenderEngine runtime effects: %zu\n", mRuntimeEffects.size());
-        for (const auto& [linearEffect, unused] : mRuntimeEffects) {
-            StringAppendF(&result, "- inputDataspace: %s\n",
-                          dataspaceDetails(
-                                  static_cast<android_dataspace>(linearEffect.inputDataspace))
-                                  .c_str());
-            StringAppendF(&result, "- outputDataspace: %s\n",
-                          dataspaceDetails(
-                                  static_cast<android_dataspace>(linearEffect.outputDataspace))
-                                  .c_str());
-            StringAppendF(&result, "undoPremultipliedAlpha: %s\n",
-                          linearEffect.undoPremultipliedAlpha ? "true" : "false");
-        }
-    }
-    StringAppendF(&result, "\n");
 }
 
 } // namespace skia
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index c891a70..4a37ffe 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -43,6 +43,8 @@
 
 class SkData;
 
+struct SkPoint3;
+
 namespace android {
 namespace renderengine {
 namespace skia {
@@ -53,34 +55,23 @@
     SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLContext ctxt,
                        EGLSurface placeholder, EGLContext protectedContext,
                        EGLSurface protectedPlaceholder);
-    ~SkiaGLRenderEngine() override EXCLUDES(mRenderingMutex);
+    ~SkiaGLRenderEngine() override;
 
-    std::future<void> primeCache() override;
-    void cleanupPostRender() override;
-    void cleanFramebufferCache() override{};
     int getContextPriority() override;
-    bool isProtected() const override { return mInProtectedContext; }
-    bool supportsProtectedContent() const override;
-    void useProtectedContext(bool useProtectedContext) override;
-    bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
-    void assertShadersCompiled(int numShaders) override;
-    void onActiveDisplaySizeChanged(ui::Size size) override;
-    int reportShadersCompiled() override;
 
 protected:
-    void dump(std::string& result) override;
-    size_t getMaxTextureSize() const override;
-    size_t getMaxViewportDims() const override;
-    void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
-    void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override;
-    bool canSkipPostRenderCleanup() const override;
-    void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
-                            const DisplaySettings& display,
-                            const std::vector<LayerSettings>& layers,
-                            const std::shared_ptr<ExternalTexture>& buffer,
-                            const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
+    // Implementations of abstract SkiaRenderEngine functions specific to
+    // rendering backend
+    virtual SkiaRenderEngine::Contexts createDirectContexts(const GrContextOptions& options);
+    bool supportsProtectedContentImpl() const override;
+    bool useProtectedContextImpl(GrProtected isProtected) override;
+    void waitFence(GrDirectContext* grContext, base::borrowed_fd fenceFd) override;
+    base::unique_fd flushAndSubmit(GrDirectContext* context) override;
+    void appendBackendSpecificInfoToDump(std::string& result) override;
 
 private:
+    bool waitGpuFence(base::borrowed_fd fenceFd);
+    base::unique_fd flush();
     static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
     static EGLContext createEglContext(EGLDisplay display, EGLConfig config,
                                        EGLContext shareContext,
@@ -88,103 +79,14 @@
                                        Protection protection);
     static std::optional<RenderEngine::ContextPriority> createContextPriority(
             const RenderEngineCreationArgs& args);
-    static EGLSurface createPlaceholderEglPbufferSurface(EGLDisplay display, EGLConfig config,
-                                                         int hwcFormat, Protection protection);
-    inline SkRect getSkRect(const FloatRect& layer);
-    inline SkRect getSkRect(const Rect& layer);
-    inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const FloatRect& bounds,
-                                                        const FloatRect& crop, float cornerRadius);
-    inline bool layerHasBlur(const LayerSettings& layer, bool colorTransformModifiesAlpha);
-    inline SkColor getSkColor(const vec4& color);
-    inline SkM44 getSkM44(const mat4& matrix);
-    inline SkPoint3 getSkPoint3(const vec3& vector);
-    inline GrDirectContext* getActiveGrContext() const;
-
-    base::unique_fd flush();
-    // waitFence attempts to wait in the GPU, and if unable to waits on the CPU instead.
-    void waitFence(base::borrowed_fd fenceFd);
-    bool waitGpuFence(base::borrowed_fd fenceFd);
-
-    void initCanvas(SkCanvas* canvas, const DisplaySettings& display);
-    void drawShadow(SkCanvas* canvas, const SkRRect& casterRRect,
-                    const ShadowSettings& shadowSettings);
-
-    // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned.
-    // Otherwise it returns the input shader.
-    struct RuntimeEffectShaderParameters {
-        sk_sp<SkShader> shader;
-        const LayerSettings& layer;
-        const DisplaySettings& display;
-        bool undoPremultipliedAlpha;
-        bool requiresLinearEffect;
-        float layerDimmingRatio;
-    };
-    sk_sp<SkShader> createRuntimeEffectShader(const RuntimeEffectShaderParameters&);
+    static EGLSurface createPlaceholderEglPbufferSurface(
+            EGLDisplay display, EGLConfig config, int hwcFormat, Protection protection);
 
     EGLDisplay mEGLDisplay;
     EGLContext mEGLContext;
     EGLSurface mPlaceholderSurface;
     EGLContext mProtectedEGLContext;
     EGLSurface mProtectedPlaceholderSurface;
-    BlurFilter* mBlurFilter = nullptr;
-
-    const PixelFormat mDefaultPixelFormat;
-    const bool mUseColorManagement;
-
-    // Identifier used or various mappings of layers to various
-    // textures or shaders
-    using GraphicBufferId = uint64_t;
-
-    // Number of external holders of ExternalTexture references, per GraphicBuffer ID.
-    std::unordered_map<GraphicBufferId, int32_t> mGraphicBufferExternalRefs
-            GUARDED_BY(mRenderingMutex);
-    // Cache of GL textures that we'll store per GraphicBuffer ID, shared between GPU contexts.
-    std::unordered_map<GraphicBufferId, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache
-            GUARDED_BY(mRenderingMutex);
-    std::unordered_map<shaders::LinearEffect, sk_sp<SkRuntimeEffect>, shaders::LinearEffectHasher>
-            mRuntimeEffects;
-    AutoBackendTexture::CleanupManager mTextureCleanupMgr GUARDED_BY(mRenderingMutex);
-
-    StretchShaderFactory mStretchShaderFactory;
-    // Mutex guarding rendering operations, so that:
-    // 1. GL operations aren't interleaved, and
-    // 2. Internal state related to rendering that is potentially modified by
-    // multiple threads is guaranteed thread-safe.
-    mutable std::mutex mRenderingMutex;
-
-    sp<Fence> mLastDrawFence;
-
-    // Graphics context used for creating surfaces and submitting commands
-    sk_sp<GrDirectContext> mGrContext;
-    // Same as above, but for protected content (eg. DRM)
-    sk_sp<GrDirectContext> mProtectedGrContext;
-
-    bool mInProtectedContext = false;
-    // Object to capture commands send to Skia.
-    std::unique_ptr<SkiaCapture> mCapture;
-
-    // Implements PersistentCache as a way to monitor what SkSL shaders Skia has
-    // cached.
-    class SkSLCacheMonitor : public GrContextOptions::PersistentCache {
-    public:
-        SkSLCacheMonitor() = default;
-        ~SkSLCacheMonitor() override = default;
-
-        sk_sp<SkData> load(const SkData& key) override;
-
-        void store(const SkData& key, const SkData& data, const SkString& description) override;
-
-        int shadersCachedSinceLastCall() {
-            const int shadersCachedSinceLastCall = mShadersCachedSinceLastCall;
-            mShadersCachedSinceLastCall = 0;
-            return shadersCachedSinceLastCall;
-        }
-
-    private:
-        int mShadersCachedSinceLastCall = 0;
-    };
-
-    SkSLCacheMonitor mSkSLCacheMonitor;
 };
 
 } // namespace skia
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index 1fb24f5..db983a8 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -20,16 +20,1244 @@
 
 #include "SkiaRenderEngine.h"
 
+#include <GrBackendSemaphore.h>
+#include <GrContextOptions.h>
+#include <SkBlendMode.h>
+#include <SkCanvas.h>
+#include <SkColor.h>
+#include <SkColorFilter.h>
+#include <SkColorMatrix.h>
+#include <SkColorSpace.h>
+#include <SkData.h>
+#include <SkGraphics.h>
+#include <SkImage.h>
+#include <SkImageFilters.h>
+#include <SkImageInfo.h>
+#include <SkM44.h>
+#include <SkMatrix.h>
+#include <SkPaint.h>
+#include <SkPath.h>
+#include <SkPoint.h>
+#include <SkPoint3.h>
+#include <SkRect.h>
+#include <SkRefCnt.h>
+#include <SkRegion.h>
+#include <SkRRect.h>
+#include <SkRuntimeEffect.h>
+#include <SkSamplingOptions.h>
+#include <SkScalar.h>
+#include <SkShader.h>
+#include <SkShadowUtils.h>
+#include <SkString.h>
+#include <SkSurface.h>
+#include <SkTileMode.h>
 #include <src/core/SkTraceEventCommon.h>
+#include <android-base/stringprintf.h>
+#include <gui/TraceUtils.h>
+#include <sync/sync.h>
+#include <ui/BlurRegion.h>
+#include <ui/DataspaceUtils.h>
+#include <ui/DebugUtils.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Trace.h>
+
+#include <cmath>
+#include <cstdint>
+#include <memory>
+#include <numeric>
+
+#include "Cache.h"
+#include "ColorSpaces.h"
+#include "filters/BlurFilter.h"
+#include "filters/GaussianBlurFilter.h"
+#include "filters/KawaseBlurFilter.h"
+#include "filters/LinearEffect.h"
+#include "log/log_main.h"
+#include "skia/debug/SkiaCapture.h"
+#include "skia/debug/SkiaMemoryReporter.h"
+#include "skia/filters/StretchShaderFactory.h"
+#include "system/graphics-base-v1.0.h"
+
+namespace {
+
+// Debugging settings
+static const bool kPrintLayerSettings = false;
+static const bool kFlushAfterEveryLayer = kPrintLayerSettings;
+
+} // namespace
+
+// Utility functions related to SkRect
+
+namespace {
+
+static inline SkRect getSkRect(const android::FloatRect& rect) {
+    return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
+}
+
+static inline SkRect getSkRect(const android::Rect& rect) {
+    return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
+}
+
+/**
+ *  Verifies that common, simple bounds + clip combinations can be converted into
+ *  a single RRect draw call returning true if possible. If true the radii parameter
+ *  will be filled with the correct radii values that combined with bounds param will
+ *  produce the insected roundRect. If false, the returned state of the radii param is undefined.
+ */
+static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,
+                                    const SkRect& insetCrop, const android::vec2& cornerRadius,
+                                    SkVector radii[4]) {
+    const bool leftEqual = bounds.fLeft == crop.fLeft;
+    const bool topEqual = bounds.fTop == crop.fTop;
+    const bool rightEqual = bounds.fRight == crop.fRight;
+    const bool bottomEqual = bounds.fBottom == crop.fBottom;
+
+    // In the event that the corners of the bounds only partially align with the crop we
+    // need to ensure that the resulting shape can still be represented as a round rect.
+    // In particular the round rect implementation will scale the value of all corner radii
+    // if the sum of the radius along any edge is greater than the length of that edge.
+    // See https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
+    const bool requiredWidth = bounds.width() > (cornerRadius.x * 2);
+    const bool requiredHeight = bounds.height() > (cornerRadius.y * 2);
+    if (!requiredWidth || !requiredHeight) {
+        return false;
+    }
+
+    // Check each cropped corner to ensure that it exactly matches the crop or its corner is
+    // contained within the cropped shape and does not need rounded.
+    // compute the UpperLeft corner radius
+    if (leftEqual && topEqual) {
+        radii[0].set(cornerRadius.x, cornerRadius.y);
+    } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) ||
+               (topEqual && bounds.fLeft >= insetCrop.fLeft)) {
+        radii[0].set(0, 0);
+    } else {
+        return false;
+    }
+    // compute the UpperRight corner radius
+    if (rightEqual && topEqual) {
+        radii[1].set(cornerRadius.x, cornerRadius.y);
+    } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) ||
+               (topEqual && bounds.fRight <= insetCrop.fRight)) {
+        radii[1].set(0, 0);
+    } else {
+        return false;
+    }
+    // compute the BottomRight corner radius
+    if (rightEqual && bottomEqual) {
+        radii[2].set(cornerRadius.x, cornerRadius.y);
+    } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) ||
+               (bottomEqual && bounds.fRight <= insetCrop.fRight)) {
+        radii[2].set(0, 0);
+    } else {
+        return false;
+    }
+    // compute the BottomLeft corner radius
+    if (leftEqual && bottomEqual) {
+        radii[3].set(cornerRadius.x, cornerRadius.y);
+    } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) ||
+               (bottomEqual && bounds.fLeft >= insetCrop.fLeft)) {
+        radii[3].set(0, 0);
+    } else {
+        return false;
+    }
+
+    return true;
+}
+
+static inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const android::FloatRect& boundsRect,
+                                                           const android::FloatRect& cropRect,
+                                                           const android::vec2& cornerRadius) {
+    const SkRect bounds = getSkRect(boundsRect);
+    const SkRect crop = getSkRect(cropRect);
+
+    SkRRect clip;
+    if (cornerRadius.x > 0 && cornerRadius.y > 0) {
+        // it the crop and the bounds are equivalent or there is no crop then we don't need a clip
+        if (bounds == crop || crop.isEmpty()) {
+            return {SkRRect::MakeRectXY(bounds, cornerRadius.x, cornerRadius.y), clip};
+        }
+
+        // This makes an effort to speed up common, simple bounds + clip combinations by
+        // converting them to a single RRect draw. It is possible there are other cases
+        // that can be converted.
+        if (crop.contains(bounds)) {
+            const auto insetCrop = crop.makeInset(cornerRadius.x, cornerRadius.y);
+            if (insetCrop.contains(bounds)) {
+                return {SkRRect::MakeRect(bounds), clip}; // clip is empty - no rounding required
+            }
+
+            SkVector radii[4];
+            if (intersectionIsRoundRect(bounds, crop, insetCrop, cornerRadius, radii)) {
+                SkRRect intersectionBounds;
+                intersectionBounds.setRectRadii(bounds, radii);
+                return {intersectionBounds, clip};
+            }
+        }
+
+        // we didn't hit any of our fast paths so set the clip to the cropRect
+        clip.setRectXY(crop, cornerRadius.x, cornerRadius.y);
+    }
+
+    // if we hit this point then we either don't have rounded corners or we are going to rely
+    // on the clip to round the corners for us
+    return {SkRRect::MakeRect(bounds), clip};
+}
+
+static inline bool layerHasBlur(const android::renderengine::LayerSettings& layer,
+                                bool colorTransformModifiesAlpha) {
+    if (layer.backgroundBlurRadius > 0 || layer.blurRegions.size()) {
+        // return false if the content is opaque and would therefore occlude the blur
+        const bool opaqueContent = !layer.source.buffer.buffer || layer.source.buffer.isOpaque;
+        const bool opaqueAlpha = layer.alpha == 1.0f && !colorTransformModifiesAlpha;
+        return layer.skipContentDraw || !(opaqueContent && opaqueAlpha);
+    }
+    return false;
+}
+
+static inline SkColor getSkColor(const android::vec4& color) {
+    return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255);
+}
+
+static inline SkM44 getSkM44(const android::mat4& matrix) {
+    return SkM44(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],
+                 matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],
+                 matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2],
+                 matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);
+}
+
+static inline SkPoint3 getSkPoint3(const android::vec3& vector) {
+    return SkPoint3::Make(vector.x, vector.y, vector.z);
+}
+
+} // namespace
 
 namespace android {
 namespace renderengine {
 namespace skia {
-SkiaRenderEngine::SkiaRenderEngine(RenderEngineType type) : RenderEngine(type) {}
+
+using base::StringAppendF;
+
+std::future<void> SkiaRenderEngine::primeCache() {
+    Cache::primeShaderCache(this);
+    return {};
+}
+
+sk_sp<SkData> SkiaRenderEngine::SkSLCacheMonitor::load(const SkData& key) {
+    // This "cache" does not actually cache anything. It just allows us to
+    // monitor Skia's internal cache. So this method always returns null.
+    return nullptr;
+}
+
+void SkiaRenderEngine::SkSLCacheMonitor::store(const SkData& key, const SkData& data,
+                                               const SkString& description) {
+    mShadersCachedSinceLastCall++;
+    mTotalShadersCompiled++;
+    ATRACE_FORMAT("SF cache: %i shaders", mTotalShadersCompiled);
+}
+
+int SkiaRenderEngine::reportShadersCompiled() {
+    return mSkSLCacheMonitor.totalShadersCompiled();
+}
 
 void SkiaRenderEngine::setEnableTracing(bool tracingEnabled) {
     SkAndroidFrameworkTraceUtil::setEnableTracing(tracingEnabled);
 }
+
+SkiaRenderEngine::SkiaRenderEngine(
+    RenderEngineType type,
+    PixelFormat pixelFormat,
+    bool useColorManagement,
+    bool supportsBackgroundBlur) :
+    RenderEngine(type),
+    mDefaultPixelFormat(pixelFormat),
+    mUseColorManagement(useColorManagement) {
+    if (supportsBackgroundBlur) {
+        ALOGD("Background Blurs Enabled");
+        mBlurFilter = new KawaseBlurFilter();
+    }
+    mCapture = std::make_unique<SkiaCapture>();
+}
+
+SkiaRenderEngine::~SkiaRenderEngine() { }
+
+// To be called from backend dtors.
+void SkiaRenderEngine::finishRenderingAndAbandonContext() {
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+
+    if (mBlurFilter) {
+        delete mBlurFilter;
+    }
+
+    if (mGrContext) {
+        mGrContext->flushAndSubmit(true);
+        mGrContext->abandonContext();
+    }
+
+    if (mProtectedGrContext) {
+        mProtectedGrContext->flushAndSubmit(true);
+        mProtectedGrContext->abandonContext();
+    }
+}
+
+void SkiaRenderEngine::useProtectedContext(bool useProtectedContext) {
+    if (useProtectedContext == mInProtectedContext ||
+        (useProtectedContext && !supportsProtectedContent())) {
+        return;
+    }
+
+    // release any scratch resources before switching into a new mode
+    if (getActiveGrContext()) {
+        getActiveGrContext()->purgeUnlockedResources(true);
+    }
+
+    // Backend-specific way to switch to protected context
+    if (useProtectedContextImpl(
+            useProtectedContext ? GrProtected::kYes : GrProtected::kNo)) {
+        mInProtectedContext = useProtectedContext;
+        // given that we are sharing the same thread between two GrContexts we need to
+        // make sure that the thread state is reset when switching between the two.
+        if (getActiveGrContext()) {
+            getActiveGrContext()->resetContext();
+        }
+    }
+}
+
+GrDirectContext* SkiaRenderEngine::getActiveGrContext() {
+    return mInProtectedContext ? mProtectedGrContext.get() : mGrContext.get();
+}
+
+static float toDegrees(uint32_t transform) {
+    switch (transform) {
+        case ui::Transform::ROT_90:
+            return 90.0;
+        case ui::Transform::ROT_180:
+            return 180.0;
+        case ui::Transform::ROT_270:
+            return 270.0;
+        default:
+            return 0.0;
+    }
+}
+
+static SkColorMatrix toSkColorMatrix(const android::mat4& matrix) {
+    return SkColorMatrix(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0], 0, matrix[0][1],
+                         matrix[1][1], matrix[2][1], matrix[3][1], 0, matrix[0][2], matrix[1][2],
+                         matrix[2][2], matrix[3][2], 0, matrix[0][3], matrix[1][3], matrix[2][3],
+                         matrix[3][3], 0);
+}
+
+static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destinationDataspace) {
+    int64_t sourceTransfer = sourceDataspace & HAL_DATASPACE_TRANSFER_MASK;
+    int64_t destTransfer = destinationDataspace & HAL_DATASPACE_TRANSFER_MASK;
+
+    // Treat unsupported dataspaces as srgb
+    if (destTransfer != HAL_DATASPACE_TRANSFER_LINEAR &&
+        destTransfer != HAL_DATASPACE_TRANSFER_HLG &&
+        destTransfer != HAL_DATASPACE_TRANSFER_ST2084) {
+        destTransfer = HAL_DATASPACE_TRANSFER_SRGB;
+    }
+
+    if (sourceTransfer != HAL_DATASPACE_TRANSFER_LINEAR &&
+        sourceTransfer != HAL_DATASPACE_TRANSFER_HLG &&
+        sourceTransfer != HAL_DATASPACE_TRANSFER_ST2084) {
+        sourceTransfer = HAL_DATASPACE_TRANSFER_SRGB;
+    }
+
+    const bool isSourceLinear = sourceTransfer == HAL_DATASPACE_TRANSFER_LINEAR;
+    const bool isSourceSRGB = sourceTransfer == HAL_DATASPACE_TRANSFER_SRGB;
+    const bool isDestLinear = destTransfer == HAL_DATASPACE_TRANSFER_LINEAR;
+    const bool isDestSRGB = destTransfer == HAL_DATASPACE_TRANSFER_SRGB;
+
+    return !(isSourceLinear && isDestSRGB) && !(isSourceSRGB && isDestLinear) &&
+            sourceTransfer != destTransfer;
+}
+
+void SkiaRenderEngine::ensureGrContextsCreated() {
+    if (mGrContext) {
+        return;
+    }
+
+    GrContextOptions options;
+    options.fDisableDriverCorrectnessWorkarounds = true;
+    options.fDisableDistanceFieldPaths = true;
+    options.fReducedShaderVariations = true;
+    options.fPersistentCache = &mSkSLCacheMonitor;
+    std::tie(mGrContext, mProtectedGrContext) = createDirectContexts(options);
+}
+
+void SkiaRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
+                                                  bool isRenderable) {
+    // Only run this if RE is running on its own thread. This way the access to GL
+    // operations is guaranteed to be happening on the same thread.
+    if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED) {
+        return;
+    }
+    // We currently don't attempt to map a buffer if the buffer contains protected content
+    // because GPU resources for protected buffers is much more limited.
+    const bool isProtectedBuffer = buffer->getUsage() & GRALLOC_USAGE_PROTECTED;
+    if (isProtectedBuffer) {
+        return;
+    }
+    ATRACE_CALL();
+
+    // If we were to support caching protected buffers then we will need to switch the
+    // currently bound context if we are not already using the protected context (and subsequently
+    // switch back after the buffer is cached).  However, for non-protected content we can bind
+    // the texture in either GL context because they are initialized with the same share_context
+    // which allows the texture state to be shared between them.
+    auto grContext = getActiveGrContext();
+    auto& cache = mTextureCache;
+
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    mGraphicBufferExternalRefs[buffer->getId()]++;
+
+    if (const auto& iter = cache.find(buffer->getId()); iter == cache.end()) {
+        std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef =
+                std::make_shared<AutoBackendTexture::LocalRef>(grContext,
+                                                               buffer->toAHardwareBuffer(),
+                                                               isRenderable, mTextureCleanupMgr);
+        cache.insert({buffer->getId(), imageTextureRef});
+    }
+}
+
+void SkiaRenderEngine::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    if (const auto& iter = mGraphicBufferExternalRefs.find(buffer->getId());
+        iter != mGraphicBufferExternalRefs.end()) {
+        if (iter->second == 0) {
+            ALOGW("Attempted to unmap GraphicBuffer <id: %" PRId64
+                  "> from RenderEngine texture, but the "
+                  "ref count was already zero!",
+                  buffer->getId());
+            mGraphicBufferExternalRefs.erase(buffer->getId());
+            return;
+        }
+
+        iter->second--;
+
+        // Swap contexts if needed prior to deleting this buffer
+        // See Issue 1 of
+        // https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_protected_content.txt: even
+        // when a protected context and an unprotected context are part of the same share group,
+        // protected surfaces may not be accessed by an unprotected context, implying that protected
+        // surfaces may only be freed when a protected context is active.
+        const bool inProtected = mInProtectedContext;
+        useProtectedContext(buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+
+        if (iter->second == 0) {
+            mTextureCache.erase(buffer->getId());
+            mGraphicBufferExternalRefs.erase(buffer->getId());
+        }
+
+        // Swap back to the previous context so that cached values of isProtected in SurfaceFlinger
+        // are up-to-date.
+        if (inProtected != mInProtectedContext) {
+            useProtectedContext(inProtected);
+        }
+    }
+}
+
+bool SkiaRenderEngine::canSkipPostRenderCleanup() const {
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    return mTextureCleanupMgr.isEmpty();
+}
+
+void SkiaRenderEngine::cleanupPostRender() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    mTextureCleanupMgr.cleanup();
+}
+
+sk_sp<SkShader> SkiaRenderEngine::createRuntimeEffectShader(
+        const RuntimeEffectShaderParameters& parameters) {
+    // The given surface will be stretched by HWUI via matrix transformation
+    // which gets similar results for most surfaces
+    // Determine later on if we need to leverage the stertch shader within
+    // surface flinger
+    const auto& stretchEffect = parameters.layer.stretchEffect;
+    auto shader = parameters.shader;
+    if (stretchEffect.hasEffect()) {
+        const auto targetBuffer = parameters.layer.source.buffer.buffer;
+        const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
+        if (graphicBuffer && parameters.shader) {
+            shader = mStretchShaderFactory.createSkShader(shader, stretchEffect);
+        }
+    }
+
+    if (parameters.requiresLinearEffect) {
+        const ui::Dataspace inputDataspace = mUseColorManagement ? parameters.layer.sourceDataspace
+                                                                 : ui::Dataspace::V0_SRGB_LINEAR;
+        const ui::Dataspace outputDataspace = mUseColorManagement
+                ? parameters.display.outputDataspace
+                : ui::Dataspace::V0_SRGB_LINEAR;
+
+        auto effect =
+                shaders::LinearEffect{.inputDataspace = inputDataspace,
+                                      .outputDataspace = outputDataspace,
+                                      .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha};
+
+        auto effectIter = mRuntimeEffects.find(effect);
+        sk_sp<SkRuntimeEffect> runtimeEffect = nullptr;
+        if (effectIter == mRuntimeEffects.end()) {
+            runtimeEffect = buildRuntimeEffect(effect);
+            mRuntimeEffects.insert({effect, runtimeEffect});
+        } else {
+            runtimeEffect = effectIter->second;
+        }
+        mat4 colorTransform = parameters.layer.colorTransform;
+
+        colorTransform *=
+                mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio,
+                                 parameters.layerDimmingRatio, 1.f));
+        const auto targetBuffer = parameters.layer.source.buffer.buffer;
+        const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
+        const auto hardwareBuffer = graphicBuffer ? graphicBuffer->toAHardwareBuffer() : nullptr;
+        return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform,
+                                        parameters.display.maxLuminance,
+                                        parameters.display.currentLuminanceNits,
+                                        parameters.layer.source.buffer.maxLuminanceNits,
+                                        hardwareBuffer, parameters.display.renderIntent);
+    }
+    return parameters.shader;
+}
+
+void SkiaRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
+    if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+        // Record display settings when capture is running.
+        std::stringstream displaySettings;
+        PrintTo(display, &displaySettings);
+        // Store the DisplaySettings in additional information.
+        canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings",
+                               SkData::MakeWithCString(displaySettings.str().c_str()));
+    }
+
+    // Before doing any drawing, let's make sure that we'll start at the origin of the display.
+    // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
+    // displays might have different scaling when compared to the physical screen.
+
+    canvas->clipRect(getSkRect(display.physicalDisplay));
+    canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
+
+    const auto clipWidth = display.clip.width();
+    const auto clipHeight = display.clip.height();
+    auto rotatedClipWidth = clipWidth;
+    auto rotatedClipHeight = clipHeight;
+    // Scale is contingent on the rotation result.
+    if (display.orientation & ui::Transform::ROT_90) {
+        std::swap(rotatedClipWidth, rotatedClipHeight);
+    }
+    const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
+            static_cast<SkScalar>(rotatedClipWidth);
+    const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
+            static_cast<SkScalar>(rotatedClipHeight);
+    canvas->scale(scaleX, scaleY);
+
+    // Canvas rotation is done by centering the clip window at the origin, rotating, translating
+    // back so that the top left corner of the clip is at (0, 0).
+    canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
+    canvas->rotate(toDegrees(display.orientation));
+    canvas->translate(-clipWidth / 2, -clipHeight / 2);
+    canvas->translate(-display.clip.left, -display.clip.top);
+}
+
+class AutoSaveRestore {
+public:
+    AutoSaveRestore(SkCanvas* canvas) : mCanvas(canvas) { mSaveCount = canvas->save(); }
+    ~AutoSaveRestore() { restore(); }
+    void replace(SkCanvas* canvas) {
+        mCanvas = canvas;
+        mSaveCount = canvas->save();
+    }
+    void restore() {
+        if (mCanvas) {
+            mCanvas->restoreToCount(mSaveCount);
+            mCanvas = nullptr;
+        }
+    }
+
+private:
+    SkCanvas* mCanvas;
+    int mSaveCount;
+};
+
+static SkRRect getBlurRRect(const BlurRegion& region) {
+    const auto rect = SkRect::MakeLTRB(region.left, region.top, region.right, region.bottom);
+    const SkVector radii[4] = {SkVector::Make(region.cornerRadiusTL, region.cornerRadiusTL),
+                               SkVector::Make(region.cornerRadiusTR, region.cornerRadiusTR),
+                               SkVector::Make(region.cornerRadiusBR, region.cornerRadiusBR),
+                               SkVector::Make(region.cornerRadiusBL, region.cornerRadiusBL)};
+    SkRRect roundedRect;
+    roundedRect.setRectRadii(rect, radii);
+    return roundedRect;
+}
+
+// Arbitrary default margin which should be close enough to zero.
+constexpr float kDefaultMargin = 0.0001f;
+static bool equalsWithinMargin(float expected, float value, float margin = kDefaultMargin) {
+    LOG_ALWAYS_FATAL_IF(margin < 0.f, "Margin is negative!");
+    return std::abs(expected - value) < margin;
+}
+
+namespace {
+template <typename T>
+void logSettings(const T& t) {
+    std::stringstream stream;
+    PrintTo(t, &stream);
+    auto string = stream.str();
+    size_t pos = 0;
+    // Perfetto ignores \n, so split up manually into separate ALOGD statements.
+    const size_t size = string.size();
+    while (pos < size) {
+        const size_t end = std::min(string.find("\n", pos), size);
+        ALOGD("%s", string.substr(pos, end - pos).c_str());
+        pos = end + 1;
+    }
+}
+} // namespace
+
+// Helper class intended to be used on the stack to ensure that texture cleanup
+// is deferred until after this class goes out of scope.
+class DeferTextureCleanup final {
+public:
+    DeferTextureCleanup(AutoBackendTexture::CleanupManager& mgr) : mMgr(mgr) {
+        mMgr.setDeferredStatus(true);
+    }
+    ~DeferTextureCleanup() { mMgr.setDeferredStatus(false); }
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(DeferTextureCleanup);
+    AutoBackendTexture::CleanupManager& mMgr;
+};
+
+void SkiaRenderEngine::drawLayersInternal(
+        const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+        const DisplaySettings& display, const std::vector<LayerSettings>& layers,
+        const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/,
+        base::unique_fd&& bufferFence) {
+    ATRACE_NAME("SkiaGL::drawLayersInternal");
+
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+
+    if (buffer == nullptr) {
+        ALOGE("No output buffer provided. Aborting GPU composition.");
+        resultPromise->set_value({BAD_VALUE, base::unique_fd()});
+        return;
+    }
+
+    validateOutputBufferUsage(buffer->getBuffer());
+
+    auto grContext = getActiveGrContext();
+    auto& cache = mTextureCache;
+
+    // any AutoBackendTexture deletions will now be deferred until cleanupPostRender is called
+    DeferTextureCleanup dtc(mTextureCleanupMgr);
+
+    std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef;
+    if (const auto& it = cache.find(buffer->getBuffer()->getId()); it != cache.end()) {
+        surfaceTextureRef = it->second;
+    } else {
+        surfaceTextureRef =
+                std::make_shared<AutoBackendTexture::LocalRef>(grContext,
+                                                               buffer->getBuffer()
+                                                                       ->toAHardwareBuffer(),
+                                                               true, mTextureCleanupMgr);
+    }
+
+    // wait on the buffer to be ready to use prior to using it
+    waitFence(grContext, bufferFence);
+
+    const ui::Dataspace dstDataspace =
+            mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR;
+    sk_sp<SkSurface> dstSurface = surfaceTextureRef->getOrCreateSurface(dstDataspace, grContext);
+
+    SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get());
+    if (dstCanvas == nullptr) {
+        ALOGE("Cannot acquire canvas from Skia.");
+        resultPromise->set_value({BAD_VALUE, base::unique_fd()});
+        return;
+    }
+
+    // setup color filter if necessary
+    sk_sp<SkColorFilter> displayColorTransform;
+    if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
+        displayColorTransform = SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform));
+    }
+    const bool ctModifiesAlpha =
+            displayColorTransform && !displayColorTransform->isAlphaUnchanged();
+
+    // Find the max layer white point to determine the max luminance of the scene...
+    const float maxLayerWhitePoint = std::transform_reduce(
+            layers.cbegin(), layers.cend(), 0.f,
+            [](float left, float right) { return std::max(left, right); },
+            [&](const auto& l) { return l.whitePointNits; });
+
+    // ...and compute the dimming ratio if dimming is requested
+    const float displayDimmingRatio = display.targetLuminanceNits > 0.f &&
+                    maxLayerWhitePoint > 0.f && display.targetLuminanceNits > maxLayerWhitePoint
+            ? maxLayerWhitePoint / display.targetLuminanceNits
+            : 1.f;
+
+    // Find if any layers have requested blur, we'll use that info to decide when to render to an
+    // offscreen buffer and when to render to the native buffer.
+    sk_sp<SkSurface> activeSurface(dstSurface);
+    SkCanvas* canvas = dstCanvas;
+    SkiaCapture::OffscreenState offscreenCaptureState;
+    const LayerSettings* blurCompositionLayer = nullptr;
+    if (mBlurFilter) {
+        bool requiresCompositionLayer = false;
+        for (const auto& layer : layers) {
+            // if the layer doesn't have blur or it is not visible then continue
+            if (!layerHasBlur(layer, ctModifiesAlpha)) {
+                continue;
+            }
+            if (layer.backgroundBlurRadius > 0 &&
+                layer.backgroundBlurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
+                requiresCompositionLayer = true;
+            }
+            for (auto region : layer.blurRegions) {
+                if (region.blurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
+                    requiresCompositionLayer = true;
+                }
+            }
+            if (requiresCompositionLayer) {
+                activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
+                canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState);
+                blurCompositionLayer = &layer;
+                break;
+            }
+        }
+    }
+
+    AutoSaveRestore surfaceAutoSaveRestore(canvas);
+    // Clear the entire canvas with a transparent black to prevent ghost images.
+    canvas->clear(SK_ColorTRANSPARENT);
+    initCanvas(canvas, display);
+
+    if (kPrintLayerSettings) {
+        logSettings(display);
+    }
+    for (const auto& layer : layers) {
+        ATRACE_FORMAT("DrawLayer: %s", layer.name.c_str());
+
+        if (kPrintLayerSettings) {
+            logSettings(layer);
+        }
+
+        sk_sp<SkImage> blurInput;
+        if (blurCompositionLayer == &layer) {
+            LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface);
+            LOG_ALWAYS_FATAL_IF(canvas == dstCanvas);
+
+            // save a snapshot of the activeSurface to use as input to the blur shaders
+            blurInput = activeSurface->makeImageSnapshot();
+
+            // blit the offscreen framebuffer into the destination AHB, but only
+            // if there are blur regions. backgroundBlurRadius blurs the entire
+            // image below, so it can skip this step.
+            if (layer.blurRegions.size()) {
+                SkPaint paint;
+                paint.setBlendMode(SkBlendMode::kSrc);
+                if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+                    uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState);
+                    dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()),
+                                              String8::format("SurfaceID|%" PRId64, id).c_str(),
+                                              nullptr);
+                    dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint);
+                } else {
+                    activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
+                }
+            }
+
+            // assign dstCanvas to canvas and ensure that the canvas state is up to date
+            canvas = dstCanvas;
+            surfaceAutoSaveRestore.replace(canvas);
+            initCanvas(canvas, display);
+
+            LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getSaveCount() !=
+                                dstSurface->getCanvas()->getSaveCount());
+            LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getTotalMatrix() !=
+                                dstSurface->getCanvas()->getTotalMatrix());
+
+            // assign dstSurface to activeSurface
+            activeSurface = dstSurface;
+        }
+
+        SkAutoCanvasRestore layerAutoSaveRestore(canvas, true);
+        if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+            // Record the name of the layer if the capture is running.
+            std::stringstream layerSettings;
+            PrintTo(layer, &layerSettings);
+            // Store the LayerSettings in additional information.
+            canvas->drawAnnotation(SkRect::MakeEmpty(), layer.name.c_str(),
+                                   SkData::MakeWithCString(layerSettings.str().c_str()));
+        }
+        // Layers have a local transform that should be applied to them
+        canvas->concat(getSkM44(layer.geometry.positionTransform).asM33());
+
+        const auto [bounds, roundRectClip] =
+                getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop,
+                                 layer.geometry.roundedCornersRadius);
+        if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) {
+            std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
+
+            // if multiple layers have blur, then we need to take a snapshot now because
+            // only the lowest layer will have blurImage populated earlier
+            if (!blurInput) {
+                blurInput = activeSurface->makeImageSnapshot();
+            }
+            // rect to be blurred in the coordinate space of blurInput
+            const auto blurRect = canvas->getTotalMatrix().mapRect(bounds.rect());
+
+            // if the clip needs to be applied then apply it now and make sure
+            // it is restored before we attempt to draw any shadows.
+            SkAutoCanvasRestore acr(canvas, true);
+            if (!roundRectClip.isEmpty()) {
+                canvas->clipRRect(roundRectClip, true);
+            }
+
+            // TODO(b/182216890): Filter out empty layers earlier
+            if (blurRect.width() > 0 && blurRect.height() > 0) {
+                if (layer.backgroundBlurRadius > 0) {
+                    ATRACE_NAME("BackgroundBlur");
+                    auto blurredImage = mBlurFilter->generate(grContext, layer.backgroundBlurRadius,
+                                                              blurInput, blurRect);
+
+                    cachedBlurs[layer.backgroundBlurRadius] = blurredImage;
+
+                    mBlurFilter->drawBlurRegion(canvas, bounds, layer.backgroundBlurRadius, 1.0f,
+                                                blurRect, blurredImage, blurInput);
+                }
+
+                canvas->concat(getSkM44(layer.blurRegionTransform).asM33());
+                for (auto region : layer.blurRegions) {
+                    if (cachedBlurs[region.blurRadius] == nullptr) {
+                        ATRACE_NAME("BlurRegion");
+                        cachedBlurs[region.blurRadius] =
+                                mBlurFilter->generate(grContext, region.blurRadius, blurInput,
+                                                      blurRect);
+                    }
+
+                    mBlurFilter->drawBlurRegion(canvas, getBlurRRect(region), region.blurRadius,
+                                                region.alpha, blurRect,
+                                                cachedBlurs[region.blurRadius], blurInput);
+                }
+            }
+        }
+
+        if (layer.shadow.length > 0) {
+            // This would require a new parameter/flag to SkShadowUtils::DrawShadow
+            LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow");
+
+            SkRRect shadowBounds, shadowClip;
+            if (layer.geometry.boundaries == layer.shadow.boundaries) {
+                shadowBounds = bounds;
+                shadowClip = roundRectClip;
+            } else {
+                std::tie(shadowBounds, shadowClip) =
+                        getBoundsAndClip(layer.shadow.boundaries, layer.geometry.roundedCornersCrop,
+                                         layer.geometry.roundedCornersRadius);
+            }
+
+            // Technically, if bounds is a rect and roundRectClip is not empty,
+            // it means that the bounds and roundedCornersCrop were different
+            // enough that we should intersect them to find the proper shadow.
+            // In practice, this often happens when the two rectangles appear to
+            // not match due to rounding errors. Draw the rounded version, which
+            // looks more like the intent.
+            const auto& rrect =
+                    shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds;
+            drawShadow(canvas, rrect, layer.shadow);
+        }
+
+        const float layerDimmingRatio = layer.whitePointNits <= 0.f
+                ? displayDimmingRatio
+                : (layer.whitePointNits / maxLayerWhitePoint) * displayDimmingRatio;
+
+        const bool dimInLinearSpace = display.dimmingStage !=
+                aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF;
+
+        const bool requiresLinearEffect = layer.colorTransform != mat4() ||
+                (mUseColorManagement &&
+                 needsToneMapping(layer.sourceDataspace, display.outputDataspace)) ||
+                (dimInLinearSpace && !equalsWithinMargin(1.f, layerDimmingRatio));
+
+        // quick abort from drawing the remaining portion of the layer
+        if (layer.skipContentDraw ||
+            (layer.alpha == 0 && !requiresLinearEffect && !layer.disableBlending &&
+             (!displayColorTransform || displayColorTransform->isAlphaUnchanged()))) {
+            continue;
+        }
+
+        // If we need to map to linear space or color management is disabled, then mark the source
+        // image with the same colorspace as the destination surface so that Skia's color
+        // management is a no-op.
+        const ui::Dataspace layerDataspace = (!mUseColorManagement || requiresLinearEffect)
+                ? dstDataspace
+                : layer.sourceDataspace;
+
+        SkPaint paint;
+        if (layer.source.buffer.buffer) {
+            ATRACE_NAME("DrawImage");
+            validateInputBufferUsage(layer.source.buffer.buffer->getBuffer());
+            const auto& item = layer.source.buffer;
+            std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr;
+
+            if (const auto& iter = cache.find(item.buffer->getBuffer()->getId());
+                iter != cache.end()) {
+                imageTextureRef = iter->second;
+            } else {
+                // If we didn't find the image in the cache, then create a local ref but don't cache
+                // it. If we're using skia, we're guaranteed to run on a dedicated GPU thread so if
+                // we didn't find anything in the cache then we intentionally did not cache this
+                // buffer's resources.
+                imageTextureRef = std::make_shared<
+                        AutoBackendTexture::LocalRef>(grContext,
+                                                      item.buffer->getBuffer()->toAHardwareBuffer(),
+                                                      false, mTextureCleanupMgr);
+            }
+
+            // if the layer's buffer has a fence, then we must must respect the fence prior to using
+            // the buffer.
+            if (layer.source.buffer.fence != nullptr) {
+                waitFence(grContext, layer.source.buffer.fence->get());
+            }
+
+            // isOpaque means we need to ignore the alpha in the image,
+            // replacing it with the alpha specified by the LayerSettings. See
+            // https://developer.android.com/reference/android/view/SurfaceControl.Builder#setOpaque(boolean)
+            // The proper way to do this is to use an SkColorType that ignores
+            // alpha, like kRGB_888x_SkColorType, and that is used if the
+            // incoming image is kRGBA_8888_SkColorType. However, the incoming
+            // image may be kRGBA_F16_SkColorType, for which there is no RGBX
+            // SkColorType, or kRGBA_1010102_SkColorType, for which we have
+            // kRGB_101010x_SkColorType, but it is not yet supported as a source
+            // on the GPU. (Adding both is tracked in skbug.com/12048.) In the
+            // meantime, we'll use a workaround that works unless we need to do
+            // any color conversion. The workaround requires that we pretend the
+            // image is already premultiplied, so that we do not premultiply it
+            // before applying SkBlendMode::kPlus.
+            const bool useIsOpaqueWorkaround = item.isOpaque &&
+                    (imageTextureRef->colorType() == kRGBA_1010102_SkColorType ||
+                     imageTextureRef->colorType() == kRGBA_F16_SkColorType);
+            const auto alphaType = useIsOpaqueWorkaround ? kPremul_SkAlphaType
+                    : item.isOpaque                      ? kOpaque_SkAlphaType
+                    : item.usePremultipliedAlpha         ? kPremul_SkAlphaType
+                                                         : kUnpremul_SkAlphaType;
+            sk_sp<SkImage> image = imageTextureRef->makeImage(layerDataspace, alphaType, grContext);
+
+            auto texMatrix = getSkM44(item.textureTransform).asM33();
+            // textureTansform was intended to be passed directly into a shader, so when
+            // building the total matrix with the textureTransform we need to first
+            // normalize it, then apply the textureTransform, then scale back up.
+            texMatrix.preScale(1.0f / bounds.width(), 1.0f / bounds.height());
+            texMatrix.postScale(image->width(), image->height());
+
+            SkMatrix matrix;
+            if (!texMatrix.invert(&matrix)) {
+                matrix = texMatrix;
+            }
+            // The shader does not respect the translation, so we add it to the texture
+            // transform for the SkImage. This will make sure that the correct layer contents
+            // are drawn in the correct part of the screen.
+            matrix.postTranslate(bounds.rect().fLeft, bounds.rect().fTop);
+
+            sk_sp<SkShader> shader;
+
+            if (layer.source.buffer.useTextureFiltering) {
+                shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
+                                           SkSamplingOptions(
+                                                   {SkFilterMode::kLinear, SkMipmapMode::kNone}),
+                                           &matrix);
+            } else {
+                shader = image->makeShader(SkSamplingOptions(), matrix);
+            }
+
+            if (useIsOpaqueWorkaround) {
+                shader = SkShaders::Blend(SkBlendMode::kPlus, shader,
+                                          SkShaders::Color(SkColors::kBlack,
+                                                           toSkColorSpace(layerDataspace)));
+            }
+
+            paint.setShader(createRuntimeEffectShader(
+                    RuntimeEffectShaderParameters{.shader = shader,
+                                                  .layer = layer,
+                                                  .display = display,
+                                                  .undoPremultipliedAlpha = !item.isOpaque &&
+                                                          item.usePremultipliedAlpha,
+                                                  .requiresLinearEffect = requiresLinearEffect,
+                                                  .layerDimmingRatio = dimInLinearSpace
+                                                          ? layerDimmingRatio
+                                                          : 1.f}));
+
+            // Turn on dithering when dimming beyond this (arbitrary) threshold...
+            static constexpr float kDimmingThreshold = 0.2f;
+            // ...or we're rendering an HDR layer down to an 8-bit target
+            // Most HDR standards require at least 10-bits of color depth for source content, so we
+            // can just extract the transfer function rather than dig into precise gralloc layout.
+            // Furthermore, we can assume that the only 8-bit target we support is RGBA8888.
+            const bool requiresDownsample = isHdrDataspace(layer.sourceDataspace) &&
+                    buffer->getPixelFormat() == PIXEL_FORMAT_RGBA_8888;
+            if (layerDimmingRatio <= kDimmingThreshold || requiresDownsample) {
+                paint.setDither(true);
+            }
+            paint.setAlphaf(layer.alpha);
+
+            if (imageTextureRef->colorType() == kAlpha_8_SkColorType) {
+                LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with A8");
+
+                // SysUI creates the alpha layer as a coverage layer, which is
+                // appropriate for the DPU. Use a color matrix to convert it to
+                // a mask.
+                // TODO (b/219525258): Handle input as a mask.
+                //
+                // The color matrix will convert A8 pixels with no alpha to
+                // black, as described by this vector. If the display handles
+                // the color transform, we need to invert it to find the color
+                // that will result in black after the DPU applies the transform.
+                SkV4 black{0.0f, 0.0f, 0.0f, 1.0f}; // r, g, b, a
+                if (display.colorTransform != mat4() && display.deviceHandlesColorTransform) {
+                    SkM44 colorSpaceMatrix = getSkM44(display.colorTransform);
+                    if (colorSpaceMatrix.invert(&colorSpaceMatrix)) {
+                        black = colorSpaceMatrix * black;
+                    } else {
+                        // We'll just have to use 0,0,0 as black, which should
+                        // be close to correct.
+                        ALOGI("Could not invert colorTransform!");
+                    }
+                }
+                SkColorMatrix colorMatrix(0, 0, 0, 0, black[0],
+                                          0, 0, 0, 0, black[1],
+                                          0, 0, 0, 0, black[2],
+                                          0, 0, 0, -1, 1);
+                if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
+                    // On the other hand, if the device doesn't handle it, we
+                    // have to apply it ourselves.
+                    colorMatrix.postConcat(toSkColorMatrix(display.colorTransform));
+                }
+                paint.setColorFilter(SkColorFilters::Matrix(colorMatrix));
+            }
+        } else {
+            ATRACE_NAME("DrawColor");
+            const auto color = layer.source.solidColor;
+            sk_sp<SkShader> shader = SkShaders::Color(SkColor4f{.fR = color.r,
+                                                                .fG = color.g,
+                                                                .fB = color.b,
+                                                                .fA = layer.alpha},
+                                                      toSkColorSpace(layerDataspace));
+            paint.setShader(createRuntimeEffectShader(
+                    RuntimeEffectShaderParameters{.shader = shader,
+                                                  .layer = layer,
+                                                  .display = display,
+                                                  .undoPremultipliedAlpha = false,
+                                                  .requiresLinearEffect = requiresLinearEffect,
+                                                  .layerDimmingRatio = layerDimmingRatio}));
+        }
+
+        if (layer.disableBlending) {
+            paint.setBlendMode(SkBlendMode::kSrc);
+        }
+
+        // An A8 buffer will already have the proper color filter attached to
+        // its paint, including the displayColorTransform as needed.
+        if (!paint.getColorFilter()) {
+            if (!dimInLinearSpace && !equalsWithinMargin(1.0, layerDimmingRatio)) {
+                // If we don't dim in linear space, then when we gamma correct the dimming ratio we
+                // can assume a gamma 2.2 transfer function.
+                static constexpr float kInverseGamma22 = 1.f / 2.2f;
+                const auto gammaCorrectedDimmingRatio =
+                        std::pow(layerDimmingRatio, kInverseGamma22);
+                auto dimmingMatrix =
+                        mat4::scale(vec4(gammaCorrectedDimmingRatio, gammaCorrectedDimmingRatio,
+                                         gammaCorrectedDimmingRatio, 1.f));
+
+                const auto colorFilter =
+                        SkColorFilters::Matrix(toSkColorMatrix(std::move(dimmingMatrix)));
+                paint.setColorFilter(displayColorTransform
+                                             ? displayColorTransform->makeComposed(colorFilter)
+                                             : colorFilter);
+            } else {
+                paint.setColorFilter(displayColorTransform);
+            }
+        }
+
+        if (!roundRectClip.isEmpty()) {
+            canvas->clipRRect(roundRectClip, true);
+        }
+
+        if (!bounds.isRect()) {
+            paint.setAntiAlias(true);
+            canvas->drawRRect(bounds, paint);
+        } else {
+            canvas->drawRect(bounds.rect(), paint);
+        }
+        if (kFlushAfterEveryLayer) {
+            ATRACE_NAME("flush surface");
+            activeSurface->flush();
+        }
+    }
+    for (const auto& borderRenderInfo : display.borderInfoList) {
+        SkPaint p;
+        p.setColor(SkColor4f{borderRenderInfo.color.r, borderRenderInfo.color.g,
+                             borderRenderInfo.color.b, borderRenderInfo.color.a});
+        p.setAntiAlias(true);
+        p.setStyle(SkPaint::kStroke_Style);
+        p.setStrokeWidth(borderRenderInfo.width);
+        SkRegion sk_region;
+        SkPath path;
+
+        // Construct a final SkRegion using Regions
+        for (const auto& r : borderRenderInfo.combinedRegion) {
+            sk_region.op({r.left, r.top, r.right, r.bottom}, SkRegion::kUnion_Op);
+        }
+
+        sk_region.getBoundaryPath(&path);
+        canvas->drawPath(path, p);
+        path.close();
+    }
+
+    surfaceAutoSaveRestore.restore();
+    mCapture->endCapture();
+    {
+        ATRACE_NAME("flush surface");
+        LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface);
+        activeSurface->flush();
+    }
+
+    base::unique_fd drawFence = flushAndSubmit(grContext);
+    resultPromise->set_value({NO_ERROR, std::move(drawFence)});
+    return;
+}
+
+size_t SkiaRenderEngine::getMaxTextureSize() const {
+    return mGrContext->maxTextureSize();
+}
+
+size_t SkiaRenderEngine::getMaxViewportDims() const {
+    return mGrContext->maxRenderTargetSize();
+}
+
+void SkiaRenderEngine::drawShadow(SkCanvas* canvas,
+                                  const SkRRect& casterRRect,
+                                  const ShadowSettings& settings) {
+    ATRACE_CALL();
+    const float casterZ = settings.length / 2.0f;
+    const auto flags =
+            settings.casterIsTranslucent ? kTransparentOccluder_ShadowFlag : kNone_ShadowFlag;
+
+    SkShadowUtils::DrawShadow(canvas, SkPath::RRect(casterRRect), SkPoint3::Make(0, 0, casterZ),
+                              getSkPoint3(settings.lightPos), settings.lightRadius,
+                              getSkColor(settings.ambientColor), getSkColor(settings.spotColor),
+                              flags);
+}
+
+void SkiaRenderEngine::onActiveDisplaySizeChanged(ui::Size size) {
+    // This cache multiplier was selected based on review of cache sizes relative
+    // to the screen resolution. Looking at the worst case memory needed by blur (~1.5x),
+    // shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a
+    // conservative default based on that analysis.
+    const float SURFACE_SIZE_MULTIPLIER = 3.5f * bytesPerPixel(mDefaultPixelFormat);
+    const int maxResourceBytes = size.width * size.height * SURFACE_SIZE_MULTIPLIER;
+
+    // start by resizing the current context
+    getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
+
+    // if it is possible to switch contexts then we will resize the other context
+    const bool originalProtectedState = mInProtectedContext;
+    useProtectedContext(!mInProtectedContext);
+    if (mInProtectedContext != originalProtectedState) {
+        getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
+        // reset back to the initial context that was active when this method was called
+        useProtectedContext(originalProtectedState);
+    }
+}
+
+void SkiaRenderEngine::dump(std::string& result) {
+    // Dump for the specific backend (GLES or Vk)
+    appendBackendSpecificInfoToDump(result);
+
+    // Info about protected content
+    StringAppendF(&result, "RenderEngine supports protected context: %d\n",
+                  supportsProtectedContent());
+    StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext);
+    StringAppendF(&result, "RenderEngine shaders cached since last dump/primeCache: %d\n",
+                  mSkSLCacheMonitor.shadersCachedSinceLastCall());
+
+    std::vector<ResourcePair> cpuResourceMap = {
+            {"skia/sk_resource_cache/bitmap_", "Bitmaps"},
+            {"skia/sk_resource_cache/rrect-blur_", "Masks"},
+            {"skia/sk_resource_cache/rects-blur_", "Masks"},
+            {"skia/sk_resource_cache/tessellated", "Shadows"},
+            {"skia", "Other"},
+    };
+    SkiaMemoryReporter cpuReporter(cpuResourceMap, false);
+    SkGraphics::DumpMemoryStatistics(&cpuReporter);
+    StringAppendF(&result, "Skia CPU Caches: ");
+    cpuReporter.logTotals(result);
+    cpuReporter.logOutput(result);
+
+    {
+        std::lock_guard<std::mutex> lock(mRenderingMutex);
+
+        std::vector<ResourcePair> gpuResourceMap = {
+                {"texture_renderbuffer", "Texture/RenderBuffer"},
+                {"texture", "Texture"},
+                {"gr_text_blob_cache", "Text"},
+                {"skia", "Other"},
+        };
+        SkiaMemoryReporter gpuReporter(gpuResourceMap, true);
+        mGrContext->dumpMemoryStatistics(&gpuReporter);
+        StringAppendF(&result, "Skia's GPU Caches: ");
+        gpuReporter.logTotals(result);
+        gpuReporter.logOutput(result);
+        StringAppendF(&result, "Skia's Wrapped Objects:\n");
+        gpuReporter.logOutput(result, true);
+
+        StringAppendF(&result, "RenderEngine tracked buffers: %zu\n",
+                      mGraphicBufferExternalRefs.size());
+        StringAppendF(&result, "Dumping buffer ids...\n");
+        for (const auto& [id, refCounts] : mGraphicBufferExternalRefs) {
+            StringAppendF(&result, "- 0x%" PRIx64 " - %d refs \n", id, refCounts);
+        }
+        StringAppendF(&result, "RenderEngine AHB/BackendTexture cache size: %zu\n",
+                      mTextureCache.size());
+        StringAppendF(&result, "Dumping buffer ids...\n");
+        // TODO(178539829): It would be nice to know which layer these are coming from and what
+        // the texture sizes are.
+        for (const auto& [id, unused] : mTextureCache) {
+            StringAppendF(&result, "- 0x%" PRIx64 "\n", id);
+        }
+        StringAppendF(&result, "\n");
+
+        SkiaMemoryReporter gpuProtectedReporter(gpuResourceMap, true);
+        if (mProtectedGrContext) {
+            mProtectedGrContext->dumpMemoryStatistics(&gpuProtectedReporter);
+        }
+        StringAppendF(&result, "Skia's GPU Protected Caches: ");
+        gpuProtectedReporter.logTotals(result);
+        gpuProtectedReporter.logOutput(result);
+        StringAppendF(&result, "Skia's Protected Wrapped Objects:\n");
+        gpuProtectedReporter.logOutput(result, true);
+
+        StringAppendF(&result, "\n");
+        StringAppendF(&result, "RenderEngine runtime effects: %zu\n", mRuntimeEffects.size());
+        for (const auto& [linearEffect, unused] : mRuntimeEffects) {
+            StringAppendF(&result, "- inputDataspace: %s\n",
+                          dataspaceDetails(
+                                  static_cast<android_dataspace>(linearEffect.inputDataspace))
+                                  .c_str());
+            StringAppendF(&result, "- outputDataspace: %s\n",
+                          dataspaceDetails(
+                                  static_cast<android_dataspace>(linearEffect.outputDataspace))
+                                  .c_str());
+            StringAppendF(&result, "undoPremultipliedAlpha: %s\n",
+                          linearEffect.undoPremultipliedAlpha ? "true" : "false");
+        }
+    }
+    StringAppendF(&result, "\n");
+}
+
 } // namespace skia
 } // namespace renderengine
 } // namespace android
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index 5d10b6f..a5cd278 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -20,6 +20,31 @@
 #include <renderengine/RenderEngine.h>
 #include <sys/types.h>
 
+#include <GrBackendSemaphore.h>
+#include <GrDirectContext.h>
+#include <SkSurface.h>
+#include <android-base/thread_annotations.h>
+#include <renderengine/ExternalTexture.h>
+#include <renderengine/RenderEngine.h>
+#include <sys/types.h>
+
+#include <mutex>
+#include <unordered_map>
+
+#include "AutoBackendTexture.h"
+#include "GrContextOptions.h"
+#include "SkImageInfo.h"
+#include "SkiaRenderEngine.h"
+#include "android-base/macros.h"
+#include "debug/SkiaCapture.h"
+#include "filters/BlurFilter.h"
+#include "filters/LinearEffect.h"
+#include "filters/StretchShaderFactory.h"
+
+class SkData;
+
+struct SkPoint3;
+
 namespace android {
 
 namespace renderengine {
@@ -31,36 +56,141 @@
 
 class BlurFilter;
 
-// TODO: Put common skia stuff here that can be shared between the GL & Vulkan backends
-// Currently mostly just handles all the no-op / missing APIs
 class SkiaRenderEngine : public RenderEngine {
 public:
     static std::unique_ptr<SkiaRenderEngine> create(const RenderEngineCreationArgs& args);
-    SkiaRenderEngine(RenderEngineType type);
-    ~SkiaRenderEngine() override {}
+    SkiaRenderEngine(RenderEngineType type,
+                     PixelFormat pixelFormat,
+                     bool useColorManagement,
+                     bool supportsBackgroundBlur);
+    ~SkiaRenderEngine() override;
 
-    virtual std::future<void> primeCache() override { return {}; };
-    virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override{};
-    virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{};
-    virtual bool isProtected() const override { return false; } // mInProtectedContext; }
-    virtual bool supportsProtectedContent() const override { return false; };
-    virtual int getContextPriority() override { return 0; }
-    virtual void assertShadersCompiled(int numShaders) {}
-    virtual int reportShadersCompiled() { return 0; }
-    virtual void setEnableTracing(bool tracingEnabled) override;
+    std::future<void> primeCache() override final;
+    void cleanupPostRender() override final;
+    void cleanFramebufferCache() override final{ }
+    bool isProtected() const override final{ return mInProtectedContext; }
+    bool supportsBackgroundBlur() override final {
+        return mBlurFilter != nullptr;
+    }
+    void onActiveDisplaySizeChanged(ui::Size size) override final;
+    int reportShadersCompiled();
 
+    virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override final{};
+    virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override final{};
+    virtual void setEnableTracing(bool tracingEnabled) override final;
+
+    void useProtectedContext(bool useProtectedContext) override;
+    bool supportsProtectedContent() const override {
+        return supportsProtectedContentImpl();
+    }
+    void ensureGrContextsCreated();
 protected:
-    virtual void mapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/,
-                                          bool /*isRenderable*/) override = 0;
-    virtual void unmapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/) override = 0;
+    // This is so backends can stop the generic rendering state first before
+    // cleaning up backend-specific state
+    void finishRenderingAndAbandonContext();
 
-    virtual void drawLayersInternal(
-            const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
-            const DisplaySettings& display, const std::vector<LayerSettings>& layers,
-            const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
-            base::unique_fd&& bufferFence) override {
-        resultPromise->set_value({NO_ERROR, base::unique_fd()});
+    // Functions that a given backend (GLES, Vulkan) must implement
+    using Contexts = std::pair<sk_sp<GrDirectContext>, sk_sp<GrDirectContext>>;
+    virtual Contexts createDirectContexts(const GrContextOptions& options) = 0;
+    virtual bool supportsProtectedContentImpl() const = 0;
+    virtual bool useProtectedContextImpl(GrProtected isProtected) = 0;
+    virtual void waitFence(GrDirectContext* grContext, base::borrowed_fd fenceFd) = 0;
+    virtual base::unique_fd flushAndSubmit(GrDirectContext* context) = 0;
+    virtual void appendBackendSpecificInfoToDump(std::string& result) = 0;
+
+    size_t getMaxTextureSize() const override final;
+    size_t getMaxViewportDims() const override final;
+    GrDirectContext* getActiveGrContext();
+
+    // Implements PersistentCache as a way to monitor what SkSL shaders Skia has
+    // cached.
+    class SkSLCacheMonitor : public GrContextOptions::PersistentCache {
+    public:
+        SkSLCacheMonitor() = default;
+        ~SkSLCacheMonitor() override = default;
+
+        sk_sp<SkData> load(const SkData& key) override;
+
+        void store(const SkData& key, const SkData& data, const SkString& description) override;
+
+        int shadersCachedSinceLastCall() {
+            const int shadersCachedSinceLastCall = mShadersCachedSinceLastCall;
+            mShadersCachedSinceLastCall = 0;
+            return shadersCachedSinceLastCall;
+        }
+
+        int totalShadersCompiled() const { return mTotalShadersCompiled; }
+
+    private:
+        int mShadersCachedSinceLastCall = 0;
+        int mTotalShadersCompiled = 0;
     };
+
+private:
+    void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
+                                  bool isRenderable) override final;
+    void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override final;
+    bool canSkipPostRenderCleanup() const override final;
+
+    void initCanvas(SkCanvas* canvas, const DisplaySettings& display);
+    void drawShadow(SkCanvas* canvas, const SkRRect& casterRRect,
+                    const ShadowSettings& shadowSettings);
+    void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+                            const DisplaySettings& display,
+                            const std::vector<LayerSettings>& layers,
+                            const std::shared_ptr<ExternalTexture>& buffer,
+                            const bool useFramebufferCache,
+                            base::unique_fd&& bufferFence) override final;
+
+    void dump(std::string& result) override final;
+
+    // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned.
+    // Otherwise it returns the input shader.
+    struct RuntimeEffectShaderParameters {
+        sk_sp<SkShader> shader;
+        const LayerSettings& layer;
+        const DisplaySettings& display;
+        bool undoPremultipliedAlpha;
+        bool requiresLinearEffect;
+        float layerDimmingRatio;
+    };
+    sk_sp<SkShader> createRuntimeEffectShader(const RuntimeEffectShaderParameters&);
+
+    const PixelFormat mDefaultPixelFormat;
+    const bool mUseColorManagement;
+
+    // Identifier used for various mappings of layers to various
+    // textures or shaders
+    using GraphicBufferId = uint64_t;
+
+    // Number of external holders of ExternalTexture references, per GraphicBuffer ID.
+    std::unordered_map<GraphicBufferId, int32_t> mGraphicBufferExternalRefs
+            GUARDED_BY(mRenderingMutex);
+    // Cache of GL textures that we'll store per GraphicBuffer ID, shared between GPU contexts.
+    std::unordered_map<GraphicBufferId, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache
+            GUARDED_BY(mRenderingMutex);
+    std::unordered_map<shaders::LinearEffect, sk_sp<SkRuntimeEffect>, shaders::LinearEffectHasher>
+            mRuntimeEffects;
+    AutoBackendTexture::CleanupManager mTextureCleanupMgr GUARDED_BY(mRenderingMutex);
+
+    StretchShaderFactory mStretchShaderFactory;
+
+    sp<Fence> mLastDrawFence;
+    BlurFilter* mBlurFilter = nullptr;
+
+    // Object to capture commands send to Skia.
+    std::unique_ptr<SkiaCapture> mCapture;
+
+    // Mutex guarding rendering operations, so that internal state related to
+    // rendering that is potentially modified by multiple threads is guaranteed thread-safe.
+    mutable std::mutex mRenderingMutex;
+    SkSLCacheMonitor mSkSLCacheMonitor;
+
+    // Graphics context used for creating surfaces and submitting commands
+    sk_sp<GrDirectContext> mGrContext;
+    // Same as above, but for protected content (eg. DRM)
+    sk_sp<GrDirectContext> mProtectedGrContext;
+    bool mInProtectedContext = false;
 };
 
 } // namespace skia
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index e66fee1..bbab792 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -29,6 +29,8 @@
     ],
     test_suites: ["device-tests"],
     srcs: [
+        "DisplaySettingsTest.cpp",
+        "LayerSettingsTest.cpp",
         "RenderEngineTest.cpp",
         "RenderEngineThreadedTest.cpp",
     ],
diff --git a/libs/renderengine/tests/DisplaySettingsTest.cpp b/libs/renderengine/tests/DisplaySettingsTest.cpp
new file mode 100644
index 0000000..0e93c88
--- /dev/null
+++ b/libs/renderengine/tests/DisplaySettingsTest.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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 "DisplaySettingsTest"
+
+#include <gtest/gtest.h>
+#include <renderengine/DisplaySettings.h>
+
+namespace android::renderengine {
+
+TEST(DisplaySettingsTest, currentLuminanceNits) {
+    DisplaySettings a, b;
+    ASSERT_EQ(a, b);
+
+    a.currentLuminanceNits = 45.f;
+
+    ASSERT_FALSE(a == b);
+}
+
+TEST(DisplaySettingsTest, targetLuminanceNits) {
+    DisplaySettings a, b;
+    ASSERT_EQ(a, b);
+
+    a.targetLuminanceNits = 45.f;
+
+    ASSERT_FALSE(a == b);
+}
+
+TEST(DisplaySettingsTest, deviceHandlesColorTransform) {
+    DisplaySettings a, b;
+    ASSERT_EQ(a, b);
+
+    a.deviceHandlesColorTransform = true;
+
+    ASSERT_FALSE(a == b);
+}
+
+TEST(DisplaySettingsTest, dimmingStage) {
+    DisplaySettings a, b;
+    ASSERT_EQ(a, b);
+
+    a.dimmingStage = aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF;
+
+    ASSERT_FALSE(a == b);
+}
+
+TEST(DisplaySettingsTest, renderIntent) {
+    DisplaySettings a, b;
+    ASSERT_EQ(a, b);
+
+    a.renderIntent = aidl::android::hardware::graphics::composer3::RenderIntent::TONE_MAP_ENHANCE;
+
+    ASSERT_FALSE(a == b);
+}
+} // namespace android::renderengine
diff --git a/libs/renderengine/tests/LayerSettingsTest.cpp b/libs/renderengine/tests/LayerSettingsTest.cpp
new file mode 100644
index 0000000..4737335
--- /dev/null
+++ b/libs/renderengine/tests/LayerSettingsTest.cpp
@@ -0,0 +1,33 @@
+/*
+ * 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 "LayerSettingsTest"
+
+#include <gtest/gtest.h>
+#include <renderengine/LayerSettings.h>
+
+namespace android::renderengine {
+
+TEST(LayerSettingsTest, whitePointNits) {
+    LayerSettings a, b;
+    ASSERT_EQ(a, b);
+
+    a.whitePointNits = 45.f;
+
+    ASSERT_FALSE(a == b);
+}
+} // namespace android::renderengine
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 2493242..d23063c 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -91,6 +91,14 @@
                 sign(linear.b) * OETF_sRGB(linear.b));
 }
 
+// clang-format off
+// Converts red channels to green channels, and zeroes out an existing green channel.
+static const auto kRemoveGreenAndMoveRedToGreenMat4 = mat4(0, 1, 0, 0,
+                                                           0, 0, 0, 0,
+                                                           0, 0, 1, 0,
+                                                           0, 0, 0, 1);
+// clang-format on
+
 } // namespace
 
 class RenderEngineFactory {
@@ -224,14 +232,14 @@
     std::shared_ptr<renderengine::ExternalTexture> allocateDefaultBuffer() {
         return std::make_shared<
                 renderengine::impl::
-                        ExternalTexture>(new GraphicBuffer(DEFAULT_DISPLAY_WIDTH,
-                                                           DEFAULT_DISPLAY_HEIGHT,
-                                                           HAL_PIXEL_FORMAT_RGBA_8888, 1,
-                                                           GRALLOC_USAGE_SW_READ_OFTEN |
-                                                                   GRALLOC_USAGE_SW_WRITE_OFTEN |
-                                                                   GRALLOC_USAGE_HW_RENDER |
-                                                                   GRALLOC_USAGE_HW_TEXTURE,
-                                                           "output"),
+                        ExternalTexture>(sp<GraphicBuffer>::
+                                                 make(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+                                                      HAL_PIXEL_FORMAT_RGBA_8888, 1,
+                                                      GRALLOC_USAGE_SW_READ_OFTEN |
+                                                              GRALLOC_USAGE_SW_WRITE_OFTEN |
+                                                              GRALLOC_USAGE_HW_RENDER |
+                                                              GRALLOC_USAGE_HW_TEXTURE,
+                                                      "output"),
                                          *mRE,
                                          renderengine::impl::ExternalTexture::Usage::READABLE |
                                                  renderengine::impl::ExternalTexture::Usage::
@@ -243,12 +251,12 @@
                                                                         uint32_t height) {
         return std::make_shared<
                 renderengine::impl::
-                        ExternalTexture>(new GraphicBuffer(width, height,
-                                                           HAL_PIXEL_FORMAT_RGBA_8888, 1,
-                                                           GRALLOC_USAGE_SW_READ_OFTEN |
-                                                                   GRALLOC_USAGE_SW_WRITE_OFTEN |
-                                                                   GRALLOC_USAGE_HW_TEXTURE,
-                                                           "input"),
+                        ExternalTexture>(sp<GraphicBuffer>::
+                                                 make(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1,
+                                                      GRALLOC_USAGE_SW_READ_OFTEN |
+                                                              GRALLOC_USAGE_SW_WRITE_OFTEN |
+                                                              GRALLOC_USAGE_HW_TEXTURE,
+                                                      "input"),
                                          *mRE,
                                          renderengine::impl::ExternalTexture::Usage::READABLE |
                                                  renderengine::impl::ExternalTexture::Usage::
@@ -277,10 +285,12 @@
     }
 
     std::shared_ptr<renderengine::ExternalTexture> allocateR8Buffer(int width, int height) {
-        auto buffer = new GraphicBuffer(width, height, android::PIXEL_FORMAT_R_8, 1,
-                                        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
-                                                GRALLOC_USAGE_HW_TEXTURE,
-                                        "r8");
+        const auto kUsageFlags =
+                static_cast<uint64_t>(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+                                      GRALLOC_USAGE_HW_TEXTURE);
+        auto buffer =
+                sp<GraphicBuffer>::make(static_cast<uint32_t>(width), static_cast<uint32_t>(height),
+                                        android::PIXEL_FORMAT_R_8, 1u, kUsageFlags, "r8");
         if (buffer->initCheck() != 0) {
             // Devices are not required to support R8.
             return nullptr;
@@ -436,7 +446,9 @@
                            const ubyte4& backgroundColor) {
         const Rect casterRect(castingLayer.geometry.boundaries);
         Region casterRegion = Region(casterRect);
-        const float casterCornerRadius = castingLayer.geometry.roundedCornersRadius;
+        const float casterCornerRadius = (castingLayer.geometry.roundedCornersRadius.x +
+                                          castingLayer.geometry.roundedCornersRadius.y) /
+                2.0;
         if (casterCornerRadius > 0.0f) {
             // ignore the corners if a corner radius is set
             Rect cornerRect(casterCornerRadius, casterCornerRadius);
@@ -1121,7 +1133,7 @@
     renderengine::LayerSettings layer;
     layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
     layer.geometry.boundaries = fullscreenRect().toFloatRect();
-    layer.geometry.roundedCornersRadius = 5.0f;
+    layer.geometry.roundedCornersRadius = {5.0f, 5.0f};
     layer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect();
     SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
     layer.alpha = 1.0f;
@@ -1486,13 +1498,13 @@
 
     auto buf = std::make_shared<
             renderengine::impl::
-                    ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                       1,
-                                                       GRALLOC_USAGE_SW_READ_OFTEN |
-                                                               GRALLOC_USAGE_SW_WRITE_OFTEN |
-                                                               GRALLOC_USAGE_HW_RENDER |
-                                                               GRALLOC_USAGE_HW_TEXTURE,
-                                                       "input"),
+                    ExternalTexture>(sp<GraphicBuffer>::make(kGreyLevels, 1,
+                                                             HAL_PIXEL_FORMAT_RGBA_8888, 1,
+                                                             GRALLOC_USAGE_SW_READ_OFTEN |
+                                                                     GRALLOC_USAGE_SW_WRITE_OFTEN |
+                                                                     GRALLOC_USAGE_HW_RENDER |
+                                                                     GRALLOC_USAGE_HW_TEXTURE,
+                                                             "input"),
                                      *mRE,
                                      renderengine::impl::ExternalTexture::Usage::READABLE |
                                              renderengine::impl::ExternalTexture::Usage::WRITEABLE);
@@ -1519,13 +1531,13 @@
 
     mBuffer = std::make_shared<
             renderengine::impl::
-                    ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                       1,
-                                                       GRALLOC_USAGE_SW_READ_OFTEN |
-                                                               GRALLOC_USAGE_SW_WRITE_OFTEN |
-                                                               GRALLOC_USAGE_HW_RENDER |
-                                                               GRALLOC_USAGE_HW_TEXTURE,
-                                                       "output"),
+                    ExternalTexture>(sp<GraphicBuffer>::make(kGreyLevels, 1,
+                                                             HAL_PIXEL_FORMAT_RGBA_8888, 1,
+                                                             GRALLOC_USAGE_SW_READ_OFTEN |
+                                                                     GRALLOC_USAGE_SW_WRITE_OFTEN |
+                                                                     GRALLOC_USAGE_HW_RENDER |
+                                                                     GRALLOC_USAGE_HW_TEXTURE,
+                                                             "output"),
                                      *mRE,
                                      renderengine::impl::ExternalTexture::Usage::READABLE |
                                              renderengine::impl::ExternalTexture::Usage::WRITEABLE);
@@ -1598,6 +1610,36 @@
     drawEmptyLayers();
 }
 
+TEST_P(RenderEngineTest, drawLayers_fillRedBufferAndEmptyBuffer) {
+    const auto& renderEngineFactory = GetParam();
+    if (renderEngineFactory->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+        // GLES-specific test
+        return;
+    }
+
+    initializeRenderEngine();
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+    settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+
+    // add a red layer
+    renderengine::LayerSettings layerOne{
+            .geometry.boundaries = fullscreenRect().toFloatRect(),
+            .source.solidColor = half3(1.0f, 0.0f, 0.0f),
+            .alpha = 1.f,
+    };
+
+    std::vector<renderengine::LayerSettings> layersFirst{layerOne};
+    invokeDraw(settings, layersFirst);
+    expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
+
+    // re-draw with an empty layer above it, and we get a transparent black one
+    std::vector<renderengine::LayerSettings> layersSecond;
+    invokeDraw(settings, layersSecond);
+    expectBufferColor(fullscreenRect(), 0, 0, 0, 0);
+}
+
 TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) {
     initializeRenderEngine();
 
@@ -2123,7 +2165,7 @@
     casterBounds.offsetBy(shadowLength + 1, shadowLength + 1);
     renderengine::LayerSettings castingLayer;
     castingLayer.geometry.boundaries = casterBounds.toFloatRect();
-    castingLayer.geometry.roundedCornersRadius = 3.0f;
+    castingLayer.geometry.roundedCornersRadius = {3.0f, 3.0f};
     castingLayer.geometry.roundedCornersCrop = casterBounds.toFloatRect();
     castingLayer.alpha = 1.0f;
     renderengine::ShadowSettings settings =
@@ -2211,7 +2253,8 @@
     renderengine::LayerSettings redLayer;
     redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
     redLayer.geometry.boundaries = fullscreenRect().toFloatRect();
-    redLayer.geometry.roundedCornersRadius = 5.0f;
+    redLayer.geometry.roundedCornersRadius = {5.0f, 5.0f};
+
     redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect();
     // Red background.
     redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
@@ -2223,7 +2266,7 @@
     renderengine::LayerSettings greenLayer;
     greenLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
     greenLayer.geometry.boundaries = fullscreenRect().toFloatRect();
-    greenLayer.geometry.roundedCornersRadius = 5.0f;
+    greenLayer.geometry.roundedCornersRadius = {5.0f, 5.0f};
     // Bottom right corner is not going to be rounded.
     greenLayer.geometry.roundedCornersCrop =
             Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3, DEFAULT_DISPLAY_HEIGHT,
@@ -2260,7 +2303,7 @@
     renderengine::LayerSettings redLayer;
     redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
     redLayer.geometry.boundaries = fullscreenRect().toFloatRect();
-    redLayer.geometry.roundedCornersRadius = 5.0f;
+    redLayer.geometry.roundedCornersRadius = {5.0f, 5.0f};
     redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect();
     // Red background.
     redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
@@ -2305,7 +2348,7 @@
     renderengine::LayerSettings redLayer;
     redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
     redLayer.geometry.boundaries = FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, 32);
-    redLayer.geometry.roundedCornersRadius = 64;
+    redLayer.geometry.roundedCornersRadius = {64.0f, 64.0f};
     redLayer.geometry.roundedCornersCrop = FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, 128);
     // Red background.
     redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
@@ -2326,6 +2369,49 @@
     expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, 31), 255, 0, 0, 255);
 }
 
+TEST_P(RenderEngineTest, testRoundedCornersXY) {
+    if (GetParam()->type() != renderengine::RenderEngine::RenderEngineType::SKIA_GL) {
+        GTEST_SKIP();
+    }
+
+    initializeRenderEngine();
+
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+    settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+
+    std::vector<renderengine::LayerSettings> layers;
+
+    renderengine::LayerSettings redLayer;
+    redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+    redLayer.geometry.boundaries = fullscreenRect().toFloatRect();
+    redLayer.geometry.roundedCornersRadius = {5.0f, 20.0f};
+    redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect();
+    // Red background.
+    redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
+    redLayer.alpha = 1.0f;
+
+    layers.push_back(redLayer);
+
+    invokeDraw(settings, layers);
+
+    // Due to roundedCornersRadius, the corners are untouched.
+    expectBufferColor(Point(0, 0), 0, 0, 0, 0);
+    expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 0), 0, 0, 0, 0);
+    expectBufferColor(Point(0, DEFAULT_DISPLAY_HEIGHT - 1), 0, 0, 0, 0);
+    expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 1), 0, 0, 0, 0);
+
+    // Y-axis draws a larger radius, check that its untouched as well
+    expectBufferColor(Point(0, DEFAULT_DISPLAY_HEIGHT - 5), 0, 0, 0, 0);
+    expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 5), 0, 0, 0, 0);
+    expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 5), 0, 0, 0, 0);
+    expectBufferColor(Point(0, 5), 0, 0, 0, 0);
+
+    //  middle should be red
+    expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 255, 0, 0, 255);
+}
+
 TEST_P(RenderEngineTest, testClear) {
     initializeRenderEngine();
 
@@ -2403,6 +2489,55 @@
     expectBufferColor(rect, 0, 128, 0, 128);
 }
 
+TEST_P(RenderEngineTest, testBorder) {
+    if (GetParam()->type() != renderengine::RenderEngine::RenderEngineType::SKIA_GL) {
+        GTEST_SKIP();
+    }
+
+    if (!GetParam()->useColorManagement()) {
+        GTEST_SKIP();
+    }
+
+    initializeRenderEngine();
+
+    const ui::Dataspace dataspace = ui::Dataspace::V0_SRGB;
+
+    const auto displayRect = Rect(1080, 2280);
+    renderengine::DisplaySettings display{
+            .physicalDisplay = displayRect,
+            .clip = displayRect,
+            .outputDataspace = dataspace,
+    };
+    display.borderInfoList.clear();
+    renderengine::BorderRenderInfo info;
+    info.combinedRegion = Region(Rect(99, 99, 199, 199));
+    info.width = 20.0f;
+    info.color = half4{1.0f, 128.0f / 255.0f, 0.0f, 1.0f};
+    display.borderInfoList.emplace_back(info);
+
+    const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255));
+    const renderengine::LayerSettings greenLayer{
+            .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = greenBuffer,
+                                            .usePremultipliedAlpha = true,
+                                    },
+                    },
+            .alpha = 1.0f,
+            .sourceDataspace = dataspace,
+            .whitePointNits = 200.f,
+    };
+
+    std::vector<renderengine::LayerSettings> layers;
+    layers.emplace_back(greenLayer);
+    invokeDraw(display, layers);
+
+    expectBufferColor(Rect(99, 99, 101, 101), 255, 128, 0, 255, 1);
+}
+
 TEST_P(RenderEngineTest, testDimming) {
     if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
         GTEST_SKIP();
@@ -2557,6 +2692,133 @@
     expectBufferColor(Rect(2, 0, 3, 1), 122, 0, 0, 255, 1);
 }
 
+TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform) {
+    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+        GTEST_SKIP();
+    }
+    initializeRenderEngine();
+
+    const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 |
+                                                               ui::Dataspace::TRANSFER_GAMMA2_2 |
+                                                               ui::Dataspace::RANGE_FULL);
+
+    const auto displayRect = Rect(3, 1);
+    const renderengine::DisplaySettings display{
+            .physicalDisplay = displayRect,
+            .clip = displayRect,
+            .outputDataspace = dataspace,
+            .colorTransform = kRemoveGreenAndMoveRedToGreenMat4,
+            .targetLuminanceNits = 1000.f,
+            .dimmingStage = aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+    };
+
+    const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255));
+    const auto blueBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 0, 255, 255));
+    const auto redBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(255, 0, 0, 255));
+
+    const renderengine::LayerSettings greenLayer{
+            .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = greenBuffer,
+                                            .usePremultipliedAlpha = true,
+                                    },
+                    },
+            .alpha = 1.0f,
+            .sourceDataspace = dataspace,
+            .whitePointNits = 200.f,
+    };
+
+    const renderengine::LayerSettings redLayer{
+            .geometry.boundaries = FloatRect(1.f, 0.f, 2.f, 1.f),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = redBuffer,
+                                            .usePremultipliedAlpha = true,
+                                    },
+                    },
+            .alpha = 1.0f,
+            .sourceDataspace = dataspace,
+            // When the white point is not set for a layer, just ignore it and treat it as the same
+            // as the max layer
+            .whitePointNits = -1.f,
+    };
+
+    std::vector<renderengine::LayerSettings> layers{greenLayer, redLayer};
+    invokeDraw(display, layers);
+
+    expectBufferColor(Rect(1, 1), 0, 0, 0, 255, 1);
+    expectBufferColor(Rect(1, 0, 2, 1), 0, 122, 0, 255, 1);
+}
+
+TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform_deviceHandles) {
+    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+        GTEST_SKIP();
+    }
+    initializeRenderEngine();
+
+    const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 |
+                                                               ui::Dataspace::TRANSFER_GAMMA2_2 |
+                                                               ui::Dataspace::RANGE_FULL);
+
+    const auto displayRect = Rect(3, 1);
+    const renderengine::DisplaySettings display{
+            .physicalDisplay = displayRect,
+            .clip = displayRect,
+            .outputDataspace = dataspace,
+            .colorTransform = kRemoveGreenAndMoveRedToGreenMat4,
+            .deviceHandlesColorTransform = true,
+            .targetLuminanceNits = 1000.f,
+            .dimmingStage = aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+    };
+
+    const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255));
+    const auto blueBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 0, 255, 255));
+    const auto redBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(255, 0, 0, 255));
+
+    const renderengine::LayerSettings greenLayer{
+            .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = greenBuffer,
+                                            .usePremultipliedAlpha = true,
+                                    },
+                    },
+            .alpha = 1.0f,
+            .sourceDataspace = dataspace,
+            .whitePointNits = 200.f,
+    };
+
+    const renderengine::LayerSettings redLayer{
+            .geometry.boundaries = FloatRect(1.f, 0.f, 2.f, 1.f),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = redBuffer,
+                                            .usePremultipliedAlpha = true,
+                                    },
+                    },
+            .alpha = 1.0f,
+            .sourceDataspace = dataspace,
+            // When the white point is not set for a layer, just ignore it and treat it as the same
+            // as the max layer
+            .whitePointNits = -1.f,
+    };
+
+    std::vector<renderengine::LayerSettings> layers{greenLayer, redLayer};
+    invokeDraw(display, layers);
+
+    expectBufferColor(Rect(1, 1), 0, 122, 0, 255, 1);
+    expectBufferColor(Rect(1, 0, 2, 1), 122, 0, 0, 255, 1);
+}
+
 TEST_P(RenderEngineTest, testDimming_withoutTargetLuminance) {
     initializeRenderEngine();
     if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
@@ -2796,10 +3058,7 @@
             // pure red to pure green. That will occur when the R8 buffer is
             // 255. When the R8 buffer is 0, it will still change to black, as
             // with r8_behaves_as_mask.
-            .colorTransform = mat4(0, 1, 0, 0,
-                                   0, 0, 0, 0,
-                                   0, 0, 1, 0,
-                                   0, 0, 0, 1),
+            .colorTransform = kRemoveGreenAndMoveRedToGreenMat4,
             .deviceHandlesColorTransform = false,
     };
 
@@ -2902,6 +3161,23 @@
     expectBufferColor(Rect(1, 0, 2, 1), 255, 0, 0, 255); // Still red.
     expectBufferColor(Rect(0, 0, 1, 1), 0,  70, 0, 255);
 }
+
+TEST_P(RenderEngineTest, primeShaderCache) {
+    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+        GTEST_SKIP();
+    }
+
+    initializeRenderEngine();
+
+    auto fut = mRE->primeCache();
+    if (fut.valid()) {
+        fut.wait();
+    }
+
+    const int minimumExpectedShadersCompiled = GetParam()->useColorManagement() ? 60 : 30;
+    ASSERT_GT(static_cast<skia::SkiaGLRenderEngine*>(mRE.get())->reportShadersCompiled(),
+              minimumExpectedShadersCompiled);
+}
 } // namespace renderengine
 } // namespace android
 
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 9685189..909ded3 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -176,7 +176,7 @@
     std::vector<renderengine::LayerSettings> layers;
     std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared<
             renderengine::impl::
-                    ExternalTexture>(new GraphicBuffer(), *mRenderEngine,
+                    ExternalTexture>(sp<GraphicBuffer>::make(), *mRenderEngine,
                                      renderengine::impl::ExternalTexture::Usage::READABLE |
                                              renderengine::impl::ExternalTexture::Usage::WRITEABLE);
 
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index edd453a..2b93c6e 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -24,7 +24,6 @@
 cc_library_shared {
     name: "libsensor",
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -53,5 +52,9 @@
 
     export_include_dirs: ["include"],
 
-    export_shared_lib_headers: ["libbinder", "libpermission", "libhardware"],
+    export_shared_lib_headers: [
+        "libbinder",
+        "libpermission",
+        "libhardware",
+    ],
 }
diff --git a/libs/sensor/fuzz/bittube_fuzzer/Android.bp b/libs/sensor/fuzz/bittube_fuzzer/Android.bp
new file mode 100644
index 0000000..7af22cc
--- /dev/null
+++ b/libs/sensor/fuzz/bittube_fuzzer/Android.bp
@@ -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.
+ *
+ *****************************************************************************
+ */
+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: "bittube_fuzzer",
+    srcs: [
+        "bittube_fuzzer.cpp",
+    ],
+    static_libs: [
+    ],
+    shared_libs: [
+        "libsensor",
+        "libbinder",
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libhardware",
+        "libpermission",
+    ],
+    export_shared_lib_headers: [
+        "libbinder",
+        "libpermission",
+        "libhardware",
+    ],
+    header_libs: [
+    ],
+}
diff --git a/libs/sensor/fuzz/bittube_fuzzer/bittube_fuzzer.cpp b/libs/sensor/fuzz/bittube_fuzzer/bittube_fuzzer.cpp
new file mode 100644
index 0000000..6f10a67
--- /dev/null
+++ b/libs/sensor/fuzz/bittube_fuzzer/bittube_fuzzer.cpp
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * 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 <fuzzer/FuzzedDataProvider.h>
+
+#include <sensor/BitTube.h>
+#include <binder/Parcel.h>
+using namespace android;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+    BitTube bittube(size);
+    Parcel parcel[5];
+    bittube.writeToParcel(parcel);
+    sp<BitTube> tube(new BitTube(size));
+    bittube.sendObjects<uint8_t>(tube, data, size);
+    uint8_t recvData[size];
+    for (int i = 0; i < size; i++) recvData[i] = fdp.ConsumeIntegral<uint8_t>();
+    bittube.recvObjects<uint8_t>(tube, recvData, size);
+
+    return 0;
+}
diff --git a/libs/sensor/fuzz/sensor_fuzzer/Android.bp b/libs/sensor/fuzz/sensor_fuzzer/Android.bp
new file mode 100644
index 0000000..685c549
--- /dev/null
+++ b/libs/sensor/fuzz/sensor_fuzzer/Android.bp
@@ -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.
+ *
+ *****************************************************************************
+ */
+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: "sensor_fuzzer",
+    srcs: [
+        "sensor_fuzzer.cpp",
+    ],
+    shared_libs: [
+        "libsensor",
+        "libbinder",
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libhardware",
+        "libpermission",
+    ],
+    export_shared_lib_headers: [
+        "libbinder",
+        "libpermission",
+        "libhardware",
+    ],
+}
diff --git a/libs/sensor/fuzz/sensor_fuzzer/sensor_fuzzer.cpp b/libs/sensor/fuzz/sensor_fuzzer/sensor_fuzzer.cpp
new file mode 100644
index 0000000..129f430
--- /dev/null
+++ b/libs/sensor/fuzz/sensor_fuzzer/sensor_fuzzer.cpp
@@ -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.
+ *
+ *****************************************************************************
+ */
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <sensor/Sensor.h>
+using namespace android;
+
+const int MAX_STR_LEN = 32;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+    struct sensor_t sensor_type;
+    sensor_type.name = fdp.ConsumeBytesAsString(MAX_STR_LEN).c_str();
+    sensor_type.vendor = fdp.ConsumeBytesAsString(MAX_STR_LEN).c_str();
+    sensor_type.stringType = "";
+    sensor_type.requiredPermission = "";
+    sensor_type.version = fdp.ConsumeIntegral<int>();
+    sensor_type.handle = fdp.ConsumeIntegral<int>();
+    sensor_type.type = fdp.ConsumeIntegral<int>();
+    sensor_type.maxRange = fdp.ConsumeFloatingPoint<float>();
+    sensor_type.resolution = fdp.ConsumeFloatingPoint<float>();
+    sensor_type.power = fdp.ConsumeFloatingPoint<float>();
+    sensor_type.minDelay = fdp.ConsumeIntegral<int32_t>();
+    sensor_type.fifoReservedEventCount = fdp.ConsumeIntegral<uint32_t>();
+    sensor_type.fifoMaxEventCount = fdp.ConsumeIntegral<uint32_t>();
+    int halVersion = fdp.ConsumeIntegral<int>();
+    Sensor sensor1(&sensor_type, halVersion);
+    uint8_t buffer[size];
+    for (int i = 0; i < size; i++) buffer[i] = data[i];
+    sensor1.flatten(buffer, size);
+    std::vector<uint8_t> buffer1(sensor1.getFlattenedSize());
+    auto ab = sensor1.unflatten(buffer1.data(), buffer1.size());
+    return 0;
+}
+
diff --git a/libs/sensor/tests/Android.bp b/libs/sensor/tests/Android.bp
index 8fdb003..ac4be44 100644
--- a/libs/sensor/tests/Android.bp
+++ b/libs/sensor/tests/Android.bp
@@ -24,9 +24,10 @@
 cc_test {
     name: "libsensor_test",
 
-    clang: true,
-
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 
     srcs: [
         "Sensor_test.cpp",
diff --git a/libs/shaders/TEST_MAPPING b/libs/shaders/TEST_MAPPING
new file mode 100644
index 0000000..ad6514d
--- /dev/null
+++ b/libs/shaders/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "presubmit": [
+    {
+      "name": "librenderengine_test"
+    },
+    {
+      "name": "libshaders_test"
+    }
+  ]
+}
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index f0d45c2..f80e93f 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -78,7 +78,7 @@
             shader.append(R"(
 
                 float EOTF_sRGB(float srgb) {
-                    return srgb <= 0.08125 ? srgb / 4.50 : pow((srgb + 0.099) / 1.099, 0.45);
+                    return srgb <= 0.08125 ? srgb / 4.50 : pow((srgb + 0.099) / 1.099, 1 / 0.45);
                 }
 
                 float3 EOTF_sRGB(float3 srgb) {
@@ -469,12 +469,17 @@
         float currentDisplayLuminanceNits, float maxLuminance, AHardwareBuffer* buffer,
         aidl::android::hardware::graphics::composer3::RenderIntent renderIntent) {
     std::vector<tonemap::ShaderUniform> uniforms;
-    if (linearEffect.inputDataspace == linearEffect.outputDataspace) {
+
+    const ui::Dataspace inputDataspace = linearEffect.fakeInputDataspace == ui::Dataspace::UNKNOWN
+            ? linearEffect.inputDataspace
+            : linearEffect.fakeInputDataspace;
+
+    if (inputDataspace == linearEffect.outputDataspace) {
         uniforms.push_back({.name = "in_rgbToXyz", .value = buildUniformValue<mat4>(mat4())});
         uniforms.push_back(
                 {.name = "in_xyzToRgb", .value = buildUniformValue<mat4>(colorTransform)});
     } else {
-        ColorSpace inputColorSpace = toColorSpace(linearEffect.inputDataspace);
+        ColorSpace inputColorSpace = toColorSpace(inputDataspace);
         ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace);
         uniforms.push_back({.name = "in_rgbToXyz",
                             .value = buildUniformValue<mat4>(mat4(inputColorSpace.getRGBtoXYZ()))});
diff --git a/libs/shaders/tests/Android.bp b/libs/shaders/tests/Android.bp
new file mode 100644
index 0000000..cf671bc
--- /dev/null
+++ b/libs/shaders/tests/Android.bp
@@ -0,0 +1,48 @@
+// 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.
+
+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 {
+    name: "libshaders_test",
+    test_suites: ["device-tests"],
+    srcs: [
+        "shaders_test.cpp",
+    ],
+    header_libs: [
+        "libtonemap_headers",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.graphics.composer3-V1-ndk",
+        "android.hardware.graphics.common@1.2",
+        "libnativewindow",
+    ],
+    static_libs: [
+        "libarect",
+        "libgmock",
+        "libgtest",
+        "libmath",
+        "libshaders",
+        "libtonemap",
+        "libui-types",
+    ],
+}
diff --git a/libs/shaders/tests/shaders_test.cpp b/libs/shaders/tests/shaders_test.cpp
new file mode 100644
index 0000000..d45fb24
--- /dev/null
+++ b/libs/shaders/tests/shaders_test.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#include "shaders/shaders.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <math/mat4.h>
+#include <tonemap/tonemap.h>
+#include <ui/ColorSpace.h>
+#include <cmath>
+
+namespace android {
+
+using testing::Contains;
+using testing::HasSubstr;
+
+struct ShadersTest : public ::testing::Test {};
+
+namespace {
+
+MATCHER_P2(UniformEq, name, value, "") {
+    return arg.name == name && arg.value == value;
+}
+
+template <typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, bool> = true>
+std::vector<uint8_t> buildUniformValue(T value) {
+    std::vector<uint8_t> result;
+    result.resize(sizeof(value));
+    std::memcpy(result.data(), &value, sizeof(value));
+    return result;
+}
+
+} // namespace
+
+TEST_F(ShadersTest, buildLinearEffectUniforms_selectsNoOpGamutMatrices) {
+    shaders::LinearEffect effect =
+            shaders::LinearEffect{.inputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+                                  .outputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+                                  .fakeInputDataspace = ui::Dataspace::UNKNOWN};
+
+    mat4 colorTransform = mat4::scale(vec4(.9, .9, .9, 1.));
+    auto uniforms =
+            shaders::buildLinearEffectUniforms(effect, colorTransform, 1.f, 1.f, 1.f, nullptr,
+                                               aidl::android::hardware::graphics::composer3::
+                                                       RenderIntent::COLORIMETRIC);
+    EXPECT_THAT(uniforms, Contains(UniformEq("in_rgbToXyz", buildUniformValue<mat4>(mat4()))));
+    EXPECT_THAT(uniforms,
+                Contains(UniformEq("in_xyzToRgb", buildUniformValue<mat4>(colorTransform))));
+}
+
+TEST_F(ShadersTest, buildLinearEffectUniforms_selectsGamutTransformMatrices) {
+    shaders::LinearEffect effect =
+            shaders::LinearEffect{.inputDataspace = ui::Dataspace::V0_SRGB,
+                                  .outputDataspace = ui::Dataspace::DISPLAY_P3,
+                                  .fakeInputDataspace = ui::Dataspace::UNKNOWN};
+
+    ColorSpace inputColorSpace = ColorSpace::sRGB();
+    ColorSpace outputColorSpace = ColorSpace::DisplayP3();
+    auto uniforms =
+            shaders::buildLinearEffectUniforms(effect, mat4(), 1.f, 1.f, 1.f, nullptr,
+                                               aidl::android::hardware::graphics::composer3::
+                                                       RenderIntent::COLORIMETRIC);
+    EXPECT_THAT(uniforms,
+                Contains(UniformEq("in_rgbToXyz",
+                                   buildUniformValue<mat4>(mat4(inputColorSpace.getRGBtoXYZ())))));
+    EXPECT_THAT(uniforms,
+                Contains(UniformEq("in_xyzToRgb",
+                                   buildUniformValue<mat4>(mat4(outputColorSpace.getXYZtoRGB())))));
+}
+
+TEST_F(ShadersTest, buildLinearEffectUniforms_respectsFakeInputDataspace) {
+    shaders::LinearEffect effect =
+            shaders::LinearEffect{.inputDataspace = ui::Dataspace::V0_SRGB,
+                                  .outputDataspace = ui::Dataspace::DISPLAY_P3,
+                                  .fakeInputDataspace = ui::Dataspace::DISPLAY_P3};
+
+    auto uniforms =
+            shaders::buildLinearEffectUniforms(effect, mat4(), 1.f, 1.f, 1.f, nullptr,
+                                               aidl::android::hardware::graphics::composer3::
+                                                       RenderIntent::COLORIMETRIC);
+    EXPECT_THAT(uniforms, Contains(UniformEq("in_rgbToXyz", buildUniformValue<mat4>(mat4()))));
+    EXPECT_THAT(uniforms, Contains(UniformEq("in_xyzToRgb", buildUniformValue<mat4>(mat4()))));
+}
+
+} // namespace android
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 0a85fe0..ca8adfa 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -36,7 +36,6 @@
 
 cc_defaults {
     name: "libui-defaults",
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -111,7 +110,6 @@
     },
     double_loadable: true,
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libs/ui/DeviceProductInfo.cpp b/libs/ui/DeviceProductInfo.cpp
index 496e2a8..3306012 100644
--- a/libs/ui/DeviceProductInfo.cpp
+++ b/libs/ui/DeviceProductInfo.cpp
@@ -27,7 +27,7 @@
 using base::StringAppendF;
 
 void DeviceProductInfo::dump(std::string& result) const {
-    StringAppendF(&result, "{name=%s, ", name.c_str());
+    StringAppendF(&result, "{name=\"%s\", ", name.c_str());
     StringAppendF(&result, "manufacturerPnpId=%s, ", manufacturerPnpId.data());
     StringAppendF(&result, "productId=%s, ", productId.c_str());
 
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 4f950b8..f6ab7b2 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -1245,8 +1245,9 @@
         } else {
             if (importBuffers) {
                 for (uint32_t i = 0; i < bufferCount; i++) {
-                    error = mMapper.importBuffer(makeFromAidl(result.buffers[i]),
-                                                 &outBufferHandles[i]);
+                    auto handle = makeFromAidl(result.buffers[i]);
+                    error = mMapper.importBuffer(handle, &outBufferHandles[i]);
+                    native_handle_delete(handle);
                     if (error != NO_ERROR) {
                         for (uint32_t j = 0; j < i; j++) {
                             mMapper.freeBuffer(outBufferHandles[j]);
diff --git a/libs/ui/tools/Android.bp b/libs/ui/tools/Android.bp
index c28c303..5d6070c 100644
--- a/libs/ui/tools/Android.bp
+++ b/libs/ui/tools/Android.bp
@@ -25,7 +25,7 @@
 
 cc_defaults {
     name: "libui_tools_default",
-    clang_cflags: [
+    cflags: [
         "-Wall",
         "-Wextra",
         "-Werror",
diff --git a/libs/vibrator/include/vibrator/ExternalVibration.h b/libs/vibrator/include/vibrator/ExternalVibration.h
index c6eb3d1..760dbce 100644
--- a/libs/vibrator/include/vibrator/ExternalVibration.h
+++ b/libs/vibrator/include/vibrator/ExternalVibration.h
@@ -33,7 +33,6 @@
     ExternalVibration(int32_t uid, std::string pkg, const audio_attributes_t& attrs,
             sp<IExternalVibrationController> controller);
     virtual ~ExternalVibration() = default;
-    ExternalVibration(const ExternalVibration&) = default;
 
     bool operator==(const ExternalVibration&) const;
 
diff --git a/libs/vr/libbroadcastring/Android.bp b/libs/vr/libbroadcastring/Android.bp
index d4538f1..e72ca74 100644
--- a/libs/vr/libbroadcastring/Android.bp
+++ b/libs/vr/libbroadcastring/Android.bp
@@ -9,7 +9,7 @@
 
 cc_library_static {
     name: "libbroadcastring",
-    clang: true,
+
     cflags: [
         "-Wall",
         "-Wextra",
@@ -26,7 +26,6 @@
 
 cc_test {
     name: "broadcast_ring_tests",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index c1f6da3..c95603b 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -16,7 +16,6 @@
 
 cc_library_static {
     name: "libpdx",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
@@ -42,7 +41,6 @@
 
 cc_test {
     name: "pdx_tests",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
@@ -72,7 +70,6 @@
 // Code analysis target.
 cc_test {
     name: "pdx_encoder_performance_test",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
diff --git a/libs/vr/libpdx/fuzz/Android.bp b/libs/vr/libpdx/fuzz/Android.bp
index cc32b18..ac831ce 100644
--- a/libs/vr/libpdx/fuzz/Android.bp
+++ b/libs/vr/libpdx/fuzz/Android.bp
@@ -9,7 +9,6 @@
 
 cc_fuzz {
     name: "libpdx_service_dispatcher_fuzzer",
-    clang: true,
     srcs: [
         "service_dispatcher_fuzzer.cpp",
     ],
@@ -24,13 +23,12 @@
     shared_libs: [
         "libutils",
         "liblog",
-        "libcutils"
+        "libcutils",
     ],
 }
 
 cc_fuzz {
     name: "libpdx_message_fuzzer",
-    clang: true,
     srcs: [
         "message_fuzzer.cpp",
     ],
@@ -45,13 +43,12 @@
     shared_libs: [
         "libutils",
         "liblog",
-        "libcutils"
+        "libcutils",
     ],
 }
 
 cc_fuzz {
     name: "libpdx_serialization_fuzzer",
-    clang: true,
     srcs: [
         "serialization_fuzzer.cpp",
     ],
@@ -66,6 +63,6 @@
     shared_libs: [
         "libutils",
         "liblog",
-        "libcutils"
+        "libcutils",
     ],
 }
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index 8046857..a5758b5 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -9,7 +9,6 @@
 
 cc_defaults {
     name: "pdx_default_transport_compiler_defaults",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
@@ -26,7 +25,10 @@
 cc_defaults {
     name: "pdx_use_transport_servicefs",
     export_include_dirs: ["private/servicefs"],
-    whole_static_libs: ["libpdx_servicefs", "libservicefs"],
+    whole_static_libs: [
+        "libpdx_servicefs",
+        "libservicefs",
+    ],
 }
 
 cc_defaults {
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index 216ca9f..7f88daf 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -9,7 +9,6 @@
 
 cc_library_static {
     name: "libpdx_uds",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
@@ -41,7 +40,6 @@
 
 cc_test {
     name: "libpdx_uds_tests",
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
diff --git a/opengl/OWNERS b/opengl/OWNERS
index a47fb9a..379f763 100644
--- a/opengl/OWNERS
+++ b/opengl/OWNERS
@@ -6,7 +6,6 @@
 jessehall@google.com
 lfy@google.com
 lpy@google.com
-timvp@google.com
 romanl@google.com
 vantablack@google.com
 yuxinhu@google.com
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index c9fce8a..c1e935a 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -108,7 +108,6 @@
         // In particular, DO NOT add libutils nor anything "above" libui
         "libgraphicsenv",
         "libnativewindow",
-        "libbacktrace",
         "libbase",
     ],
 }
@@ -165,6 +164,7 @@
         "libnativeloader_lazy",
         "libutils",
         "libSurfaceFlingerProp",
+        "libunwindstack",
     ],
     static_libs: [
         "libEGL_getProcAddress",
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
index beca7f1..86c788d 100644
--- a/opengl/libs/EGL/BlobCache.cpp
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -52,35 +52,37 @@
     ALOGV("initializing random seed using %lld", (unsigned long long)now);
 }
 
-void BlobCache::set(const void* key, size_t keySize, const void* value, size_t valueSize) {
+BlobCache::InsertResult BlobCache::set(const void* key, size_t keySize, const void* value,
+                                       size_t valueSize) {
     if (mMaxKeySize < keySize) {
         ALOGV("set: not caching because the key is too large: %zu (limit: %zu)", keySize,
               mMaxKeySize);
-        return;
+        return InsertResult::kKeyTooBig;
     }
     if (mMaxValueSize < valueSize) {
         ALOGV("set: not caching because the value is too large: %zu (limit: %zu)", valueSize,
               mMaxValueSize);
-        return;
+        return InsertResult::kValueTooBig;
     }
     if (mMaxTotalSize < keySize + valueSize) {
         ALOGV("set: not caching because the combined key/value size is too "
               "large: %zu (limit: %zu)",
               keySize + valueSize, mMaxTotalSize);
-        return;
+        return InsertResult::kCombinedTooBig;
     }
     if (keySize == 0) {
         ALOGW("set: not caching because keySize is 0");
-        return;
+        return InsertResult::kInvalidKeySize;
     }
-    if (valueSize <= 0) {
+    if (valueSize == 0) {
         ALOGW("set: not caching because valueSize is 0");
-        return;
+        return InsertResult::kInvalidValueSize;
     }
 
     std::shared_ptr<Blob> cacheKey(new Blob(key, keySize, false));
     CacheEntry cacheEntry(cacheKey, nullptr);
 
+    bool didClean = false;
     while (true) {
         auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), cacheEntry);
         if (index == mCacheEntries.end() || cacheEntry < *index) {
@@ -92,13 +94,14 @@
                 if (isCleanable()) {
                     // Clean the cache and try again.
                     clean();
+                    didClean = true;
                     continue;
                 } else {
                     ALOGV("set: not caching new key/value pair because the "
                           "total cache size limit would be exceeded: %zu "
                           "(limit: %zu)",
                           keySize + valueSize, mMaxTotalSize);
-                    break;
+                    return InsertResult::kNotEnoughSpace;
                 }
             }
             mCacheEntries.insert(index, CacheEntry(keyBlob, valueBlob));
@@ -114,12 +117,13 @@
                 if (isCleanable()) {
                     // Clean the cache and try again.
                     clean();
+                    didClean = true;
                     continue;
                 } else {
                     ALOGV("set: not caching new value because the total cache "
                           "size limit would be exceeded: %zu (limit: %zu)",
                           keySize + valueSize, mMaxTotalSize);
-                    break;
+                    return InsertResult::kNotEnoughSpace;
                 }
             }
             index->setValue(valueBlob);
@@ -128,7 +132,7 @@
                   "value",
                   keySize, valueSize);
         }
-        break;
+        return didClean ? InsertResult::kDidClean : InsertResult::kInserted;
     }
 }
 
diff --git a/opengl/libs/EGL/BlobCache.h b/opengl/libs/EGL/BlobCache.h
index 50b4e4c..ff03d30 100644
--- a/opengl/libs/EGL/BlobCache.h
+++ b/opengl/libs/EGL/BlobCache.h
@@ -39,6 +39,26 @@
     // (key sizes plus value sizes) will not exceed maxTotalSize.
     BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize);
 
+    // Return value from set(), below.
+    enum class InsertResult {
+        // The key is larger than maxKeySize specified in the constructor.
+        kKeyTooBig,
+        // The value is larger than maxValueSize specified in the constructor.
+        kValueTooBig,
+        // The combined key + value is larger than maxTotalSize specified in the constructor.
+        kCombinedTooBig,
+        // keySize is 0
+        kInvalidKeySize,
+        // valueSize is 0
+        kInvalidValueSize,
+        // Unable to free enough space to fit the new entry.
+        kNotEnoughSpace,
+        // The new entry was inserted, but an old entry had to be evicted.
+        kDidClean,
+        // There was enough room in the cache and the new entry was inserted.
+        kInserted,
+
+    };
     // set inserts a new binary value into the cache and associates it with the
     // given binary key.  If the key or value are too large for the cache then
     // the cache remains unchanged.  This includes the case where a different
@@ -54,7 +74,7 @@
     //   0 < keySize
     //   value != NULL
     //   0 < valueSize
-    void set(const void* key, size_t keySize, const void* value, size_t valueSize);
+    InsertResult set(const void* key, size_t keySize, const void* value, size_t valueSize);
 
     // get retrieves from the cache the binary value associated with a given
     // binary key.  If the key is present in the cache then the length of the
diff --git a/opengl/libs/EGL/BlobCache_test.cpp b/opengl/libs/EGL/BlobCache_test.cpp
index d31373b..ceea0fb 100644
--- a/opengl/libs/EGL/BlobCache_test.cpp
+++ b/opengl/libs/EGL/BlobCache_test.cpp
@@ -49,7 +49,7 @@
 
 TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
     unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
-    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
     ASSERT_EQ('e', buf[0]);
     ASSERT_EQ('f', buf[1]);
@@ -59,8 +59,8 @@
 
 TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
     unsigned char buf[2] = {0xee, 0xee};
-    mBC->set("ab", 2, "cd", 2);
-    mBC->set("ef", 2, "gh", 2);
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("ab", 2, "cd", 2));
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("ef", 2, "gh", 2));
     ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
     ASSERT_EQ('c', buf[0]);
     ASSERT_EQ('d', buf[1]);
@@ -71,7 +71,7 @@
 
 TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
     unsigned char buf[6] = {0xee, 0xee, 0xee, 0xee, 0xee, 0xee};
-    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf + 1, 4));
     ASSERT_EQ(0xee, buf[0]);
     ASSERT_EQ('e', buf[1]);
@@ -83,7 +83,7 @@
 
 TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
     unsigned char buf[3] = {0xee, 0xee, 0xee};
-    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
     ASSERT_EQ(0xee, buf[0]);
     ASSERT_EQ(0xee, buf[1]);
@@ -91,14 +91,14 @@
 }
 
 TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
-    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, nullptr, 0));
 }
 
 TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
     unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
-    mBC->set("abcd", 4, "efgh", 4);
-    mBC->set("abcd", 4, "ijkl", 4);
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "ijkl", 4));
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
     ASSERT_EQ('i', buf[0]);
     ASSERT_EQ('j', buf[1]);
@@ -108,8 +108,8 @@
 
 TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
     unsigned char buf[MAX_VALUE_SIZE + 1] = {0xee, 0xee, 0xee, 0xee};
-    mBC->set("abcd", 4, "efgh", 4);
-    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1);
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
+    ASSERT_EQ(BlobCache::InsertResult::kValueTooBig, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1));
     ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
     ASSERT_EQ('e', buf[0]);
     ASSERT_EQ('f', buf[1]);
@@ -123,7 +123,7 @@
     for (int i = 0; i < MAX_KEY_SIZE + 1; i++) {
         key[i] = 'a';
     }
-    mBC->set(key, MAX_KEY_SIZE + 1, "bbbb", 4);
+    ASSERT_EQ(BlobCache::InsertResult::kKeyTooBig, mBC->set(key, MAX_KEY_SIZE + 1, "bbbb", 4));
     ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE + 1, buf, 4));
     ASSERT_EQ(0xee, buf[0]);
     ASSERT_EQ(0xee, buf[1]);
@@ -136,7 +136,7 @@
     for (int i = 0; i < MAX_VALUE_SIZE + 1; i++) {
         buf[i] = 'b';
     }
-    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1);
+    ASSERT_EQ(BlobCache::InsertResult::kValueTooBig, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1));
     for (int i = 0; i < MAX_VALUE_SIZE + 1; i++) {
         buf[i] = 0xee;
     }
@@ -163,7 +163,8 @@
         buf[i] = 'b';
     }
 
-    mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE);
+    ASSERT_EQ(BlobCache::InsertResult::kCombinedTooBig,
+              mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE));
     ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
 }
 
@@ -173,7 +174,7 @@
     for (int i = 0; i < MAX_KEY_SIZE; i++) {
         key[i] = 'a';
     }
-    mBC->set(key, MAX_KEY_SIZE, "wxyz", 4);
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(key, MAX_KEY_SIZE, "wxyz", 4));
     ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4));
     ASSERT_EQ('w', buf[0]);
     ASSERT_EQ('x', buf[1]);
@@ -186,7 +187,7 @@
     for (int i = 0; i < MAX_VALUE_SIZE; i++) {
         buf[i] = 'b';
     }
-    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE);
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE));
     for (int i = 0; i < MAX_VALUE_SIZE; i++) {
         buf[i] = 0xee;
     }
@@ -212,13 +213,45 @@
         buf[i] = 'b';
     }
 
-    mBC->set(key, MAX_KEY_SIZE, buf, bufSize);
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(key, MAX_KEY_SIZE, buf, bufSize));
     ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
 }
 
+// Verify that kNotEnoughSpace is returned from BlobCache::set when expected.
+// Note: This relies on internal knowledge of how BlobCache works.
+TEST_F(BlobCacheTest, NotEnoughSpace) {
+    // Insert a small entry into the cache.
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("x", 1, "y", 1));
+
+    // Attempt to put a max size entry into the cache. If the cache were empty,
+    // as in CacheMaxKeyValuePairSizeSucceeds, this would succeed. Based on the
+    // current logic of BlobCache, the small entry is not big enough to allow it
+    // to be cleaned to insert the new entry.
+    ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+    enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE };
+
+    char key[MAX_KEY_SIZE];
+    char buf[bufSize];
+    for (int i = 0; i < MAX_KEY_SIZE; i++) {
+        key[i] = 'a';
+    }
+    for (int i = 0; i < bufSize; i++) {
+        buf[i] = 'b';
+    }
+
+    ASSERT_EQ(BlobCache::InsertResult::kNotEnoughSpace, mBC->set(key, MAX_KEY_SIZE, buf, bufSize));
+    ASSERT_EQ(0, mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
+
+    // The original entry remains in the cache.
+    unsigned char buf2[1] = {0xee};
+    ASSERT_EQ(size_t(1), mBC->get("x", 1, buf2, 1));
+    ASSERT_EQ('y', buf2[0]);
+}
+
 TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
     unsigned char buf[1] = {0xee};
-    mBC->set("x", 1, "y", 1);
+    ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("x", 1, "y", 1));
     ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
     ASSERT_EQ('y', buf[0]);
 }
@@ -243,12 +276,12 @@
     const int maxEntries = MAX_TOTAL_SIZE / 2;
     for (int i = 0; i < maxEntries; i++) {
         uint8_t k = i;
-        mBC->set(&k, 1, "x", 1);
+        ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(&k, 1, "x", 1));
     }
     // Insert one more entry, causing a cache overflow.
     {
         uint8_t k = maxEntries;
-        mBC->set(&k, 1, "x", 1);
+        ASSERT_EQ(BlobCache::InsertResult::kDidClean, mBC->set(&k, 1, "x", 1));
     }
     // Count the number of entries in the cache.
     int numCached = 0;
@@ -261,6 +294,14 @@
     ASSERT_EQ(maxEntries / 2 + 1, numCached);
 }
 
+TEST_F(BlobCacheTest, InvalidKeySize) {
+    ASSERT_EQ(BlobCache::InsertResult::kInvalidKeySize, mBC->set("", 0, "efgh", 4));
+}
+
+TEST_F(BlobCacheTest, InvalidValueSize) {
+    ASSERT_EQ(BlobCache::InsertResult::kInvalidValueSize, mBC->set("abcd", 4, "", 0));
+}
+
 class BlobCacheFlattenTest : public BlobCacheTest {
 protected:
     virtual void SetUp() {
diff --git a/opengl/libs/EGL/CallStack.h b/opengl/libs/EGL/CallStack.h
index b7fdf97..96437c3 100644
--- a/opengl/libs/EGL/CallStack.h
+++ b/opengl/libs/EGL/CallStack.h
@@ -16,8 +16,8 @@
 
 #pragma once
 
-#include <backtrace/Backtrace.h>
 #include <log/log.h>
+#include <unwindstack/AndroidUnwinder.h>
 
 #include <memory>
 
@@ -26,12 +26,15 @@
     // Create a callstack with the current thread's stack trace.
     // Immediately dump it to logcat using the given logtag.
     static void log(const char* logtag) noexcept {
-        std::unique_ptr<Backtrace> backtrace(
-                Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
-        if (backtrace->Unwind(2)) {
-            for (size_t i = 0, c = backtrace->NumFrames(); i < c; i++) {
+        unwindstack::AndroidLocalUnwinder unwinder;
+        unwindstack::AndroidUnwinderData data;
+        if (unwinder.Unwind(data)) {
+            for (size_t i = 2, c = data.frames.size(); i < c; i++) {
+                auto& frame = data.frames[i];
+                // Trim the first two frames.
+                frame.num -= 2;
                 __android_log_print(ANDROID_LOG_DEBUG, logtag, "%s",
-                                    backtrace->FormatFrameData(i).c_str());
+                                    unwinder.FormatFrame(frame).c_str());
             }
         }
     }
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/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index f4dbe49..7619a50 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -1453,7 +1453,11 @@
             setError(EGL_BAD_SURFACE, EGL_FALSE);
         }
         int err = native_window_set_auto_refresh(s->getNativeWindow(), value != 0);
-        return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+        if (err != 0) {
+            return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+        } else if (!s->cnx->useAngle) {
+            return EGL_TRUE;
+        } // else if ANGLE, fall through to the call to the driver (i.e. ANGLE) below
     }
 
     if (attribute == EGL_TIMESTAMPS_ANDROID) {
@@ -1463,7 +1467,11 @@
             return EGL_TRUE;
         }
         int err = native_window_enable_frame_timestamps(s->getNativeWindow(), value != 0);
-        return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+        if (err != 0) {
+            return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+        } else if (!s->cnx->useAngle) {
+            return EGL_TRUE;
+        } // else if ANGLE, fall through to the call to the driver (i.e. ANGLE) below
     }
 
     if (s->setSmpte2086Attribute(attribute, value)) {
diff --git a/opengl/tests/gl2_cameraeye/AndroidManifest.xml b/opengl/tests/gl2_cameraeye/AndroidManifest.xml
index c53f7be..a4674e1 100644
--- a/opengl/tests/gl2_cameraeye/AndroidManifest.xml
+++ b/opengl/tests/gl2_cameraeye/AndroidManifest.xml
@@ -26,7 +26,7 @@
     <uses-feature android:name="android.hardware.camera.autofocus" />
     <uses-feature android:glEsVersion="0x00020000" />
     <application android:label="@string/gl2cameraeye_name">
-        <activity android:name="GL2CameraEye">
+        <activity android:name="GL2CameraEye" android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
diff --git a/opengl/tests/gl2_java/AndroidManifest.xml b/opengl/tests/gl2_java/AndroidManifest.xml
index 8bb6840..500adb5 100644
--- a/opengl/tests/gl2_java/AndroidManifest.xml
+++ b/opengl/tests/gl2_java/AndroidManifest.xml
@@ -22,7 +22,8 @@
         <activity android:name="GL2JavaActivity"
                 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
             	android:launchMode="singleTask"
-            	android:configChanges="orientation|keyboardHidden">
+		android:configChanges="orientation|keyboardHidden"
+		android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/opengl/tests/gl2_jni/AndroidManifest.xml b/opengl/tests/gl2_jni/AndroidManifest.xml
index 1827e5f..b4ce99b 100644
--- a/opengl/tests/gl2_jni/AndroidManifest.xml
+++ b/opengl/tests/gl2_jni/AndroidManifest.xml
@@ -21,7 +21,8 @@
         <activity android:name="GL2JNIActivity"
                 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
             	android:launchMode="singleTask"
-            	android:configChanges="orientation|keyboardHidden">
+		android:configChanges="orientation|keyboardHidden"
+		android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/opengl/tests/gl_jni/AndroidManifest.xml b/opengl/tests/gl_jni/AndroidManifest.xml
index 5d0ec96..bedab56 100644
--- a/opengl/tests/gl_jni/AndroidManifest.xml
+++ b/opengl/tests/gl_jni/AndroidManifest.xml
@@ -24,7 +24,8 @@
                 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
             	android:launchMode="singleTask"
             	android:screenOrientation="landscape"
-            	android:configChanges="orientation|keyboardHidden">
+		android:configChanges="orientation|keyboardHidden"
+		android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/opengl/tests/lighting1709/AndroidManifest.xml b/opengl/tests/lighting1709/AndroidManifest.xml
index 6c23d42..d766be9 100644
--- a/opengl/tests/lighting1709/AndroidManifest.xml
+++ b/opengl/tests/lighting1709/AndroidManifest.xml
@@ -2,7 +2,7 @@
         package="com.android.lightingtest">
 
     <application>
-        <activity android:name="ClearActivity" android:label="LightingTest">
+        <activity android:name="ClearActivity" android:label="LightingTest" android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/opengl/tests/testPauseResume/AndroidManifest.xml b/opengl/tests/testPauseResume/AndroidManifest.xml
index 1879bc3..ae82a82 100644
--- a/opengl/tests/testPauseResume/AndroidManifest.xml
+++ b/opengl/tests/testPauseResume/AndroidManifest.xml
@@ -24,7 +24,8 @@
                 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
             	android:launchMode="singleTask"
             	android:screenOrientation="landscape"
-            	android:configChanges="orientation|keyboardHidden">
+		android:configChanges="orientation|keyboardHidden"
+		android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 120000
index 0000000..ee92d9e
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1 @@
+../../build/soong/scripts/rustfmt.toml
\ No newline at end of file
diff --git a/services/audiomanager/IAudioManager.cpp b/services/audiomanager/IAudioManager.cpp
index ae1bb1a..3ef5049 100644
--- a/services/audiomanager/IAudioManager.cpp
+++ b/services/audiomanager/IAudioManager.cpp
@@ -87,12 +87,12 @@
     }
 
     virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,
-            audio_port_handle_t deviceId) {
+            audio_port_handle_t eventId) {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
         data.writeInt32((int32_t) piid);
         data.writeInt32((int32_t) event);
-        data.writeInt32((int32_t) deviceId);
+        data.writeInt32((int32_t) eventId);
         return remote()->transact(PLAYER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
@@ -141,6 +141,17 @@
         data.writeInt32((int32_t) sessionId);
         return remote()->transact(PLAYER_SESSION_ID, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual status_t portEvent(audio_port_handle_t portId, player_state_t event,
+            const std::unique_ptr<os::PersistableBundle>& extras) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
+        data.writeInt32((int32_t) portId);
+        data.writeInt32((int32_t) event);
+        // TODO: replace PersistableBundle with own struct
+        data.writeNullableParcelable(extras);
+        return remote()->transact(PORT_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioManager, "android.media.IAudioService");
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index 5b4ee21..fba64c7 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -99,7 +99,7 @@
     init_rc: ["gpuservice.rc"],
     required: [
         "bpfloader",
-        "gpu_mem.o",
+        "gpuMem.o",
     ],
     srcs: [":gpuservice_binary_sources"],
     shared_libs: [
diff --git a/services/gpuservice/CleanSpec.mk b/services/gpuservice/CleanSpec.mk
index 482fc6d..c51f6aa 100644
--- a/services/gpuservice/CleanSpec.mk
+++ b/services/gpuservice/CleanSpec.mk
@@ -44,9 +44,9 @@
 #$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
 #$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
 
-# Remove gpu_mem.o
+# Remove gpuMem.o
 $(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/frameworks/native/services/gpuservice/bpf)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/FAKE/gpu_mem.o_intermediates)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/ETC/gpu_mem.o_gpu_mem.o_intermediates)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/bpf/gpu_mem.o)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/fake_packages/gpu_mem.o-timestamp)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/FAKE/gpuMem.o_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/ETC/gpuMem.o_gpuMem.o_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/bpf/gpuMem.o)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/fake_packages/gpuMem.o-timestamp)
diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp
index 076affd..680b291 100644
--- a/services/gpuservice/bpfprogs/Android.bp
+++ b/services/gpuservice/bpfprogs/Android.bp
@@ -22,8 +22,8 @@
 }
 
 bpf {
-    name: "gpu_mem.o",
-    srcs: ["gpu_mem.c"],
+    name: "gpuMem.o",
+    srcs: ["gpuMem.c"],
     btf: true,
     cflags: [
         "-Wall",
diff --git a/services/gpuservice/bpfprogs/gpu_mem.c b/services/gpuservice/bpfprogs/gpuMem.c
similarity index 100%
rename from services/gpuservice/bpfprogs/gpu_mem.c
rename to services/gpuservice/bpfprogs/gpuMem.c
diff --git a/services/gpuservice/gpumem/include/gpumem/GpuMem.h b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
index de691e2..7588b54 100644
--- a/services/gpuservice/gpumem/include/gpumem/GpuMem.h
+++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
@@ -57,9 +57,9 @@
     static constexpr char kGpuMemTotalTracepoint[] = "gpu_mem_total";
     // pinned gpu memory total bpf c program path in bpf sysfs
     static constexpr char kGpuMemTotalProgPath[] =
-            "/sys/fs/bpf/prog_gpu_mem_tracepoint_gpu_mem_gpu_mem_total";
+            "/sys/fs/bpf/prog_gpuMem_tracepoint_gpu_mem_gpu_mem_total";
     // pinned gpu memory total bpf map path in bpf sysfs
-    static constexpr char kGpuMemTotalMapPath[] = "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map";
+    static constexpr char kGpuMemTotalMapPath[] = "/sys/fs/bpf/map_gpuMem_gpu_mem_total_map";
     // 30 seconds timeout for trying to attach bpf program to tracepoint
     static constexpr int kGpuWaitTimeout = 30;
 };
diff --git a/services/gpuservice/gpuwork/Android.bp b/services/gpuservice/gpuwork/Android.bp
index a9a59bc..e204040 100644
--- a/services/gpuservice/gpuwork/Android.bp
+++ b/services/gpuservice/gpuwork/Android.bp
@@ -55,6 +55,6 @@
     ],
     required: [
         "bpfloader",
-        "gpu_work.o",
+        "gpuWork.o",
     ],
 }
diff --git a/services/gpuservice/gpuwork/GpuWork.cpp b/services/gpuservice/gpuwork/GpuWork.cpp
index 974ae38..fd70323 100644
--- a/services/gpuservice/gpuwork/GpuWork.cpp
+++ b/services/gpuservice/gpuwork/GpuWork.cpp
@@ -42,7 +42,7 @@
 #include <unordered_set>
 #include <vector>
 
-#include "gpuwork/gpu_work.h"
+#include "gpuwork/gpuWork.h"
 
 #define ONE_MS_IN_NS (10000000)
 
@@ -128,11 +128,11 @@
     {
         std::lock_guard<std::mutex> lock(mMutex);
 
-        if (!getBpfMap("/sys/fs/bpf/map_gpu_work_gpu_work_map", &mGpuWorkMap)) {
+        if (!getBpfMap("/sys/fs/bpf/map_gpuWork_gpu_work_map", &mGpuWorkMap)) {
             return;
         }
 
-        if (!getBpfMap("/sys/fs/bpf/map_gpu_work_gpu_work_global_data", &mGpuWorkGlobalDataMap)) {
+        if (!getBpfMap("/sys/fs/bpf/map_gpuWork_gpu_work_global_data", &mGpuWorkGlobalDataMap)) {
             return;
         }
 
@@ -140,7 +140,7 @@
     }
 
     // Attach the tracepoint.
-    if (!attachTracepoint("/sys/fs/bpf/prog_gpu_work_tracepoint_power_gpu_work_period", "power",
+    if (!attachTracepoint("/sys/fs/bpf/prog_gpuWork_tracepoint_power_gpu_work_period", "power",
                           "gpu_work_period")) {
         return;
     }
diff --git a/services/gpuservice/gpuwork/bpfprogs/Android.bp b/services/gpuservice/gpuwork/bpfprogs/Android.bp
index b3c4eff..fe45c98 100644
--- a/services/gpuservice/gpuwork/bpfprogs/Android.bp
+++ b/services/gpuservice/gpuwork/bpfprogs/Android.bp
@@ -17,8 +17,8 @@
 }
 
 bpf {
-    name: "gpu_work.o",
-    srcs: ["gpu_work.c"],
+    name: "gpuWork.o",
+    srcs: ["gpuWork.c"],
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/services/gpuservice/gpuwork/bpfprogs/gpu_work.c b/services/gpuservice/gpuwork/bpfprogs/gpuWork.c
similarity index 98%
rename from services/gpuservice/gpuwork/bpfprogs/gpu_work.c
rename to services/gpuservice/gpuwork/bpfprogs/gpuWork.c
index 95cfae7..f470189 100644
--- a/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
+++ b/services/gpuservice/gpuwork/bpfprogs/gpuWork.c
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "include/gpuwork/gpu_work.h"
+#include "include/gpuwork/gpuWork.h"
 
 #include <linux/bpf.h>
 #include <stddef.h>
@@ -153,11 +153,11 @@
     uint32_t uid;
 
     // The start time of the period in nanoseconds. The clock must be
-    // CLOCK_MONOTONIC, as returned by the ktime_get_ns(void) function.
+    // CLOCK_MONOTONIC_RAW, as returned by the ktime_get_raw_ns(void) function.
     uint64_t start_time_ns;
 
     // The end time of the period in nanoseconds. The clock must be
-    // CLOCK_MONOTONIC, as returned by the ktime_get_ns(void) function.
+    // CLOCK_MONOTONIC_RAW, as returned by the ktime_get_raw_ns(void) function.
     uint64_t end_time_ns;
 
     // The amount of time the GPU was running GPU work for |uid| during the
diff --git a/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h b/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpuWork.h
similarity index 94%
rename from services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h
rename to services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpuWork.h
index 57338f4..2affb60 100644
--- a/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h
+++ b/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpuWork.h
@@ -49,6 +49,8 @@
     // negative duration.
     uint32_t error_count;
 
+    // Needed to make 32-bit arch struct size match 64-bit BPF arch struct size.
+    uint32_t padding0;
 } UidTrackingInfo;
 
 typedef struct {
diff --git a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
index acecd56..cece999 100644
--- a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
+++ b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
@@ -27,7 +27,7 @@
 #include <functional>
 #include <thread>
 
-#include "gpuwork/gpu_work.h"
+#include "gpuwork/gpuWork.h"
 
 namespace android {
 namespace gpuwork {
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index 4fb0d2e..86f6c7f 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -35,6 +35,7 @@
     header_libs: ["bpf_headers"],
     shared_libs: [
         "libbase",
+        "libbinder",
         "libbpf_bcc",
         "libcutils",
         "libgfxstats",
diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp
index e916221..8dabe4f 100644
--- a/services/gpuservice/tests/unittests/GpuMemTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "gpuservice_unittest"
 
 #include <android-base/stringprintf.h>
+#define BPF_MAP_MAKE_VISIBLE_FOR_TESTING
 #include <bpf/BpfMap.h>
 #include <gmock/gmock.h>
 #include <gpumem/GpuMem.h>
@@ -65,11 +66,11 @@
         mTestableGpuMem = TestableGpuMem(mGpuMem.get());
         mTestableGpuMem.setInitialized();
         errno = 0;
-        mTestMap = bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE,
-                                                   BPF_F_NO_PREALLOC);
+        mTestMap = std::move(bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH,
+                                                             TEST_MAP_SIZE,
+                                                             BPF_F_NO_PREALLOC));
 
         EXPECT_EQ(0, errno);
-        EXPECT_LE(0, mTestMap.getMap().get());
         EXPECT_TRUE(mTestMap.isValid());
     }
 
@@ -89,8 +90,8 @@
     EXPECT_EQ(mTestableGpuMem.getGpuMemTraceGroup(), "gpu_mem");
     EXPECT_EQ(mTestableGpuMem.getGpuMemTotalTracepoint(), "gpu_mem_total");
     EXPECT_EQ(mTestableGpuMem.getGpuMemTotalProgPath(),
-              "/sys/fs/bpf/prog_gpu_mem_tracepoint_gpu_mem_gpu_mem_total");
-    EXPECT_EQ(mTestableGpuMem.getGpuMemTotalMapPath(), "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map");
+              "/sys/fs/bpf/prog_gpuMem_tracepoint_gpu_mem_gpu_mem_total");
+    EXPECT_EQ(mTestableGpuMem.getGpuMemTotalMapPath(), "/sys/fs/bpf/map_gpuMem_gpu_mem_total_map");
 }
 
 TEST_F(GpuMemTest, bpfInitializationFailed) {
diff --git a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
index d76f039..5c04210 100644
--- a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
@@ -17,6 +17,7 @@
 #undef LOG_TAG
 #define LOG_TAG "gpuservice_unittest"
 
+#define BPF_MAP_MAKE_VISIBLE_FOR_TESTING
 #include <bpf/BpfMap.h>
 #include <gpumem/GpuMem.h>
 #include <gtest/gtest.h>
@@ -64,11 +65,11 @@
         mTestableGpuMem = TestableGpuMem(mGpuMem.get());
 
         errno = 0;
-        mTestMap = bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE,
-                                                   BPF_F_NO_PREALLOC);
+        mTestMap = std::move(bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH,
+                                                             TEST_MAP_SIZE,
+                                                             BPF_F_NO_PREALLOC));
 
         EXPECT_EQ(0, errno);
-        EXPECT_LE(0, mTestMap.getMap().get());
         EXPECT_TRUE(mTestMap.isValid());
     }
 
diff --git a/services/gpuservice/tests/unittests/GpuStatsTest.cpp b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
index 20c8ccf..7ea2288 100644
--- a/services/gpuservice/tests/unittests/GpuStatsTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
@@ -18,12 +18,14 @@
 #define LOG_TAG "gpuservice_unittest"
 
 #include <unistd.h>
+#include <binder/ProcessState.h>
 #include <cutils/properties.h>
 #include <gmock/gmock.h>
 #include <gpustats/GpuStats.h>
 #include <gtest/gtest.h>
 #include <stats_pull_atom_callback.h>
 #include <statslog.h>
+#include <utils/Looper.h>
 #include <utils/String16.h>
 #include <utils/Vector.h>
 
@@ -61,8 +63,9 @@
 // clang-format on
 
 class GpuStatsTest : public testing::Test {
+    sp<android::Looper> looper;
 public:
-    GpuStatsTest() {
+    GpuStatsTest() : looper(Looper::prepare(0 /* opts */)) {
         const ::testing::TestInfo* const test_info =
                 ::testing::UnitTest::GetInstance()->current_test_info();
         ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
@@ -72,6 +75,16 @@
         const ::testing::TestInfo* const test_info =
                 ::testing::UnitTest::GetInstance()->current_test_info();
         ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+
+        // This is required for test due to GpuStats instance spawns binder transactions
+        // in its destructor. After the gtest destructor test exits immidiatelly.
+        // It results in binder thread not able to process above binder transactions and memory leak
+        // occures. Binder thread needs time to process callbacks transactions.
+        // It leads to GpuStats instance destructor needs to be called in advance.
+        mGpuStats.reset(nullptr);
+        // performs all pending callbacks until all data has been consumed
+        // gives time to process binder transactions by thread pool
+        looper->pollAll(1000);
     }
 
     std::string inputCommand(InputCommand cmd);
@@ -79,6 +92,10 @@
     void SetUp() override {
         mCpuVulkanVersion = property_get_int32("ro.cpuvulkan.version", 0);
         mGlesVersion = property_get_int32("ro.opengles.version", 0);
+
+        // start the thread pool
+        sp<ProcessState> ps(ProcessState::self());
+        ps->startThreadPool();
     }
 
     std::unique_ptr<GpuStats> mGpuStats = std::make_unique<GpuStats>();
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 41878e3..29a0e4f 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -38,6 +38,7 @@
         "-Wshadow",
         "-Wshadow-field-in-constructor-modified",
         "-Wshadow-uncaptured-local",
+        "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
     ],
     sanitize: {
         misc_undefined: ["bounds"],
@@ -56,7 +57,7 @@
 filegroup {
     name: "libinputflinger_sources",
     srcs: [
-        "InputClassifier.cpp",
+        "InputProcessor.cpp",
         "InputCommonConverter.cpp",
         "PreferStylusOverTouchBlocker.cpp",
         "UnwantedInteractionBlocker.cpp",
@@ -168,3 +169,39 @@
         "libinputflinger_headers",
     ],
 }
+
+// This target will build everything 'input-related'. This could be useful for
+// large refactorings of the input code. This is similar to 'm checkbuild', but
+// just for input code.
+// Use 'm checkinput' to build, and then (optionally) use 'm installclean' to
+// remove any of the installed artifacts that you may not want on your actual
+// build.
+phony {
+    name: "checkinput",
+    required: [
+        // native targets
+        "libinput",
+        "libinputflinger",
+        "inputflinger_tests",
+        "inputflinger_benchmarks",
+        "libinput_tests",
+        "libpalmrejection_test",
+        "libandroid_runtime",
+        "libinputservice_test",
+        "Bug-115739809",
+        "StructLayout_test",
+        "inputflinger_latencytracker_fuzzer",
+
+        // Java/Kotlin targets
+        "CtsWindowManagerDeviceTestCases",
+        "InputTests",
+        "CtsHardwareTestCases",
+        "CtsInputTestCases",
+        "CtsViewTestCases",
+        "CtsWidgetTestCases",
+        "FrameworksCoreTests",
+        "FrameworksServicesTests",
+        "CtsSecurityTestCases",
+        "CtsSecurityBulletinHostTestCases",
+    ],
+}
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/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 7b03631..9182503 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -55,15 +55,15 @@
 
 /**
  * The event flow is via the "InputListener" interface, as follows:
- * InputReader -> UnwantedInteractionBlocker -> InputClassifier -> InputDispatcher
+ * InputReader -> UnwantedInteractionBlocker -> InputProcessor -> InputDispatcher
  */
 InputManager::InputManager(
         const sp<InputReaderPolicyInterface>& readerPolicy,
         const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
     mDispatcher = createInputDispatcher(dispatcherPolicy);
-    mClassifier = std::make_unique<InputClassifier>(*mDispatcher);
-    mUnwantedInteractionBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier);
-    mReader = createInputReader(readerPolicy, *mUnwantedInteractionBlocker);
+    mProcessor = std::make_unique<InputProcessor>(*mDispatcher);
+    mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mProcessor);
+    mReader = createInputReader(readerPolicy, *mBlocker);
 }
 
 InputManager::~InputManager() {
@@ -110,18 +110,25 @@
     return *mReader;
 }
 
-UnwantedInteractionBlockerInterface& InputManager::getUnwantedInteractionBlocker() {
-    return *mUnwantedInteractionBlocker;
+UnwantedInteractionBlockerInterface& InputManager::getBlocker() {
+    return *mBlocker;
 }
 
-InputClassifierInterface& InputManager::getClassifier() {
-    return *mClassifier;
+InputProcessorInterface& InputManager::getProcessor() {
+    return *mProcessor;
 }
 
 InputDispatcherInterface& InputManager::getDispatcher() {
     return *mDispatcher;
 }
 
+void InputManager::monitor() {
+    mReader->monitor();
+    mBlocker->monitor();
+    mProcessor->monitor();
+    mDispatcher->monitor();
+}
+
 // Used by tests only.
 binder::Status InputManager::createInputChannel(const std::string& name, InputChannel* outChannel) {
     IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 35d2b0f..b40ab7f 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -21,7 +21,7 @@
  * Native input manager.
  */
 
-#include "InputClassifier.h"
+#include "InputProcessor.h"
 #include "InputReaderBase.h"
 #include "include/UnwantedInteractionBlockerInterface.h"
 
@@ -52,10 +52,11 @@
  *    this could be a palm on the screen. This stage would alter the event stream to remove either
  *    partially (some of the pointers) or fully (all touches) the unwanted interaction. The events
  *    are processed on the InputReader thread, without any additional queue. The events are then
- *    posted to the queue managed by the InputClassifier.
- * 3. The InputClassifier class starts a thread to communicate with the device-specific
- *    classifiers. It then waits on the queue of events from UnwantedInteractionBlocker, applies
- *    a classification to them, and queues them for the InputDispatcher.
+ *    posted to the queue managed by the InputProcessor.
+ * 3. The InputProcessor class starts a thread to communicate with the device-specific
+ *    IInputProcessor HAL. It then waits on the queue of events from UnwantedInteractionBlocker,
+ *    processes the events (for example, applies a classification to the events), and queues them
+ *    for the InputDispatcher.
  * 4. The InputDispatcher class starts a thread that waits for new events on the
  *    previous queue and asynchronously dispatches them to applications.
  *
@@ -83,13 +84,16 @@
     virtual InputReaderInterface& getReader() = 0;
 
     /* Gets the unwanted interaction blocker. */
-    virtual UnwantedInteractionBlockerInterface& getUnwantedInteractionBlocker() = 0;
+    virtual UnwantedInteractionBlockerInterface& getBlocker() = 0;
 
-    /* Gets the input classifier */
-    virtual InputClassifierInterface& getClassifier() = 0;
+    /* Gets the input processor */
+    virtual InputProcessorInterface& getProcessor() = 0;
 
     /* Gets the input dispatcher. */
     virtual InputDispatcherInterface& getDispatcher() = 0;
+
+    /* Check that the input stages have not deadlocked. */
+    virtual void monitor() = 0;
 };
 
 class InputManager : public InputManagerInterface, public BnInputFlinger {
@@ -105,9 +109,10 @@
     status_t stop() override;
 
     InputReaderInterface& getReader() override;
-    UnwantedInteractionBlockerInterface& getUnwantedInteractionBlocker() override;
-    InputClassifierInterface& getClassifier() override;
+    UnwantedInteractionBlockerInterface& getBlocker() override;
+    InputProcessorInterface& getProcessor() override;
     InputDispatcherInterface& getDispatcher() override;
+    void monitor() override;
 
     status_t dump(int fd, const Vector<String16>& args) override;
     binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
@@ -117,9 +122,9 @@
 private:
     std::unique_ptr<InputReaderInterface> mReader;
 
-    std::unique_ptr<UnwantedInteractionBlockerInterface> mUnwantedInteractionBlocker;
+    std::unique_ptr<UnwantedInteractionBlockerInterface> mBlocker;
 
-    std::unique_ptr<InputClassifierInterface> mClassifier;
+    std::unique_ptr<InputProcessorInterface> mProcessor;
 
     std::unique_ptr<InputDispatcherInterface> mDispatcher;
 };
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputProcessor.cpp
similarity index 75%
rename from services/inputflinger/InputClassifier.cpp
rename to services/inputflinger/InputProcessor.cpp
index 3ea0986..0749441 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputProcessor.cpp
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "InputClassifier"
+#define LOG_TAG "InputProcessor"
 
-#include "InputClassifier.h"
+#include "InputProcessor.h"
 #include "InputCommonConverter.h"
 
 #include <android-base/stringprintf.h>
@@ -27,7 +27,7 @@
 #include <algorithm>
 #include <cmath>
 #if defined(__linux__)
-    #include <pthread.h>
+#include <pthread.h>
 #endif
 #include <unordered_set>
 
@@ -44,10 +44,10 @@
 
 namespace android {
 
-//Max number of elements to store in mEvents.
+// Max number of elements to store in mEvents.
 static constexpr size_t MAX_EVENTS = 5;
 
-template<class K, class V>
+template <class K, class V>
 static V getValueForKey(const std::unordered_map<K, V>& map, K key, V defaultValue) {
     auto it = map.find(key);
     if (it == map.end()) {
@@ -123,15 +123,15 @@
 
 // --- ClassifierEvent ---
 
-ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) :
-        type(ClassifierEventType::MOTION), args(std::move(args)) { };
-ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyDeviceResetArgs> args) :
-        type(ClassifierEventType::DEVICE_RESET), args(std::move(args)) { };
-ClassifierEvent::ClassifierEvent(ClassifierEventType type, std::unique_ptr<NotifyArgs> args) :
-        type(type), args(std::move(args)) { };
+ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args)
+      : type(ClassifierEventType::MOTION), args(std::move(args)){};
+ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyDeviceResetArgs> args)
+      : type(ClassifierEventType::DEVICE_RESET), args(std::move(args)){};
+ClassifierEvent::ClassifierEvent(ClassifierEventType type, std::unique_ptr<NotifyArgs> args)
+      : type(type), args(std::move(args)){};
 
-ClassifierEvent::ClassifierEvent(ClassifierEvent&& other) :
-        type(other.type), args(std::move(other.args)) { };
+ClassifierEvent::ClassifierEvent(ClassifierEvent&& other)
+      : type(other.type), args(std::move(other.args)){};
 
 ClassifierEvent& ClassifierEvent::operator=(ClassifierEvent&& other) {
     type = other.type;
@@ -180,7 +180,7 @@
     mHalThread = std::thread(&MotionClassifier::processEvents, this);
 #if defined(__linux__)
     // Set the thread name for debugging
-    pthread_setname_np(mHalThread.native_handle(), "InputClassifier");
+    pthread_setname_np(mHalThread.native_handle(), "InputProcessor");
 #endif
 }
 
@@ -198,7 +198,7 @@
 
 /**
  * Obtain the classification from the HAL for a given MotionEvent.
- * Should only be called from the InputClassifier thread (mHalThread).
+ * Should only be called from the InputProcessor thread (mHalThread).
  * Should not be called from the thread that notifyMotion runs on.
  *
  * There is no way to provide a timeout for a HAL call. So if the HAL takes too long
@@ -239,8 +239,8 @@
             }
         }
         if (!halResponseOk) {
-            ALOGE("Error communicating with InputClassifier HAL. "
-                    "Exiting MotionClassifier HAL thread");
+            ALOGE("Error communicating with InputProcessor HAL. "
+                  "Exiting MotionClassifier HAL thread");
             clearClassifications();
             return;
         }
@@ -262,14 +262,14 @@
 }
 
 void MotionClassifier::updateClassification(int32_t deviceId, nsecs_t eventTime,
-        MotionClassification classification) {
+                                            MotionClassification classification) {
     std::scoped_lock lock(mLock);
     const nsecs_t lastDownTime = getValueForKey(mLastDownTimes, deviceId, static_cast<nsecs_t>(0));
     if (eventTime < lastDownTime) {
         // HAL just finished processing an event that belonged to an earlier gesture,
         // but new gesture is already in progress. Drop this classification.
         ALOGW("Received late classification. Late by at least %" PRId64 " ms.",
-                nanoseconds_to_milliseconds(lastDownTime - eventTime));
+              nanoseconds_to_milliseconds(lastDownTime - eventTime));
         return;
     }
     mClassifications[deviceId] = classification;
@@ -319,66 +319,66 @@
 
 /**
  * Per-device reset. Clear the outstanding events that are going to be sent to HAL.
- * Request InputClassifier thread to call resetDevice for this particular device.
+ * Request InputProcessor thread to call resetDevice for this particular device.
  */
 void MotionClassifier::reset(const NotifyDeviceResetArgs& args) {
     int32_t deviceId = args.deviceId;
     // Clear the pending events right away, to avoid unnecessary work done by the HAL.
     mEvents.erase([deviceId](const ClassifierEvent& event) {
-            std::optional<int32_t> eventDeviceId = event.getDeviceId();
-            return eventDeviceId && (*eventDeviceId == deviceId);
+        std::optional<int32_t> eventDeviceId = event.getDeviceId();
+        return eventDeviceId && (*eventDeviceId == deviceId);
     });
     enqueueEvent(std::make_unique<NotifyDeviceResetArgs>(args));
 }
 
-const char* MotionClassifier::getServiceStatus() REQUIRES(mLock) {
-    if (!mService) {
-        return "null";
-    }
-
-    if (AIBinder_ping(mService->asBinder().get()) == STATUS_OK) {
-        return "running";
-    }
-    return "not responding";
-}
-
 void MotionClassifier::dump(std::string& dump) {
     std::scoped_lock lock(mLock);
-    dump += StringPrintf(INDENT2 "mService status: %s\n", getServiceStatus());
-    dump += StringPrintf(INDENT2 "mEvents: %zu element(s) (max=%zu)\n",
-            mEvents.size(), MAX_EVENTS);
+    dump += StringPrintf(INDENT2 "mService connected: %s\n", mService ? "true" : "false");
+    dump += StringPrintf(INDENT2 "mEvents: %zu element(s) (max=%zu)\n", mEvents.size(), MAX_EVENTS);
     dump += INDENT2 "mClassifications, mLastDownTimes:\n";
     dump += INDENT3 "Device Id\tClassification\tLast down time";
     // Combine mClassifications and mLastDownTimes into a single table.
     // Create a superset of device ids.
     std::unordered_set<int32_t> deviceIds;
     std::for_each(mClassifications.begin(), mClassifications.end(),
-            [&deviceIds](auto pair){ deviceIds.insert(pair.first); });
+                  [&deviceIds](auto pair) { deviceIds.insert(pair.first); });
     std::for_each(mLastDownTimes.begin(), mLastDownTimes.end(),
-            [&deviceIds](auto pair){ deviceIds.insert(pair.first); });
-    for(int32_t deviceId : deviceIds) {
+                  [&deviceIds](auto pair) { deviceIds.insert(pair.first); });
+    for (int32_t deviceId : deviceIds) {
         const MotionClassification classification =
                 getValueForKey(mClassifications, deviceId, MotionClassification::NONE);
         const nsecs_t downTime = getValueForKey(mLastDownTimes, deviceId, static_cast<nsecs_t>(0));
-        dump += StringPrintf("\n" INDENT4 "%" PRId32 "\t%s\t%" PRId64,
-                deviceId, motionClassificationToString(classification), downTime);
+        dump += StringPrintf("\n" INDENT4 "%" PRId32 "\t%s\t%" PRId64, deviceId,
+                             motionClassificationToString(classification), downTime);
     }
 }
 
-// --- InputClassifier ---
+void MotionClassifier::monitor() {
+    std::scoped_lock lock(mLock);
+    if (mService) {
+        // Ping the HAL service to ensure it is alive and not blocked.
+        const binder_status_t status = AIBinder_ping(mService->asBinder().get());
+        if (status != STATUS_OK) {
+            ALOGW("IInputProcessor HAL is not responding; binder ping result: %s",
+                  AStatus_getDescription(AStatus_fromStatus(status)));
+        }
+    }
+}
 
-InputClassifier::InputClassifier(InputListenerInterface& listener) : mListener(listener) {}
+// --- InputProcessor ---
 
-void InputClassifier::onBinderDied(void* cookie) {
-    InputClassifier* classifier = static_cast<InputClassifier*>(cookie);
-    if (classifier == nullptr) {
+InputProcessor::InputProcessor(InputListenerInterface& listener) : mQueuedListener(listener) {}
+
+void InputProcessor::onBinderDied(void* cookie) {
+    InputProcessor* processor = static_cast<InputProcessor*>(cookie);
+    if (processor == nullptr) {
         LOG_ALWAYS_FATAL("Cookie is not valid");
         return;
     }
-    classifier->setMotionClassifierEnabled(false);
+    processor->setMotionClassifierEnabled(false);
 }
 
-void InputClassifier::setMotionClassifierEnabled(bool enabled) {
+void InputProcessor::setMotionClassifierEnabled(bool enabled) {
     std::scoped_lock lock(mLock);
     if (enabled) {
         ALOGI("Enabling motion classifier");
@@ -391,7 +391,7 @@
                  * and we can't continue because 'mInitializeMotionClassifier' will block in its
                  * destructor.
                  */
-                LOG_ALWAYS_FATAL("The thread to load IInputClassifier is stuck!");
+                LOG_ALWAYS_FATAL("The thread to load IInputProcessor is stuck!");
             }
         }
         mInitializeMotionClassifier = std::async(std::launch::async, [this] {
@@ -415,60 +415,72 @@
     }
 }
 
-void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
+void InputProcessor::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
     // pass through
-    mListener.notifyConfigurationChanged(args);
+    mQueuedListener.notifyConfigurationChanged(args);
+    mQueuedListener.flush();
 }
 
-void InputClassifier::notifyKey(const NotifyKeyArgs* args) {
+void InputProcessor::notifyKey(const NotifyKeyArgs* args) {
     // pass through
-    mListener.notifyKey(args);
+    mQueuedListener.notifyKey(args);
+    mQueuedListener.flush();
 }
 
-void InputClassifier::notifyMotion(const NotifyMotionArgs* args) {
-    std::scoped_lock lock(mLock);
-    // MotionClassifier is only used for touch events, for now
-    const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(*args);
-    if (!sendToMotionClassifier) {
-        mListener.notifyMotion(args);
-        return;
-    }
-
-    NotifyMotionArgs newArgs(*args);
-    newArgs.classification = mMotionClassifier->classify(newArgs);
-    mListener.notifyMotion(&newArgs);
+void InputProcessor::notifyMotion(const NotifyMotionArgs* args) {
+    { // acquire lock
+        std::scoped_lock lock(mLock);
+        // MotionClassifier is only used for touch events, for now
+        const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(*args);
+        if (!sendToMotionClassifier) {
+            mQueuedListener.notifyMotion(args);
+        } else {
+            NotifyMotionArgs newArgs(*args);
+            newArgs.classification = mMotionClassifier->classify(newArgs);
+            mQueuedListener.notifyMotion(&newArgs);
+        }
+    } // release lock
+    mQueuedListener.flush();
 }
 
-void InputClassifier::notifySensor(const NotifySensorArgs* args) {
+void InputProcessor::notifySensor(const NotifySensorArgs* args) {
     // pass through
-    mListener.notifySensor(args);
+    mQueuedListener.notifySensor(args);
+    mQueuedListener.flush();
 }
 
-void InputClassifier::notifyVibratorState(const NotifyVibratorStateArgs* args) {
+void InputProcessor::notifyVibratorState(const NotifyVibratorStateArgs* args) {
     // pass through
-    mListener.notifyVibratorState(args);
+    mQueuedListener.notifyVibratorState(args);
+    mQueuedListener.flush();
 }
 
-void InputClassifier::notifySwitch(const NotifySwitchArgs* args) {
+void InputProcessor::notifySwitch(const NotifySwitchArgs* args) {
     // pass through
-    mListener.notifySwitch(args);
+    mQueuedListener.notifySwitch(args);
+    mQueuedListener.flush();
 }
 
-void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
-    std::scoped_lock lock(mLock);
-    if (mMotionClassifier) {
-        mMotionClassifier->reset(*args);
-    }
+void InputProcessor::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
+    { // acquire lock
+        std::scoped_lock lock(mLock);
+        if (mMotionClassifier) {
+            mMotionClassifier->reset(*args);
+        }
+    } // release lock
+
     // continue to next stage
-    mListener.notifyDeviceReset(args);
+    mQueuedListener.notifyDeviceReset(args);
+    mQueuedListener.flush();
 }
 
-void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+void InputProcessor::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
     // pass through
-    mListener.notifyPointerCaptureChanged(args);
+    mQueuedListener.notifyPointerCaptureChanged(args);
+    mQueuedListener.flush();
 }
 
-void InputClassifier::setMotionClassifierLocked(
+void InputProcessor::setMotionClassifierLocked(
         std::unique_ptr<MotionClassifierInterface> motionClassifier) REQUIRES(mLock) {
     if (motionClassifier == nullptr) {
         // Destroy the ScopedDeathRecipient object, which will cause it to unlinkToDeath.
@@ -478,9 +490,9 @@
     mMotionClassifier = std::move(motionClassifier);
 }
 
-void InputClassifier::dump(std::string& dump) {
+void InputProcessor::dump(std::string& dump) {
     std::scoped_lock lock(mLock);
-    dump += "Input Classifier State:\n";
+    dump += "Input Processor State:\n";
     dump += INDENT1 "Motion Classifier:\n";
     if (mMotionClassifier) {
         mMotionClassifier->dump(dump);
@@ -490,7 +502,11 @@
     dump += "\n";
 }
 
-InputClassifier::~InputClassifier() {
+void InputProcessor::monitor() {
+    std::scoped_lock lock(mLock);
+    if (mMotionClassifier) mMotionClassifier->monitor();
 }
 
+InputProcessor::~InputProcessor() {}
+
 } // namespace android
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputProcessor.h
similarity index 85%
rename from services/inputflinger/InputClassifier.h
rename to services/inputflinger/InputProcessor.h
index e2a0bc2..261e012 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputProcessor.h
@@ -61,8 +61,8 @@
  */
 class MotionClassifierInterface {
 public:
-    MotionClassifierInterface() { }
-    virtual ~MotionClassifierInterface() { }
+    MotionClassifierInterface() {}
+    virtual ~MotionClassifierInterface() {}
     /**
      * Based on the motion event described by NotifyMotionArgs,
      * provide a MotionClassification for the current gesture.
@@ -78,16 +78,21 @@
     virtual void reset(const NotifyDeviceResetArgs& args) = 0;
 
     /**
-     * Dump the state of the motion classifier
+     * Dump the state of the motion classifier.
      */
     virtual void dump(std::string& dump) = 0;
+
+    /**
+     * Called by the heartbeat to ensure the HAL is still processing normally.
+     */
+    virtual void monitor() = 0;
 };
 
 /**
  * Base interface for an InputListener stage.
  * Provides classification to events.
  */
-class InputClassifierInterface : public InputListenerInterface {
+class InputProcessorInterface : public InputListenerInterface {
 public:
     virtual void setMotionClassifierEnabled(bool enabled) = 0;
     /**
@@ -96,8 +101,11 @@
      */
     virtual void dump(std::string& dump) = 0;
 
-    InputClassifierInterface() { }
-    virtual ~InputClassifierInterface() { }
+    /** Called by the heartbeat to ensure that the classifier has not deadlocked. */
+    virtual void monitor() = 0;
+
+    InputProcessorInterface() {}
+    virtual ~InputProcessorInterface() {}
 };
 
 // --- Implementations ---
@@ -116,10 +124,10 @@
 };
 
 /**
- * Implementation of MotionClassifierInterface that calls the InputClassifier HAL
+ * Implementation of MotionClassifierInterface that calls the InputProcessor HAL
  * in order to determine the classification for the current gesture.
  *
- * The InputClassifier HAL may keep track of the entire gesture in order to determine
+ * The InputProcessor HAL may keep track of the entire gesture in order to determine
  * the classification, and may be hardware-specific. It may use the data in
  * NotifyMotionArgs::videoFrames field to drive the classification decisions.
  * The HAL is called from a separate thread.
@@ -152,33 +160,34 @@
     virtual void reset(const NotifyDeviceResetArgs& args) override;
 
     virtual void dump(std::string& dump) override;
+    virtual void monitor() override;
 
 private:
     friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation
     explicit MotionClassifier(
             std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service);
 
-    // The events that need to be sent to the HAL.
+    /** The events that need to be sent to the HAL. */
     BlockingQueue<ClassifierEvent> mEvents;
     /**
      * Add an event to the queue mEvents.
      */
     void enqueueEvent(ClassifierEvent&& event);
     /**
-     * Thread that will communicate with InputClassifier HAL.
-     * This should be the only thread that communicates with InputClassifier HAL,
+     * Thread that will communicate with InputProcessor HAL.
+     * This should be the only thread that communicates with InputProcessor HAL,
      * because this thread is allowed to block on the HAL calls.
      */
     std::thread mHalThread;
     /**
-     * Process events and call the InputClassifier HAL
+     * Process events and call the InputProcessor HAL
      */
     void processEvents();
     /**
      * Access to the InputProcessor HAL. May be null if init() hasn't completed yet.
      * When init() successfully completes, mService is guaranteed to remain non-null and to not
      * change its value until MotionClassifier is destroyed.
-     * This variable is *not* guarded by mLock in the InputClassifier thread, because
+     * This variable is *not* guarded by mLock in the InputProcessor thread, because
      * that thread knows exactly when this variable is initialized.
      * When accessed in any other thread, mService is checked for nullness with a lock.
      */
@@ -188,8 +197,8 @@
      * Per-device input classifications. Should only be accessed using the
      * getClassification / setClassification methods.
      */
-    std::unordered_map<int32_t /*deviceId*/, MotionClassification>
-            mClassifications GUARDED_BY(mLock);
+    std::unordered_map<int32_t /*deviceId*/, MotionClassification> mClassifications
+            GUARDED_BY(mLock);
     /**
      * Set the current classification for a given device.
      */
@@ -199,7 +208,7 @@
      */
     MotionClassification getClassification(int32_t deviceId);
     void updateClassification(int32_t deviceId, nsecs_t eventTime,
-            MotionClassification classification);
+                              MotionClassification classification);
     /**
      * Clear all current classifications
      */
@@ -208,7 +217,7 @@
      * Per-device times when the last ACTION_DOWN was received.
      * Used to reject late classifications that do not belong to the current gesture.
      *
-     * Accessed indirectly by both InputClassifier thread and the thread that receives notifyMotion.
+     * Accessed indirectly by both InputProcessor thread and the thread that receives notifyMotion.
      */
     std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/> mLastDownTimes GUARDED_BY(mLock);
 
@@ -217,7 +226,7 @@
     void clearDeviceState(int32_t deviceId);
 
     /**
-     * Exit the InputClassifier HAL thread.
+     * Exit the InputProcessor HAL thread.
      * Useful for tests to ensure proper cleanup.
      */
     void requestExit();
@@ -228,14 +237,14 @@
 };
 
 /**
- * Implementation of the InputClassifierInterface.
+ * Implementation of the InputProcessorInterface.
  * Represents a separate stage of input processing. All of the input events go through this stage.
  * Acts as a passthrough for all input events except for motion events.
  * The events of motion type are sent to MotionClassifier.
  */
-class InputClassifier : public InputClassifierInterface {
+class InputProcessor : public InputProcessorInterface {
 public:
-    explicit InputClassifier(InputListenerInterface& listener);
+    explicit InputProcessor(InputListenerInterface& listener);
 
     void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
     void notifyKey(const NotifyKeyArgs* args) override;
@@ -247,8 +256,9 @@
     void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
     void dump(std::string& dump) override;
+    void monitor() override;
 
-    ~InputClassifier();
+    ~InputProcessor();
 
     // Called from InputManager
     void setMotionClassifierEnabled(bool enabled) override;
@@ -257,7 +267,7 @@
     // Protect access to mMotionClassifier, since it may become null via a hidl callback
     std::mutex mLock;
     // The next stage to pass input events to
-    InputListenerInterface& mListener;
+    QueuedInputListener mQueuedListener;
 
     std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock);
     std::future<void> mInitializeMotionClassifier GUARDED_BY(mLock);
diff --git a/services/inputflinger/InputThread.cpp b/services/inputflinger/InputThread.cpp
index b87f7a1..e2e64f9 100644
--- a/services/inputflinger/InputThread.cpp
+++ b/services/inputflinger/InputThread.cpp
@@ -41,7 +41,7 @@
 
 InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake)
       : mName(name), mThreadWake(wake) {
-    mThread = new InputThreadImpl(loop);
+    mThread = sp<InputThreadImpl>::make(loop);
     mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
 }
 
diff --git a/services/inputflinger/OWNERS b/services/inputflinger/OWNERS
index 82c6ee1..c88bfe9 100644
--- a/services/inputflinger/OWNERS
+++ b/services/inputflinger/OWNERS
@@ -1,3 +1 @@
-lzye@google.com
-michaelwr@google.com
-svv@google.com
+include platform/frameworks/base:/INPUT_OWNERS
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index 9b72ff4..f673a28 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -24,6 +24,14 @@
       "name": "libinputservice_test"
     },
     {
+      "name": "CtsHardwareTestCases",
+      "options": [
+        {
+          "include-filter": "android.hardware.input.cts.tests"
+        }
+      ]
+    },
+    {
       "name": "CtsInputTestCases"
     },
     {
@@ -31,11 +39,20 @@
       "options": [
         {
           "include-filter": "android.view.cts.MotionEventTest",
+          "include-filter": "android.view.cts.PointerCaptureTest",
           "include-filter": "android.view.cts.VerifyInputEventTest"
         }
       ]
     },
     {
+      "name": "CtsWidgetTestCases",
+      "options": [
+        {
+          "include-filter": "android.widget.cts.NumberPickerTest"
+        }
+      ]
+    },
+    {
       "name": "FrameworksCoreTests",
       "options": [
         {
@@ -45,6 +62,101 @@
       ]
     },
     {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.input"
+        }
+      ]
+    },
+    {
+      "name": "CtsSecurityTestCases",
+      "options": [
+        {
+          "include-filter": "android.security.cts.MotionEventTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsSecurityBulletinHostTestCases",
+      "options": [
+        {
+          "include-filter": "android.security.cts.Poc19_03#testPocBug_115739809"
+        }
+      ]
+    }
+  ],
+  "hwasan-postsubmit": [
+    {
+      "name": "CtsWindowManagerDeviceTestCases",
+      "options": [
+        {
+          "include-filter": "android.server.wm.WindowInputTests"
+        }
+      ]
+    },
+    {
+      "name": "libinput_tests"
+    },
+    {
+      "name": "inputflinger_tests"
+    },
+    {
+      "name": "libpalmrejection_test"
+    },
+    {
+      "name": "InputTests"
+    },
+    {
+      "name": "libinputservice_test"
+    },
+    {
+      "name": "CtsHardwareTestCases",
+      "options": [
+        {
+          "include-filter": "android.hardware.input.cts.tests"
+        }
+      ]
+    },
+    {
+      "name": "CtsInputTestCases"
+    },
+    {
+      "name": "CtsViewTestCases",
+      "options": [
+        {
+          "include-filter": "android.view.cts.MotionEventTest",
+          "include-filter": "android.view.cts.PointerCaptureTest",
+          "include-filter": "android.view.cts.VerifyInputEventTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsWidgetTestCases",
+      "options": [
+        {
+          "include-filter": "android.widget.cts.NumberPickerTest"
+        }
+      ]
+    },
+    {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "include-filter": "android.view.VerifiedKeyEventTest",
+          "include-filter": "android.view.VerifiedMotionEventTest"
+        }
+      ]
+    },
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.input"
+        }
+      ]
+    },
+    {
       "name": "CtsSecurityTestCases",
       "options": [
         {
diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp
index b69e16a..4e0f0c3 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.cpp
+++ b/services/inputflinger/UnwantedInteractionBlocker.cpp
@@ -18,6 +18,7 @@
 #include "UnwantedInteractionBlocker.h"
 
 #include <android-base/stringprintf.h>
+#include <input/PrintTools.h>
 #include <inttypes.h>
 #include <linux/input-event-codes.h>
 #include <linux/input.h>
@@ -28,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";
 /**
@@ -49,8 +82,7 @@
 }
 
 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);
 }
 
 /**
@@ -60,8 +92,8 @@
 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;
@@ -80,62 +112,6 @@
     return MT_TOOL_FINGER;
 }
 
-static std::string addPrefix(std::string str, const std::string& prefix) {
-    std::stringstream ss;
-    bool newLineStarted = true;
-    for (const auto& ch : str) {
-        if (newLineStarted) {
-            ss << prefix;
-            newLineStarted = false;
-        }
-        if (ch == '\n') {
-            newLineStarted = true;
-        }
-        ss << ch;
-    }
-    return ss.str();
-}
-
-template <typename T>
-static std::string dumpSet(const std::set<T>& v) {
-    static_assert(std::is_integral<T>::value, "Only integral types can be printed.");
-    std::string out;
-    for (const T& entry : v) {
-        out += out.empty() ? "{" : ", ";
-        out += android::base::StringPrintf("%i", entry);
-    }
-    return out.empty() ? "{}" : (out + "}");
-}
-
-template <typename K, typename V>
-static std::string dumpMap(const std::map<K, V>& map) {
-    static_assert(std::is_integral<K>::value, "Keys should have integral type to be printed.");
-    static_assert(std::is_integral<V>::value, "Values should have integral type to be printed.");
-    std::string out;
-    for (const auto& [k, v] : map) {
-        if (!out.empty()) {
-            out += "\n";
-        }
-        out += android::base::StringPrintf("%i : %i", static_cast<int>(k), static_cast<int>(v));
-    }
-    return out;
-}
-
-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;
-}
-
 static int32_t getActionUpForPointerId(const NotifyMotionArgs& args, int32_t pointerId) {
     for (size_t i = 0; i < args.pointerCount; i++) {
         if (pointerId == args.pointerProperties[i].id) {
@@ -168,19 +144,6 @@
     return AMOTION_EVENT_ACTION_MOVE;
 }
 
-static const char* toString(bool value) {
-    return value ? "true" : "false";
-}
-
-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.
@@ -356,69 +319,93 @@
 
 UnwantedInteractionBlocker::UnwantedInteractionBlocker(InputListenerInterface& listener,
                                                        bool enablePalmRejection)
-      : mListener(listener), mEnablePalmRejection(enablePalmRejection) {}
+      : mQueuedListener(listener), mEnablePalmRejection(enablePalmRejection) {}
 
 void UnwantedInteractionBlocker::notifyConfigurationChanged(
         const NotifyConfigurationChangedArgs* args) {
-    mListener.notifyConfigurationChanged(args);
+    mQueuedListener.notifyConfigurationChanged(args);
+    mQueuedListener.flush();
 }
 
 void UnwantedInteractionBlocker::notifyKey(const NotifyKeyArgs* args) {
-    mListener.notifyKey(args);
+    mQueuedListener.notifyKey(args);
+    mQueuedListener.flush();
 }
 
 void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) {
-    const std::vector<NotifyMotionArgs> processedArgs =
-            mPreferStylusOverTouchBlocker.processMotion(*args);
-    for (const NotifyMotionArgs& loopArgs : processedArgs) {
-        notifyMotionInner(&loopArgs);
-    }
+    ALOGD_IF(DEBUG_INBOUND_MOTION, "%s: %s", __func__, args->dump().c_str());
+    { // acquire lock
+        std::scoped_lock lock(mLock);
+        const std::vector<NotifyMotionArgs> processedArgs =
+                mPreferStylusOverTouchBlocker.processMotion(*args);
+        for (const NotifyMotionArgs& loopArgs : processedArgs) {
+            notifyMotionLocked(&loopArgs);
+        }
+    } // release lock
+
+    // Call out to the next stage without holding the lock
+    mQueuedListener.flush();
 }
 
-void UnwantedInteractionBlocker::notifyMotionInner(const NotifyMotionArgs* args) {
+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) {
-        mListener.notifyMotion(args);
+        enqueueOutboundMotionLocked(*args);
         return;
     }
 
-    const std::vector<NotifyMotionArgs> newMotions = it->second.processMotion(*args);
-    for (const NotifyMotionArgs& newArgs : newMotions) {
-        mListener.notifyMotion(&newArgs);
+    std::vector<NotifyMotionArgs> processedArgs = it->second.processMotion(*args);
+    for (const NotifyMotionArgs& loopArgs : processedArgs) {
+        enqueueOutboundMotionLocked(loopArgs);
     }
 }
 
 void UnwantedInteractionBlocker::notifySwitch(const NotifySwitchArgs* args) {
-    mListener.notifySwitch(args);
+    mQueuedListener.notifySwitch(args);
+    mQueuedListener.flush();
 }
 
 void UnwantedInteractionBlocker::notifySensor(const NotifySensorArgs* args) {
-    mListener.notifySensor(args);
+    mQueuedListener.notifySensor(args);
+    mQueuedListener.flush();
 }
 
 void UnwantedInteractionBlocker::notifyVibratorState(const NotifyVibratorStateArgs* args) {
-    mListener.notifyVibratorState(args);
+    mQueuedListener.notifyVibratorState(args);
+    mQueuedListener.flush();
 }
 void UnwantedInteractionBlocker::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
-    auto it = mPalmRejectors.find(args->deviceId);
-    if (it != mPalmRejectors.end()) {
-        AndroidPalmFilterDeviceInfo info = it->second.getPalmFilterDeviceInfo();
-        // Re-create the object instead of resetting it
-        mPalmRejectors.erase(it);
-        mPalmRejectors.emplace(args->deviceId, info);
-    }
-    mListener.notifyDeviceReset(args);
-    mPreferStylusOverTouchBlocker.notifyDeviceReset(*args);
+    { // acquire lock
+        std::scoped_lock lock(mLock);
+        auto it = mPalmRejectors.find(args->deviceId);
+        if (it != mPalmRejectors.end()) {
+            AndroidPalmFilterDeviceInfo info = it->second.getPalmFilterDeviceInfo();
+            // Re-create the object instead of resetting it
+            mPalmRejectors.erase(it);
+            mPalmRejectors.emplace(args->deviceId, info);
+        }
+        mQueuedListener.notifyDeviceReset(args);
+        mPreferStylusOverTouchBlocker.notifyDeviceReset(*args);
+    } // release lock
+    // Send events to the next stage without holding the lock
+    mQueuedListener.flush();
 }
 
 void UnwantedInteractionBlocker::notifyPointerCaptureChanged(
         const NotifyPointerCaptureChangedArgs* args) {
-    mListener.notifyPointerCaptureChanged(args);
+    mQueuedListener.notifyPointerCaptureChanged(args);
+    mQueuedListener.flush();
 }
 
 void UnwantedInteractionBlocker::notifyInputDevicesChanged(
         const std::vector<InputDeviceInfo>& inputDevices) {
+    std::scoped_lock lock(mLock);
     if (!mEnablePalmRejection) {
         // Palm rejection is disabled. Don't create any palm rejector objects.
         return;
@@ -450,20 +437,24 @@
 }
 
 void UnwantedInteractionBlocker::dump(std::string& dump) {
+    std::scoped_lock lock(mLock);
     dump += "UnwantedInteractionBlocker:\n";
     dump += "  mPreferStylusOverTouchBlocker:\n";
-    dump += addPrefix(mPreferStylusOverTouchBlocker.dump(), "    ");
-    dump += StringPrintf("  mEnablePalmRejection: %s\n", toString(mEnablePalmRejection));
+    dump += addLinePrefix(mPreferStylusOverTouchBlocker.dump(), "    ");
+    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);
-        dump += addPrefix(palmRejector.dump(), "      ");
+        dump += addLinePrefix(palmRejector.dump(), "      ");
     }
 }
 
-void UnwantedInteractionBlocker::monitor() {}
+void UnwantedInteractionBlocker::monitor() {
+    std::scoped_lock lock(mLock);
+}
 
 UnwantedInteractionBlocker::~UnwantedInteractionBlocker() {}
 
@@ -529,12 +520,21 @@
 
 std::string SlotState::dump() const {
     std::string out = "mSlotsByPointerId:\n";
-    out += addPrefix(dumpMap(mSlotsByPointerId), "  ") + "\n";
+    out += addLinePrefix(dumpMap(mSlotsByPointerId), "  ") + "\n";
     out += "mPointerIdsBySlot:\n";
-    out += addPrefix(dumpMap(mPointerIdsBySlot), "  ") + "\n";
+    out += addLinePrefix(dumpMap(mPointerIdsBySlot), "  ") + "\n";
     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>()),
@@ -546,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,
@@ -648,8 +646,18 @@
             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> oldSuppressedIds;
     std::swap(oldSuppressedIds, mSuppressedPointerIds);
@@ -671,12 +679,13 @@
         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;
@@ -689,11 +698,21 @@
 std::string PalmRejector::dump() const {
     std::string out;
     out += "mDeviceInfo:\n";
-    out += addPrefix(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 += addPrefix(mSlotState.dump(), "  ");
+    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 8a1cd72..8ff9658 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.h
+++ b/services/inputflinger/UnwantedInteractionBlocker.h
@@ -19,6 +19,7 @@
 #include <map>
 #include <set>
 
+#include <android-base/thread_annotations.h>
 #include "include/UnwantedInteractionBlockerInterface.h"
 #include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter_util.h"
 #include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h"
@@ -86,18 +87,23 @@
     ~UnwantedInteractionBlocker();
 
 private:
+    std::mutex mLock;
     // The next stage to pass input events to
-    InputListenerInterface& mListener;
+
+    QueuedInputListener mQueuedListener;
     const bool mEnablePalmRejection;
 
     // When stylus is down, ignore touch
-    PreferStylusOverTouchBlocker mPreferStylusOverTouchBlocker;
+    PreferStylusOverTouchBlocker mPreferStylusOverTouchBlocker GUARDED_BY(mLock);
 
     // Detect and reject unwanted palms on screen
     // Use a separate palm rejector for every touch device.
-    std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors;
+    std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors GUARDED_BY(mLock);
     // TODO(b/210159205): delete this when simultaneous stylus and touch is supported
-    void notifyMotionInner(const NotifyMotionArgs* args);
+    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 {
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 32eec29..12eeea6 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -31,11 +31,11 @@
 namespace android::inputdispatcher {
 
 // An arbitrary device id.
-static const int32_t DEVICE_ID = 1;
+constexpr int32_t DEVICE_ID = 1;
 
-// An arbitrary injector pid / uid pair that has permission to inject events.
-static const int32_t INJECTOR_PID = 999;
-static const int32_t INJECTOR_UID = 1001;
+// The default pid and uid for windows created by the test.
+constexpr int32_t WINDOW_PID = 999;
+constexpr int32_t WINDOW_UID = 1001;
 
 static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s;
 static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms;
@@ -82,8 +82,6 @@
 
     void notifyVibratorState(int32_t deviceId, bool isOn) override {}
 
-    void notifyUntrustedTouch(const std::string& obscuringPackage) override {}
-
     void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override {
         *outConfig = mConfig;
     }
@@ -108,14 +106,14 @@
 
     void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
 
-    bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override { return false; }
-
     void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {}
 
     void setPointerCapture(const PointerCaptureRequest&) override {}
 
     void notifyDropWindow(const sp<IBinder>&, float x, float y) override {}
 
+    bool isPerDisplayTouchModeEnabled() override { return false; }
+
     InputDispatcherConfiguration mConfig;
 };
 
@@ -196,8 +194,8 @@
         mInfo.globalScaleFactor = 1.0;
         mInfo.touchableRegion.clear();
         mInfo.addTouchableRegion(mFrame);
-        mInfo.ownerPid = INJECTOR_PID;
-        mInfo.ownerUid = INJECTOR_UID;
+        mInfo.ownerPid = WINDOW_PID;
+        mInfo.ownerUid = WINDOW_UID;
         mInfo.displayId = ADISPLAY_ID_DEFAULT;
     }
 
@@ -262,14 +260,15 @@
 
 static void benchmarkNotifyMotion(benchmark::State& state) {
     // Create dispatcher
-    sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy();
+    sp<FakeInputDispatcherPolicy> fakePolicy = sp<FakeInputDispatcherPolicy>::make();
     InputDispatcher dispatcher(fakePolicy);
     dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
     dispatcher.start();
 
     // Create a window that will receive motion events
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window");
+    sp<FakeWindowHandle> window =
+            sp<FakeWindowHandle>::make(application, dispatcher, "Fake Window");
 
     dispatcher.setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
 
@@ -296,28 +295,29 @@
 
 static void benchmarkInjectMotion(benchmark::State& state) {
     // Create dispatcher
-    sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy();
+    sp<FakeInputDispatcherPolicy> fakePolicy = sp<FakeInputDispatcherPolicy>::make();
     InputDispatcher dispatcher(fakePolicy);
     dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
     dispatcher.start();
 
     // Create a window that will receive motion events
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window");
+    sp<FakeWindowHandle> window =
+            sp<FakeWindowHandle>::make(application, dispatcher, "Fake Window");
 
     dispatcher.setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
 
     for (auto _ : state) {
         MotionEvent event = generateMotionEvent();
         // Send ACTION_DOWN
-        dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                    InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
+        dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                    INJECT_EVENT_TIMEOUT,
                                     POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
 
         // Send ACTION_UP
         event.setAction(AMOTION_EVENT_ACTION_UP);
-        dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                    InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
+        dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                    INJECT_EVENT_TIMEOUT,
                                     POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
 
         window->consumeEvent();
@@ -329,14 +329,15 @@
 
 static void benchmarkOnWindowInfosChanged(benchmark::State& state) {
     // Create dispatcher
-    sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy();
+    sp<FakeInputDispatcherPolicy> fakePolicy = sp<FakeInputDispatcherPolicy>::make();
     InputDispatcher dispatcher(fakePolicy);
     dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
     dispatcher.start();
 
     // Create a window
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window");
+    sp<FakeWindowHandle> window =
+            sp<FakeWindowHandle>::make(application, dispatcher, "Fake Window");
 
     std::vector<gui::WindowInfo> windowInfos{*window->getInfo()};
     gui::DisplayInfo info;
diff --git a/services/inputflinger/dispatcher/CancelationOptions.h b/services/inputflinger/dispatcher/CancelationOptions.h
index 99e2108..fec5f83 100644
--- a/services/inputflinger/dispatcher/CancelationOptions.h
+++ b/services/inputflinger/dispatcher/CancelationOptions.h
@@ -17,9 +17,11 @@
 #ifndef _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H
 #define _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H
 
+#include <utils/BitSet.h>
 #include <optional>
 
-namespace android::inputdispatcher {
+namespace android {
+namespace inputdispatcher {
 
 /* Specifies which events are to be canceled and why. */
 struct CancelationOptions {
@@ -45,9 +47,13 @@
     // The specific display id of events to cancel, or nullopt to cancel events on any display.
     std::optional<int32_t> displayId = std::nullopt;
 
+    // The specific pointers to cancel, or nullopt to cancel all pointer events
+    std::optional<BitSet32> pointerIds = std::nullopt;
+
     CancelationOptions(Mode mode, const char* reason) : mode(mode), reason(reason) {}
 };
 
-} // namespace android::inputdispatcher
+} // namespace inputdispatcher
+} // namespace android
 
 #endif // _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H
diff --git a/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h
new file mode 100644
index 0000000..4f8995f
--- /dev/null
+++ b/services/inputflinger/dispatcher/DebugConfig.h
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#ifndef _UI_INPUT_DISPATCHER_DEBUG_CONFIG_H
+#define _UI_INPUT_DISPATCHER_DEBUG_CONFIG_H
+
+#define LOG_TAG "InputDispatcher"
+
+#include <log/log.h>
+#include <log/log_event_list.h>
+
+namespace android::inputdispatcher {
+/**
+ * Log detailed debug messages about each inbound event notification to the dispatcher.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherInboundEvent DEBUG" (requires restart)
+ */
+const bool DEBUG_INBOUND_EVENT_DETAILS =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "InboundEvent", ANDROID_LOG_INFO);
+
+/**
+ * Log detailed debug messages about each outbound event processed by the dispatcher.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherOutboundEvent DEBUG" (requires restart)
+ */
+const bool DEBUG_OUTBOUND_EVENT_DETAILS =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "OutboundEvent", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about the dispatch cycle.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherDispatchCycle DEBUG" (requires restart)
+ */
+const bool DEBUG_DISPATCH_CYCLE =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "DispatchCycle", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about channel creation
+ * Enable this via "adb shell setprop log.tag.InputDispatcherChannelCreation DEBUG" (requires
+ * restart)
+ */
+const bool DEBUG_CHANNEL_CREATION =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "ChannelCreation", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about input event injection.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherInjection DEBUG" (requires restart)
+ */
+const bool DEBUG_INJECTION =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Injection", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about input focus tracking.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherFocus DEBUG" (requires restart)
+ */
+const bool DEBUG_FOCUS =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Focus", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about touch mode event
+ * Enable this via "adb shell setprop log.tag.InputDispatcherTouchMode DEBUG" (requires restart)
+ */
+const bool DEBUG_TOUCH_MODE =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "TouchMode", ANDROID_LOG_INFO);
+
+/**
+ * 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);
+
+/**
+ * Log debug messages about the app switch latency optimization.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherAppSwitch DEBUG" (requires restart)
+ */
+const bool DEBUG_APP_SWITCH =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "AppSwitch", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about hover events.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherHover DEBUG" (requires restart)
+ */
+const bool DEBUG_HOVER =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Hover", ANDROID_LOG_INFO);
+} // namespace android::inputdispatcher
+
+#endif // _UI_INPUT_DISPATCHER_DEBUG_CONFIG_H
\ No newline at end of file
diff --git a/services/inputflinger/dispatcher/DragState.h b/services/inputflinger/dispatcher/DragState.h
index 4636820..d1c8b8a 100644
--- a/services/inputflinger/dispatcher/DragState.h
+++ b/services/inputflinger/dispatcher/DragState.h
@@ -26,7 +26,8 @@
 namespace inputdispatcher {
 
 struct DragState {
-    DragState(const sp<android::gui::WindowInfoHandle>& windowHandle) : dragWindow(windowHandle) {}
+    DragState(const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t pointerId)
+          : dragWindow(windowHandle), pointerId(pointerId) {}
     void dump(std::string& dump, const char* prefix = "");
 
     // The window being dragged.
@@ -37,6 +38,8 @@
     bool isStartDrag = false;
     // Indicate if the stylus button is down at the start of the drag.
     bool isStylusButtonDownAtStart = false;
+    // Indicate which pointer id is tracked by the drag and drop.
+    const int32_t pointerId;
 };
 
 } // namespace inputdispatcher
diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp
index a02b3e8..85dcf8f 100644
--- a/services/inputflinger/dispatcher/FocusResolver.cpp
+++ b/services/inputflinger/dispatcher/FocusResolver.cpp
@@ -13,24 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-#define LOG_TAG "FocusResolver"
+#define LOG_TAG "InputDispatcher"
 #define ATRACE_TAG ATRACE_TAG_INPUT
 
 #define INDENT "  "
 #define INDENT2 "    "
 
-// Log debug messages about input focus tracking.
-static constexpr bool DEBUG_FOCUS = false;
-
 #include <inttypes.h>
 
 #include <android-base/stringprintf.h>
 #include <binder/Binder.h>
 #include <ftl/enum.h>
 #include <gui/WindowInfo.h>
-#include <log/log.h>
 
+#include "DebugConfig.h"
 #include "FocusResolver.h"
 
 using android::gui::FocusRequest;
@@ -43,7 +39,7 @@
     return it != mFocusedWindowTokenByDisplay.end() ? it->second.second : nullptr;
 }
 
-std::optional<FocusRequest> FocusResolver::getFocusRequest(int32_t displayId) {
+std::optional<FocusRequest> FocusResolver::getFocusRequest(int32_t displayId) const {
     auto it = mFocusRequestByDisplay.find(displayId);
     return it != mFocusRequestByDisplay.end() ? std::make_optional<>(it->second) : std::nullopt;
 }
diff --git a/services/inputflinger/dispatcher/FocusResolver.h b/services/inputflinger/dispatcher/FocusResolver.h
index 6d11a77..8a6dfa4 100644
--- a/services/inputflinger/dispatcher/FocusResolver.h
+++ b/services/inputflinger/dispatcher/FocusResolver.h
@@ -62,6 +62,7 @@
     std::optional<FocusResolver::FocusChanges> setFocusedWindow(
             const android::gui::FocusRequest& request,
             const std::vector<sp<android::gui::WindowInfoHandle>>& windows);
+    std::optional<android::gui::FocusRequest> getFocusRequest(int32_t displayId) const;
 
     // Display has been removed from the system, clean up old references.
     void displayRemoved(int32_t displayId);
@@ -112,7 +113,6 @@
     std::optional<FocusResolver::FocusChanges> updateFocusedWindow(
             int32_t displayId, const std::string& reason, const sp<IBinder>& token,
             const std::string& tokenName = "");
-    std::optional<android::gui::FocusRequest> getFocusRequest(int32_t displayId);
 };
 
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InjectionState.cpp b/services/inputflinger/dispatcher/InjectionState.cpp
index c8024a6..c2d3ad6 100644
--- a/services/inputflinger/dispatcher/InjectionState.cpp
+++ b/services/inputflinger/dispatcher/InjectionState.cpp
@@ -20,10 +20,9 @@
 
 namespace android::inputdispatcher {
 
-InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid)
+InjectionState::InjectionState(const std::optional<int32_t>& targetUid)
       : refCount(1),
-        injectorPid(injectorPid),
-        injectorUid(injectorUid),
+        targetUid(targetUid),
         injectionResult(android::os::InputEventInjectionResult::PENDING),
         injectionIsAsync(false),
         pendingForegroundDispatches(0) {}
diff --git a/services/inputflinger/dispatcher/InjectionState.h b/services/inputflinger/dispatcher/InjectionState.h
index 0bfafb1..90cf150 100644
--- a/services/inputflinger/dispatcher/InjectionState.h
+++ b/services/inputflinger/dispatcher/InjectionState.h
@@ -27,13 +27,12 @@
 struct InjectionState {
     mutable int32_t refCount;
 
-    int32_t injectorPid;
-    int32_t injectorUid;
+    std::optional<int32_t> targetUid;
     android::os::InputEventInjectionResult injectionResult; // initially PENDING
     bool injectionIsAsync;               // set to true if injection is not waiting for the result
     int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress
 
-    InjectionState(int32_t injectorPid, int32_t injectorUid);
+    explicit InjectionState(const std::optional<int32_t>& targetUid);
     void release();
 
 private:
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 1cc4589..b52e312 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -27,8 +27,6 @@
 #include <ftl/enum.h>
 #include <gui/SurfaceComposerClient.h>
 #include <input/InputDevice.h>
-#include <log/log.h>
-#include <log/log_event_list.h>
 #include <powermanager/PowerManager.h>
 #include <unistd.h>
 #include <utils/Trace.h>
@@ -42,6 +40,7 @@
 #include <sstream>
 
 #include "Connection.h"
+#include "DebugConfig.h"
 #include "InputDispatcher.h"
 
 #define INDENT "  "
@@ -57,7 +56,6 @@
 using android::gui::TouchOcclusionMode;
 using android::gui::WindowInfo;
 using android::gui::WindowInfoHandle;
-using android::os::BlockUntrustedTouchesMode;
 using android::os::IInputConstants;
 using android::os::InputEventInjectionResult;
 using android::os::InputEventInjectionSync;
@@ -65,79 +63,6 @@
 namespace android::inputdispatcher {
 
 namespace {
-
-/**
- * Log detailed debug messages about each inbound event notification to the dispatcher.
- * Enable this via "adb shell setprop log.tag.InputDispatcherInboundEvent DEBUG" (requires restart)
- */
-const bool DEBUG_INBOUND_EVENT_DETAILS =
-        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "InboundEvent", ANDROID_LOG_INFO);
-
-/**
- * Log detailed debug messages about each outbound event processed by the dispatcher.
- * Enable this via "adb shell setprop log.tag.InputDispatcherOutboundEvent DEBUG" (requires restart)
- */
-const bool DEBUG_OUTBOUND_EVENT_DETAILS =
-        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "OutboundEvent", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about the dispatch cycle.
- * Enable this via "adb shell setprop log.tag.InputDispatcherDispatchCycle DEBUG" (requires restart)
- */
-const bool DEBUG_DISPATCH_CYCLE =
-        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "DispatchCycle", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about channel creation
- * Enable this via "adb shell setprop log.tag.InputDispatcherChannelCreation DEBUG" (requires
- * restart)
- */
-const bool DEBUG_CHANNEL_CREATION =
-        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "ChannelCreation", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about input event injection.
- * Enable this via "adb shell setprop log.tag.InputDispatcherInjection DEBUG" (requires restart)
- */
-const bool DEBUG_INJECTION =
-        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Injection", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about input focus tracking.
- * Enable this via "adb shell setprop log.tag.InputDispatcherFocus DEBUG" (requires restart)
- */
-const bool DEBUG_FOCUS =
-        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Focus", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about touch mode event
- * Enable this via "adb shell setprop log.tag.InputDispatcherTouchMode DEBUG" (requires restart)
- */
-const bool DEBUG_TOUCH_MODE =
-        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "TouchMode", ANDROID_LOG_INFO);
-
-/**
- * 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);
-
-/**
- * Log debug messages about the app switch latency optimization.
- * Enable this via "adb shell setprop log.tag.InputDispatcherAppSwitch DEBUG" (requires restart)
- */
-const bool DEBUG_APP_SWITCH =
-        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "AppSwitch", ANDROID_LOG_INFO);
-
-/**
- * Log debug messages about hover events.
- * Enable this via "adb shell setprop log.tag.InputDispatcherHover DEBUG" (requires restart)
- */
-const bool DEBUG_HOVER =
-        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Hover", ANDROID_LOG_INFO);
-
 // Temporarily releases a held mutex for the lifetime of the instance.
 // Named to match std::scoped_lock
 class scoped_unlock {
@@ -578,6 +503,27 @@
     return false;
 }
 
+// Checks targeted injection using the window's owner's uid.
+// Returns an empty string if an entry can be sent to the given window, or an error message if the
+// entry is a targeted injection whose uid target doesn't match the window owner.
+std::optional<std::string> verifyTargetedInjection(const sp<WindowInfoHandle>& window,
+                                                   const EventEntry& entry) {
+    if (entry.injectionState == nullptr || !entry.injectionState->targetUid) {
+        // The event was not injected, or the injected event does not target a window.
+        return {};
+    }
+    const int32_t uid = *entry.injectionState->targetUid;
+    if (window == nullptr) {
+        return StringPrintf("No valid window target for injection into uid %d.", uid);
+    }
+    if (entry.injectionState->targetUid != window->getInfo()->ownerUid) {
+        return StringPrintf("Injected event targeted at uid %d would be dispatched to window '%s' "
+                            "owned by uid %d.",
+                            uid, window->getName().c_str(), window->getInfo()->ownerUid);
+    }
+    return {};
+}
+
 } // namespace
 
 // --- InputDispatcher ---
@@ -607,11 +553,12 @@
         mWindowTokenWithPointerCapture(nullptr),
         mStaleEventTimeout(staleEventTimeout),
         mLatencyAggregator(),
-        mLatencyTracker(&mLatencyAggregator) {
-    mLooper = new Looper(false);
+        mLatencyTracker(&mLatencyAggregator),
+        kPerDisplayTouchModeEnabled(mPolicy->isPerDisplayTouchModeEnabled()) {
+    mLooper = sp<Looper>::make(false);
     mReporter = createInputReporter();
 
-    mWindowInfoListener = new DispatcherWindowListener(*this);
+    mWindowInfoListener = sp<DispatcherWindowListener>::make(*this);
     SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener);
 
     mKeyRepeatState.lastKeyEntry = nullptr;
@@ -712,6 +659,13 @@
     if (focusedWindowHandle != nullptr) {
         return; // We now have a focused window. No need for ANR.
     }
+    std::optional<FocusRequest> pendingRequest =
+            mFocusResolver.getFocusRequest(mAwaitedApplicationDisplayId);
+    if (pendingRequest.has_value() && onAnrLocked(*pendingRequest)) {
+        // We don't have a focusable window but we know which window should have
+        // been focused. Blame that process in case it doesn't belong to the focused app.
+        return;
+    }
     onAnrLocked(mAwaitedFocusedApplication);
 }
 
@@ -1036,6 +990,8 @@
 
     switch (entry.type) {
         case EventEntry::Type::KEY: {
+            LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
+                                "Unexpected untrusted event.");
             // Optimize app switch latency.
             // If the application takes too long to catch up then we drop all events preceding
             // the app switch key.
@@ -1073,6 +1029,8 @@
         }
 
         case EventEntry::Type::MOTION: {
+            LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
+                                "Unexpected untrusted event.");
             if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(entry))) {
                 mNextUnblockedEvent = mInboundQueue.back();
                 needWake = true;
@@ -1421,8 +1379,10 @@
         // Enable Pointer Capture.
         if (haveWindowWithPointerCapture &&
             (entry->pointerCaptureRequest == mCurrentPointerCaptureRequest)) {
-            LOG_ALWAYS_FATAL("This request to enable Pointer Capture has already been dispatched "
-                             "to the window.");
+            // This can happen if pointer capture is disabled and re-enabled before we notify the
+            // app of the state change, so there is no need to notify the app.
+            ALOGI("Skipping dispatch of Pointer Capture being enabled: no state change.");
+            return;
         }
         if (!mCurrentPointerCaptureRequest.enable) {
             // This can happen if a window requests capture and immediately releases capture.
@@ -1705,6 +1665,13 @@
     InputEventInjectionResult injectionResult;
     if (isPointerEvent) {
         // Pointer event.  (eg. touchscreen)
+
+        if (mDragState &&
+            (entry->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN) {
+            // If drag and drop ongoing and pointer down occur: pilfer drag window pointers
+            pilferPointersLocked(mDragState->dragWindow->getToken());
+        }
+
         injectionResult =
                 findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,
                                                &conflictingPointerActions);
@@ -1718,8 +1685,7 @@
     }
 
     setInjectionResult(*entry, injectionResult);
-    if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) {
-        ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
+    if (injectionResult == InputEventInjectionResult::TARGET_MISMATCH) {
         return true;
     }
     if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
@@ -1745,18 +1711,12 @@
 }
 
 void InputDispatcher::enqueueDragEventLocked(const sp<WindowInfoHandle>& windowHandle,
-                                             bool isExiting, const MotionEntry& motionEntry) {
-    // If the window needs enqueue a drag event, the pointerCount should be 1 and the action should
-    // be AMOTION_EVENT_ACTION_MOVE, that could guarantee the first pointer is always valid.
-    LOG_ALWAYS_FATAL_IF(motionEntry.pointerCount != 1);
-    PointerCoords pointerCoords;
-    pointerCoords.copyFrom(motionEntry.pointerCoords[0]);
-    pointerCoords.transform(windowHandle->getInfo()->transform);
-
+                                             bool isExiting, const int32_t rawX,
+                                             const int32_t rawY) {
+    const vec2 xy = windowHandle->getInfo()->transform.transform(vec2(rawX, rawY));
     std::unique_ptr<DragEntry> dragEntry =
-            std::make_unique<DragEntry>(mIdGenerator.nextId(), motionEntry.eventTime,
-                                        windowHandle->getToken(), isExiting, pointerCoords.getX(),
-                                        pointerCoords.getY());
+            std::make_unique<DragEntry>(mIdGenerator.nextId(), now(), windowHandle->getToken(),
+                                        isExiting, xy.x, xy.y);
 
     enqueueInboundEventLocked(std::move(dragEntry));
 }
@@ -1920,6 +1880,17 @@
     return false;
 }
 
+static std::optional<nsecs_t> getDownTime(const EventEntry& eventEntry) {
+    if (eventEntry.type == EventEntry::Type::KEY) {
+        const KeyEntry& keyEntry = static_cast<const KeyEntry&>(eventEntry);
+        return keyEntry.downTime;
+    } else if (eventEntry.type == EventEntry::Type::MOTION) {
+        const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
+        return motionEntry.downTime;
+    }
+    return std::nullopt;
+}
+
 InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked(
         nsecs_t currentTime, const EventEntry& entry, std::vector<InputTarget>& inputTargets,
         nsecs_t* nextWakeupTime) {
@@ -1976,9 +1947,10 @@
     // we have a valid, non-null focused window
     resetNoFocusedWindowTimeoutLocked();
 
-    // Check permissions.
-    if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) {
-        return InputEventInjectionResult::PERMISSION_DENIED;
+    // Verify targeted injection.
+    if (const auto err = verifyTargetedInjection(focusedWindowHandle, entry); err) {
+        ALOGW("Dropping injected event: %s", (*err).c_str());
+        return InputEventInjectionResult::TARGET_MISMATCH;
     }
 
     if (focusedWindowHandle->getInfo()->inputConfig.test(
@@ -2008,7 +1980,7 @@
     // Success!  Output targets.
     addWindowTargetLocked(focusedWindowHandle,
                           InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,
-                          BitSet32(0), inputTargets);
+                          BitSet32(0), getDownTime(entry), inputTargets);
 
     // Done.
     return InputEventInjectionResult::SUCCEEDED;
@@ -2044,11 +2016,6 @@
         nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets,
         nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {
     ATRACE_CALL();
-    enum InjectionPermission {
-        INJECTION_PERMISSION_UNKNOWN,
-        INJECTION_PERMISSION_GRANTED,
-        INJECTION_PERMISSION_DENIED
-    };
 
     // For security reasons, we defer updating the touch state until we are sure that
     // event injection will be allowed.
@@ -2058,7 +2025,6 @@
 
     // Update the touch state as needed based on the properties of the touch event.
     InputEventInjectionResult injectionResult = InputEventInjectionResult::PENDING;
-    InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
     sp<WindowInfoHandle> newHoverWindowHandle(mLastHoverWindowHandle);
     sp<WindowInfoHandle> newTouchedWindowHandle;
 
@@ -2107,7 +2073,7 @@
               "in display %" PRId32,
               displayId);
         // TODO: test multiple simultaneous input streams.
-        injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
+        injectionResult = InputEventInjectionResult::FAILED;
         switchedDevice = false;
         wrongDevice = true;
         goto Failed;
@@ -2140,6 +2106,14 @@
             newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle();
         }
 
+        // Verify targeted injection.
+        if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
+            ALOGW("Dropping injected touch event: %s", (*err).c_str());
+            injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;
+            newTouchedWindowHandle = nullptr;
+            goto Failed;
+        }
+
         // Figure out whether splitting will be allowed for this window.
         if (newTouchedWindowHandle != nullptr) {
             if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
@@ -2183,6 +2157,11 @@
         for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
             const WindowInfo& info = *windowHandle->getInfo();
 
+            // Skip spy window targets that are not valid for targeted injection.
+            if (const auto err = verifyTargetedInjection(windowHandle, entry); err) {
+                continue;
+            }
+
             if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
                 ALOGI("Not sending touch event to %s because it is paused",
                       windowHandle->getName().c_str());
@@ -2198,23 +2177,17 @@
             }
 
             // Drop events that can't be trusted due to occlusion
-            if (mBlockUntrustedTouchesMode != BlockUntrustedTouchesMode::DISABLED) {
-                TouchOcclusionInfo occlusionInfo =
-                        computeTouchOcclusionInfoLocked(windowHandle, x, y);
-                if (!isTouchTrustedLocked(occlusionInfo)) {
-                    if (DEBUG_TOUCH_OCCLUSION) {
-                        ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
-                        for (const auto& log : occlusionInfo.debugInfo) {
-                            ALOGD("%s", log.c_str());
-                        }
-                    }
-                    sendUntrustedTouchCommandLocked(occlusionInfo.obscuringPackage);
-                    if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) {
-                        ALOGW("Dropping untrusted touch event due to %s/%d",
-                              occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid);
-                        continue;
+            TouchOcclusionInfo occlusionInfo = computeTouchOcclusionInfoLocked(windowHandle, x, y);
+            if (!isTouchTrustedLocked(occlusionInfo)) {
+                if (DEBUG_TOUCH_OCCLUSION) {
+                    ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
+                    for (const auto& log : occlusionInfo.debugInfo) {
+                        ALOGD("%s", log.c_str());
                     }
                 }
+                ALOGW("Dropping untrusted touch event due to %s/%d",
+                      occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid);
+                continue;
             }
 
             // Drop touch events if requested by input feature
@@ -2241,13 +2214,20 @@
 
             // 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);
+            tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds,
+                                             entry.eventTime);
         }
+
+        // If any existing window is pilfering pointers from newly added window, remove it
+        BitSet32 canceledPointers = BitSet32(0);
+        for (const TouchedWindow& window : tempTouchState.windows) {
+            if (window.isPilferingPointers) {
+                canceledPointers |= window.pointerIds;
+            }
+        }
+        tempTouchState.cancelPointersForNonPilferingWindows(canceledPointers);
     } else {
         /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
 
@@ -2276,6 +2256,14 @@
             newTouchedWindowHandle =
                     findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, isStylus);
 
+            // Verify targeted injection.
+            if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
+                ALOGW("Dropping injected event: %s", (*err).c_str());
+                injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;
+                newTouchedWindowHandle = nullptr;
+                goto Failed;
+            }
+
             // Drop touch events if requested by input feature
             if (newTouchedWindowHandle != nullptr &&
                 shouldDropInput(entry, newTouchedWindowHandle)) {
@@ -2313,10 +2301,9 @@
                 }
 
                 BitSet32 pointerIds;
-                if (isSplit) {
-                    pointerIds.markBit(entry.pointerProperties[0].id);
-                }
-                tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
+                pointerIds.markBit(entry.pointerProperties[0].id);
+                tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds,
+                                                 entry.eventTime);
             }
         }
     }
@@ -2367,19 +2354,26 @@
         goto Failed;
     }
 
-    // Check permission to inject into all touched foreground windows.
-    if (std::any_of(tempTouchState.windows.begin(), tempTouchState.windows.end(),
-                    [this, &entry](const TouchedWindow& touchedWindow) {
-                        return (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0 &&
-                                !checkInjectionPermission(touchedWindow.windowHandle,
-                                                          entry.injectionState);
-                    })) {
-        injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
-        injectionPermission = INJECTION_PERMISSION_DENIED;
-        goto Failed;
+    // Ensure that all touched windows are valid for injection.
+    if (entry.injectionState != nullptr) {
+        std::string errs;
+        for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
+            if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
+                // Allow ACTION_OUTSIDE events generated by targeted injection to be
+                // dispatched to any uid, since the coords will be zeroed out later.
+                continue;
+            }
+            const auto err = verifyTargetedInjection(touchedWindow.windowHandle, entry);
+            if (err) errs += "\n  - " + *err;
+        }
+        if (!errs.empty()) {
+            ALOGW("Dropping targeted injection: At least one touched window is not owned by uid "
+                  "%d:%s",
+                  *entry.injectionState->targetUid, errs.c_str());
+            injectionResult = InputEventInjectionResult::TARGET_MISMATCH;
+            goto Failed;
+        }
     }
-    // Permission granted to inject into all touched foreground windows.
-    injectionPermission = INJECTION_PERMISSION_GRANTED;
 
     // Check whether windows listening for outside touches are owned by the same UID. If it is
     // set the policy flag that we will not reveal coordinate information to this window.
@@ -2426,7 +2420,7 @@
                                                        InputTarget::
                                                                FLAG_WINDOW_IS_PARTIALLY_OBSCURED |
                                                        InputTarget::FLAG_DISPATCH_AS_IS,
-                                               BitSet32(0));
+                                               BitSet32(0), entry.eventTime);
                 }
             }
         }
@@ -2437,7 +2431,8 @@
 
     for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
         addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
-                              touchedWindow.pointerIds, inputTargets);
+                              touchedWindow.pointerIds, touchedWindow.firstDownTimeInTarget,
+                              inputTargets);
     }
 
     // Drop the outside or hover touch windows since we will not care about them
@@ -2445,19 +2440,6 @@
     tempTouchState.filterNonAsIsTouchWindows();
 
 Failed:
-    // Check injection permission once and for all.
-    if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {
-        if (checkInjectionPermission(nullptr, entry.injectionState)) {
-            injectionPermission = INJECTION_PERMISSION_GRANTED;
-        } else {
-            injectionPermission = INJECTION_PERMISSION_DENIED;
-        }
-    }
-
-    if (injectionPermission != INJECTION_PERMISSION_GRANTED) {
-        return injectionResult;
-    }
-
     // Update final pieces of touch state if the injector had permission.
     if (!wrongDevice) {
         if (switchedDevice) {
@@ -2497,21 +2479,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);
             }
         }
 
@@ -2544,13 +2533,14 @@
         vec2 local = dropWindow->getInfo()->transform.transform(x, y);
         sendDropWindowCommandLocked(dropWindow->getToken(), local.x, local.y);
     } else {
+        ALOGW("No window found when drop.");
         sendDropWindowCommandLocked(nullptr, 0, 0);
     }
     mDragState.reset();
 }
 
 void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
-    if (entry.pointerCount != 1 || !mDragState) {
+    if (!mDragState || mDragState->dragWindow->getInfo()->displayId != entry.displayId) {
         return;
     }
 
@@ -2560,47 +2550,81 @@
                 (entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
     }
 
-    int32_t maskedAction = entry.action & AMOTION_EVENT_ACTION_MASK;
-    int32_t x = static_cast<int32_t>(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
-    int32_t y = static_cast<int32_t>(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
-    if (maskedAction == AMOTION_EVENT_ACTION_MOVE) {
-        // Handle the special case : stylus button no longer pressed.
-        bool isStylusButtonDown = (entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
-        if (mDragState->isStylusButtonDownAtStart && !isStylusButtonDown) {
-            finishDragAndDrop(entry.displayId, x, y);
-            return;
+    // Find the pointer index by id.
+    int32_t pointerIndex = 0;
+    for (; static_cast<uint32_t>(pointerIndex) < entry.pointerCount; pointerIndex++) {
+        const PointerProperties& pointerProperties = entry.pointerProperties[pointerIndex];
+        if (pointerProperties.id == mDragState->pointerId) {
+            break;
         }
+    }
 
-        // Prevent stylus interceptor windows from affecting drag and drop behavior for now, until
-        // we have an explicit reason to support it.
-        constexpr bool isStylus = false;
-
-        const sp<WindowInfoHandle> hoverWindowHandle =
-                findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/, isStylus,
-                                          false /*addOutsideTargets*/, true /*ignoreDragWindow*/);
-        // enqueue drag exit if needed.
-        if (hoverWindowHandle != mDragState->dragHoverWindowHandle &&
-            !haveSameToken(hoverWindowHandle, mDragState->dragHoverWindowHandle)) {
-            if (mDragState->dragHoverWindowHandle != nullptr) {
-                enqueueDragEventLocked(mDragState->dragHoverWindowHandle, true /*isExiting*/,
-                                       entry);
-            }
-            mDragState->dragHoverWindowHandle = hoverWindowHandle;
-        }
-        // enqueue drag location if needed.
-        if (hoverWindowHandle != nullptr) {
-            enqueueDragEventLocked(hoverWindowHandle, false /*isExiting*/, entry);
-        }
-    } else if (maskedAction == AMOTION_EVENT_ACTION_UP) {
-        finishDragAndDrop(entry.displayId, x, y);
-    } else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
+    if (uint32_t(pointerIndex) == entry.pointerCount) {
+        LOG_ALWAYS_FATAL("Should find a valid pointer index by id %d", mDragState->pointerId);
         sendDropWindowCommandLocked(nullptr, 0, 0);
         mDragState.reset();
+        return;
+    }
+
+    const int32_t maskedAction = entry.action & AMOTION_EVENT_ACTION_MASK;
+    const int32_t x = entry.pointerCoords[pointerIndex].getX();
+    const int32_t y = entry.pointerCoords[pointerIndex].getY();
+
+    switch (maskedAction) {
+        case AMOTION_EVENT_ACTION_MOVE: {
+            // Handle the special case : stylus button no longer pressed.
+            bool isStylusButtonDown =
+                    (entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
+            if (mDragState->isStylusButtonDownAtStart && !isStylusButtonDown) {
+                finishDragAndDrop(entry.displayId, x, y);
+                return;
+            }
+
+            // Prevent stylus interceptor windows from affecting drag and drop behavior for now,
+            // until we have an explicit reason to support it.
+            constexpr bool isStylus = false;
+
+            const sp<WindowInfoHandle> hoverWindowHandle =
+                    findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/,
+                                              isStylus, false /*addOutsideTargets*/,
+                                              true /*ignoreDragWindow*/);
+            // enqueue drag exit if needed.
+            if (hoverWindowHandle != mDragState->dragHoverWindowHandle &&
+                !haveSameToken(hoverWindowHandle, mDragState->dragHoverWindowHandle)) {
+                if (mDragState->dragHoverWindowHandle != nullptr) {
+                    enqueueDragEventLocked(mDragState->dragHoverWindowHandle, true /*isExiting*/, x,
+                                           y);
+                }
+                mDragState->dragHoverWindowHandle = hoverWindowHandle;
+            }
+            // enqueue drag location if needed.
+            if (hoverWindowHandle != nullptr) {
+                enqueueDragEventLocked(hoverWindowHandle, false /*isExiting*/, x, y);
+            }
+            break;
+        }
+
+        case AMOTION_EVENT_ACTION_POINTER_UP:
+            if (getMotionEventActionPointerIndex(entry.action) != pointerIndex) {
+                break;
+            }
+            // The drag pointer is up.
+            [[fallthrough]];
+        case AMOTION_EVENT_ACTION_UP:
+            finishDragAndDrop(entry.displayId, x, y);
+            break;
+        case AMOTION_EVENT_ACTION_CANCEL: {
+            ALOGD("Receiving cancel when drag and drop.");
+            sendDropWindowCommandLocked(nullptr, 0, 0);
+            mDragState.reset();
+            break;
+        }
     }
 }
 
 void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHandle,
                                             int32_t targetFlags, BitSet32 pointerIds,
+                                            std::optional<nsecs_t> firstDownTimeInTarget,
                                             std::vector<InputTarget>& inputTargets) {
     std::vector<InputTarget>::iterator it =
             std::find_if(inputTargets.begin(), inputTargets.end(),
@@ -2622,6 +2646,7 @@
         inputTarget.inputChannel = inputChannel;
         inputTarget.flags = targetFlags;
         inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
+        inputTarget.firstDownTimeInTarget = firstDownTimeInTarget;
         const auto& displayInfoIt = mDisplayInfos.find(windowInfo->displayId);
         if (displayInfoIt != mDisplayInfos.end()) {
             inputTarget.displayTransform = displayInfoIt->second.transform;
@@ -2647,6 +2672,8 @@
         InputTarget target;
         target.inputChannel = monitor.inputChannel;
         target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+        // target.firstDownTimeInTarget is not set for global monitors. It is only required in split
+        // touch and global monitoring works as intended even without setting firstDownTimeInTarget
         if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
             target.displayTransform = it->second.transform;
         }
@@ -2655,26 +2682,6 @@
     }
 }
 
-bool InputDispatcher::checkInjectionPermission(const sp<WindowInfoHandle>& windowHandle,
-                                               const InjectionState* injectionState) {
-    if (injectionState &&
-        (windowHandle == nullptr ||
-         windowHandle->getInfo()->ownerUid != injectionState->injectorUid) &&
-        !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
-        if (windowHandle != nullptr) {
-            ALOGW("Permission denied: injecting event from pid %d uid %d to window %s "
-                  "owned by uid %d",
-                  injectionState->injectorPid, injectionState->injectorUid,
-                  windowHandle->getName().c_str(), windowHandle->getInfo()->ownerUid);
-        } else {
-            ALOGW("Permission denied: injecting event from pid %d uid %d",
-                  injectionState->injectorPid, injectionState->injectorUid);
-        }
-        return false;
-    }
-    return true;
-}
-
 /**
  * Indicate whether one window handle should be considered as obscuring
  * another window handle. We only check a few preconditions. Actually
@@ -2951,8 +2958,12 @@
 
         const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
         if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) {
+            LOG_ALWAYS_FATAL_IF(!inputTarget.firstDownTimeInTarget.has_value(),
+                                "Splitting motion events requires a down time to be set for the "
+                                "target");
             std::unique_ptr<MotionEntry> splitMotionEntry =
-                    splitMotionEvent(originalMotionEntry, inputTarget.pointerIds);
+                    splitMotionEvent(originalMotionEntry, inputTarget.pointerIds,
+                                     inputTarget.firstDownTimeInTarget.value());
             if (!splitMotionEntry) {
                 return; // split event was dropped
             }
@@ -3708,15 +3719,13 @@
 }
 
 void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
-        const sp<Connection>& connection) {
+        const nsecs_t downTime, const sp<Connection>& connection) {
     if (connection->status == Connection::Status::BROKEN) {
         return;
     }
 
-    nsecs_t currentTime = now();
-
     std::vector<std::unique_ptr<EventEntry>> downEvents =
-            connection->inputState.synthesizePointerDownEvents(currentTime);
+            connection->inputState.synthesizePointerDownEvents(downTime);
 
     if (downEvents.empty()) {
         return;
@@ -3764,11 +3773,11 @@
                                    InputTarget::FLAG_DISPATCH_AS_IS);
     }
 
-    startDispatchCycleLocked(currentTime, connection);
+    startDispatchCycleLocked(downTime, connection);
 }
 
 std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent(
-        const MotionEntry& originalMotionEntry, BitSet32 pointerIds) {
+        const MotionEntry& originalMotionEntry, BitSet32 pointerIds, nsecs_t splitDownTime) {
     ALOG_ASSERT(pointerIds.value != 0);
 
     uint32_t splitPointerIndexMap[MAX_POINTERS];
@@ -3836,6 +3845,13 @@
         }
     }
 
+    if (action == AMOTION_EVENT_ACTION_DOWN) {
+        LOG_ALWAYS_FATAL_IF(splitDownTime != originalMotionEntry.eventTime,
+                            "Split motion event has mismatching downTime and eventTime for "
+                            "ACTION_DOWN, motionEntry=%s, splitDownTime=%" PRId64 "ms",
+                            originalMotionEntry.getDescription().c_str(), ns2ms(splitDownTime));
+    }
+
     int32_t newId = mIdGenerator.nextId();
     if (ATRACE_ENABLED()) {
         std::string message = StringPrintf("Split MotionEvent(id=0x%" PRIx32
@@ -3856,9 +3872,9 @@
                                           originalMotionEntry.xPrecision,
                                           originalMotionEntry.yPrecision,
                                           originalMotionEntry.xCursorPosition,
-                                          originalMotionEntry.yCursorPosition,
-                                          originalMotionEntry.downTime, splitPointerCount,
-                                          splitPointerProperties, splitPointerCoords);
+                                          originalMotionEntry.yCursorPosition, splitDownTime,
+                                          splitPointerCount, splitPointerProperties,
+                                          splitPointerCoords);
 
     if (originalMotionEntry.injectionState) {
         splitMotionEntry->injectionState = originalMotionEntry.injectionState;
@@ -4193,20 +4209,20 @@
     }
 }
 
-InputEventInjectionResult InputDispatcher::injectInputEvent(
-        const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
-        InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) {
+InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* event,
+                                                            std::optional<int32_t> targetUid,
+                                                            InputEventInjectionSync syncMode,
+                                                            std::chrono::milliseconds timeout,
+                                                            uint32_t policyFlags) {
     if (DEBUG_INBOUND_EVENT_DETAILS) {
-        ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
-              "syncMode=%d, timeout=%lld, policyFlags=0x%08x",
-              event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags);
+        ALOGD("injectInputEvent - eventType=%d, targetUid=%s, syncMode=%d, timeout=%lld, "
+              "policyFlags=0x%08x",
+              event->getType(), targetUid ? std::to_string(*targetUid).c_str() : "none", syncMode,
+              timeout.count(), policyFlags);
     }
     nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count();
 
-    policyFlags |= POLICY_FLAG_INJECTED;
-    if (hasInjectionPermission(injectorPid, injectorUid)) {
-        policyFlags |= POLICY_FLAG_TRUSTED;
-    }
+    policyFlags |= POLICY_FLAG_INJECTED | POLICY_FLAG_TRUSTED;
 
     // For all injected events, set device id = VIRTUAL_KEYBOARD_ID. The only exception is events
     // that have gone through the InputFilter. If the event passed through the InputFilter, assign
@@ -4347,7 +4363,7 @@
             return InputEventInjectionResult::FAILED;
     }
 
-    InjectionState* injectionState = new InjectionState(injectorPid, injectorUid);
+    InjectionState* injectionState = new InjectionState(targetUid);
     if (syncMode == InputEventInjectionSync::NONE) {
         injectionState->injectionIsAsync = true;
     }
@@ -4419,8 +4435,7 @@
     } // release lock
 
     if (DEBUG_INJECTION) {
-        ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d",
-              injectionResult, injectorPid, injectorUid);
+        ALOGD("injectInputEvent - Finished with result %d.", injectionResult);
     }
 
     return injectionResult;
@@ -4459,19 +4474,12 @@
     return result;
 }
 
-bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
-    return injectorUid == 0 ||
-            mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
-}
-
 void InputDispatcher::setInjectionResult(EventEntry& entry,
                                          InputEventInjectionResult injectionResult) {
     InjectionState* injectionState = entry.injectionState;
     if (injectionState) {
         if (DEBUG_INJECTION) {
-            ALOGD("Setting input event injection result to %d.  "
-                  "injectorPid=%d, injectorUid=%d",
-                  injectionResult, injectionState->injectorPid, injectionState->injectorUid);
+            ALOGD("Setting input event injection result to %d.", injectionResult);
         }
 
         if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) {
@@ -4480,12 +4488,12 @@
                 case InputEventInjectionResult::SUCCEEDED:
                     ALOGV("Asynchronous input event injection succeeded.");
                     break;
+                case InputEventInjectionResult::TARGET_MISMATCH:
+                    ALOGV("Asynchronous input event injection target mismatch.");
+                    break;
                 case InputEventInjectionResult::FAILED:
                     ALOGW("Asynchronous input event injection failed.");
                     break;
-                case InputEventInjectionResult::PERMISSION_DENIED:
-                    ALOGW("Asynchronous input event injection permission denied.");
-                    break;
                 case InputEventInjectionResult::TIMED_OUT:
                     ALOGW("Asynchronous input event injection timed out.");
                     break;
@@ -4508,6 +4516,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,
@@ -4803,9 +4819,11 @@
 
         // If drag window is gone, it would receive a cancel event and broadcast the DRAG_END. We
         // could just clear the state here.
-        if (mDragState &&
+        if (mDragState && mDragState->dragWindow->getInfo()->displayId == displayId &&
             std::find(windowHandles.begin(), windowHandles.end(), mDragState->dragWindow) ==
                     windowHandles.end()) {
+            ALOGI("Drag window went away: %s", mDragState->dragWindow->getName().c_str());
+            sendDropWindowCommandLocked(nullptr, 0, 0);
             mDragState.reset();
         }
     }
@@ -4987,8 +5005,8 @@
     mLooper->wake();
 }
 
-bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid,
-                                     bool hasPermission) {
+bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission,
+                                     int32_t displayId) {
     bool needWake = false;
     {
         std::scoped_lock lock(mLock);
@@ -4997,8 +5015,9 @@
         }
         if (DEBUG_TOUCH_MODE) {
             ALOGD("Request to change touch mode from %s to %s (calling pid=%d, uid=%d, "
-                  "hasPermission=%s)",
-                  toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission));
+                  "hasPermission=%s, target displayId=%d, perDisplayTouchModeEnabled=%s)",
+                  toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission),
+                  displayId, toString(kPerDisplayTouchModeEnabled));
         }
         if (!hasPermission) {
             if (!focusedWindowIsOwnedByLocked(pid, uid) &&
@@ -5010,7 +5029,7 @@
             }
         }
 
-        // TODO(b/198499018): Store touch mode per display.
+        // TODO(b/198499018): Store touch mode per display (kPerDisplayTouchModeEnabled)
         mInTouchMode = inTouchMode;
 
         auto entry = std::make_unique<TouchModeEntry>(mIdGenerator.nextId(), now(), inTouchMode);
@@ -5051,11 +5070,6 @@
     mMaximumObscuringOpacityForTouch = opacity;
 }
 
-void InputDispatcher::setBlockUntrustedTouchesMode(BlockUntrustedTouchesMode mode) {
-    std::scoped_lock lock(mLock);
-    mBlockUntrustedTouchesMode = mode;
-}
-
 std::pair<TouchState*, TouchedWindow*> InputDispatcher::findTouchStateAndWindowLocked(
         const sp<IBinder>& token) {
     for (auto& [displayId, state] : mTouchStatesByDisplay) {
@@ -5106,16 +5120,24 @@
         state->removeWindowByToken(fromToken);
 
         // Add new window.
+        nsecs_t downTimeInTarget = now();
         int32_t newTargetFlags =
                 oldTargetFlags & (InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
         if (canReceiveForegroundTouches(*toWindowHandle->getInfo())) {
             newTargetFlags |= InputTarget::FLAG_FOREGROUND;
         }
-        state->addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds);
+        state->addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds, downTimeInTarget);
 
         // Store the dragging window.
         if (isDragDrop) {
-            mDragState = std::make_unique<DragState>(toWindowHandle);
+            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;
+            }
+            // 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);
         }
 
         // Synthesize cancel for old window and down for new window.
@@ -5127,7 +5149,7 @@
                     options(CancelationOptions::CANCEL_POINTER_EVENTS,
                             "transferring touch focus from this window to another window");
             synthesizeCancelationEventsForConnectionLocked(fromConnection, options);
-            synthesizePointerDownEventsForConnectionLocked(toConnection);
+            synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection);
         }
 
         if (DEBUG_FOCUS) {
@@ -5277,10 +5299,12 @@
                 dump += INDENT3 "Windows:\n";
                 for (size_t i = 0; i < state.windows.size(); i++) {
                     const TouchedWindow& touchedWindow = state.windows[i];
-                    dump += StringPrintf(INDENT4
-                                         "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n",
+                    dump += StringPrintf(INDENT4 "%zu: name='%s', pointerIds=0x%0x, "
+                                                 "targetFlags=0x%x, firstDownTimeInTarget=%" PRId64
+                                                 "ms\n",
                                          i, touchedWindow.windowHandle->getName().c_str(),
-                                         touchedWindow.pointerIds.value, touchedWindow.targetFlags);
+                                         touchedWindow.pointerIds.value, touchedWindow.targetFlags,
+                                         ns2ms(touchedWindow.firstDownTimeInTarget.value_or(0)));
                 }
             } else {
                 dump += INDENT3 "Windows: <none>\n";
@@ -5493,7 +5517,7 @@
         const sp<IBinder>& token = serverChannel->getConnectionToken();
         int fd = serverChannel->getFd();
         sp<Connection> connection =
-                new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator);
+                sp<Connection>::make(std::move(serverChannel), false /*monitor*/, mIdGenerator);
 
         if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) {
             ALOGE("Created a new connection, but the token %p is already known", token.get());
@@ -5503,7 +5527,8 @@
         std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
                                                             this, std::placeholders::_1, token);
 
-        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);
+        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback),
+                       nullptr);
     } // release lock
 
     // Wake the looper because some connections have changed.
@@ -5529,7 +5554,8 @@
                                           << " without a specified display.";
         }
 
-        sp<Connection> connection = new Connection(serverChannel, true /*monitor*/, mIdGenerator);
+        sp<Connection> connection =
+                sp<Connection>::make(serverChannel, true /*monitor*/, mIdGenerator);
         const sp<IBinder>& token = serverChannel->getConnectionToken();
         const int fd = serverChannel->getFd();
 
@@ -5542,7 +5568,8 @@
 
         mGlobalMonitorsByDisplay[displayId].emplace_back(serverChannel, pid);
 
-        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);
+        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback),
+                       nullptr);
     }
 
     // Wake the looper because some connections have changed.
@@ -5606,7 +5633,10 @@
 
 status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) {
     std::scoped_lock _l(mLock);
+    return pilferPointersLocked(token);
+}
 
+status_t InputDispatcher::pilferPointersLocked(const sp<IBinder>& token) {
     const std::shared_ptr<InputChannel> requestingChannel = getInputChannelLocked(token);
     if (!requestingChannel) {
         ALOGW("Attempted to pilfer pointers from an un-registered channel or invalid token");
@@ -5621,16 +5651,20 @@
     }
 
     TouchState& state = *statePtr;
-
+    TouchedWindow& window = *windowPtr;
     // Send cancel events to all the input channels we're stealing from.
     CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                                "input channel stole pointer stream");
     options.deviceId = state.deviceId;
     options.displayId = state.displayId;
+    if (state.split) {
+        // If split pointers then selectively cancel pointers otherwise cancel all pointers
+        options.pointerIds = window.pointerIds;
+    }
     std::string canceledWindows;
-    for (const TouchedWindow& window : state.windows) {
+    for (const TouchedWindow& w : state.windows) {
         const std::shared_ptr<InputChannel> channel =
-                getInputChannelLocked(window.windowHandle->getToken());
+                getInputChannelLocked(w.windowHandle->getToken());
         if (channel != nullptr && channel->getConnectionToken() != token) {
             synthesizeCancelationEventsForInputChannelLocked(channel, options);
             canceledWindows += canceledWindows.empty() ? "[" : ", ";
@@ -5642,8 +5676,14 @@
           canceledWindows.c_str());
 
     // Prevent the gesture from being sent to any other windows.
-    state.filterWindowsExcept(token);
-    state.preventNewTargets = true;
+    // This only blocks relevant pointers to be sent to other windows
+    window.isPilferingPointers = true;
+
+    if (state.split) {
+        state.cancelPointersForWindowsExcept(window.pointerIds, token);
+    } else {
+        state.filterWindowsExcept(token);
+    }
     return OK;
 }
 
@@ -5815,12 +5855,23 @@
     postCommandLocked(std::move(command));
 }
 
-void InputDispatcher::sendUntrustedTouchCommandLocked(const std::string& obscuringPackage) {
-    auto command = [this, obscuringPackage]() REQUIRES(mLock) {
-        scoped_unlock unlock(mLock);
-        mPolicy->notifyUntrustedTouch(obscuringPackage);
-    };
-    postCommandLocked(std::move(command));
+bool InputDispatcher::onAnrLocked(const android::gui::FocusRequest& pendingFocusRequest) {
+    if (pendingFocusRequest.token == nullptr) {
+        return false;
+    }
+
+    const std::string reason = android::base::StringPrintf("%s is not focusable.",
+                                                           pendingFocusRequest.windowName.c_str());
+    updateLastAnrStateLocked(pendingFocusRequest.windowName, reason);
+    sp<Connection> connection = getConnectionLocked(pendingFocusRequest.token);
+    if (connection != nullptr) {
+        processConnectionUnresponsiveLocked(*connection, std::move(reason));
+        // Stop waking up for events on this connection, it is already unresponsive
+        cancelEventsForAnrLocked(connection);
+    } else {
+        sendWindowUnresponsiveCommandLocked(pendingFocusRequest.token, std::nullopt, reason);
+    }
+    return true;
 }
 
 void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
@@ -6345,11 +6396,18 @@
     std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay;
     for (const auto& info : windowInfos) {
         handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>());
-        handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info));
+        handlesPerDisplay[info.displayId].push_back(sp<WindowInfoHandle>::make(info));
     }
 
     { // 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/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index f3dac19..dc6dd5c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -104,7 +104,7 @@
     void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
     android::os::InputEventInjectionResult injectInputEvent(
-            const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
+            const InputEvent* event, std::optional<int32_t> targetUid,
             android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
             uint32_t policyFlags) override;
 
@@ -119,9 +119,9 @@
     void setFocusedDisplay(int32_t displayId) override;
     void setInputDispatchMode(bool enabled, bool frozen) override;
     void setInputFilterEnabled(bool enabled) override;
-    bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) override;
+    bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission,
+                        int32_t displayId) override;
     void setMaximumObscuringOpacityForTouch(float opacity) override;
-    void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) override;
 
     bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
                             bool isDragDrop = false) override;
@@ -221,7 +221,8 @@
                                  const std::string& reason) REQUIRES(mLock);
     // Enqueues a drag event.
     void enqueueDragEventLocked(const sp<android::gui::WindowInfoHandle>& windowToken,
-                                bool isExiting, const MotionEntry& motionEntry) REQUIRES(mLock);
+                                bool isExiting, const int32_t rawX, const int32_t rawY)
+            REQUIRES(mLock);
 
     // Adds an event to a queue of recent events for debugging purposes.
     void addRecentEventLocked(std::shared_ptr<EventEntry> entry) REQUIRES(mLock);
@@ -255,6 +256,8 @@
 
     void removeConnectionLocked(const sp<Connection>& connection) REQUIRES(mLock);
 
+    status_t pilferPointersLocked(const sp<IBinder>& token) REQUIRES(mLock);
+
     template <typename T>
     struct StrongPointerHash {
         std::size_t operator()(const sp<T>& b) const { return std::hash<T*>{}(b.get()); }
@@ -278,7 +281,6 @@
 
     // Event injection and synchronization.
     std::condition_variable mInjectionResultAvailable;
-    bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
     void setInjectionResult(EventEntry& entry,
                             android::os::InputEventInjectionResult injectionResult);
     void transformMotionEntryForInjectionLocked(MotionEntry&,
@@ -344,7 +346,6 @@
     bool mInputFilterEnabled GUARDED_BY(mLock);
     bool mInTouchMode GUARDED_BY(mLock);
     float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock);
-    android::os::BlockUntrustedTouchesMode mBlockUntrustedTouchesMode GUARDED_BY(mLock);
 
     class DispatcherWindowListener : public gui::WindowInfosListener {
     public:
@@ -550,12 +551,11 @@
 
     void addWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle,
                                int32_t targetFlags, BitSet32 pointerIds,
+                               std::optional<nsecs_t> firstDownTimeInTarget,
                                std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
     void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId)
             REQUIRES(mLock);
     void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock);
-    bool checkInjectionPermission(const sp<android::gui::WindowInfoHandle>& windowHandle,
-                                  const InjectionState* injectionState);
     // Enqueue a drag event if needed, and update the touch state.
     // Uses findTouchedWindowTargetsLocked to make the decision
     void addDragEventLocked(const MotionEntry& entry) REQUIRES(mLock);
@@ -623,12 +623,14 @@
                                                         const CancelationOptions& options)
             REQUIRES(mLock);
 
-    void synthesizePointerDownEventsForConnectionLocked(const sp<Connection>& connection)
+    void synthesizePointerDownEventsForConnectionLocked(const nsecs_t downTime,
+                                                        const sp<Connection>& connection)
             REQUIRES(mLock);
 
-    // Splitting motion events across windows.
+    // Splitting motion events across windows. When splitting motion event for a target,
+    // splitDownTime refers to the time of first 'down' event on that particular target
     std::unique_ptr<MotionEntry> splitMotionEvent(const MotionEntry& originalMotionEntry,
-                                                  BitSet32 pointerIds);
+                                                  BitSet32 pointerIds, nsecs_t splitDownTime);
 
     // Reset and drop everything the dispatcher is doing.
     void resetAndDropEverythingLocked(const char* reason) REQUIRES(mLock);
@@ -654,9 +656,9 @@
     void sendFocusChangedCommandLocked(const sp<IBinder>& oldToken, const sp<IBinder>& newToken)
             REQUIRES(mLock);
     void sendDropWindowCommandLocked(const sp<IBinder>& token, float x, float y) REQUIRES(mLock);
-    void sendUntrustedTouchCommandLocked(const std::string& obscuringPackage) REQUIRES(mLock);
     void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
     void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock);
+    bool onAnrLocked(const android::gui::FocusRequest& pendingFocusRequest) REQUIRES(mLock);
     void updateLastAnrStateLocked(const sp<android::gui::WindowInfoHandle>& window,
                                   const std::string& reason) REQUIRES(mLock);
     void updateLastAnrStateLocked(const InputApplicationHandle& application,
@@ -685,6 +687,9 @@
     bool focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
     bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
 
+    // Per display touch mode enabled
+    const bool kPerDisplayTouchModeEnabled;
+
     sp<InputReporterInterface> mReporter;
 };
 
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index ad3c615..047c628 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
+#include "DebugConfig.h"
 #include "input/InputDevice.h"
 
 #include "InputState.h"
 
+#include <cinttypes>
 #include "InputDispatcher.h"
 
 namespace android::inputdispatcher {
@@ -100,11 +102,11 @@
                 mMotionMementos.erase(mMotionMementos.begin() + index);
                 return true;
             }
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-            ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
-                  "displayId=%" PRId32 ", actionMasked=%d",
-                  entry.deviceId, entry.source, entry.displayId, actionMasked);
-#endif
+            if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+                ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
+                      "displayId=%" PRId32 ", actionMasked=%d",
+                      entry.deviceId, entry.source, entry.displayId, actionMasked);
+            }
             return false;
         }
 
@@ -157,11 +159,11 @@
                     return true;
                 }
             }
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-            ALOGD("Dropping inconsistent motion pointer up/down or move event: "
-                  "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d",
-                  entry.deviceId, entry.source, entry.displayId, actionMasked);
-#endif
+            if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+                ALOGD("Dropping inconsistent motion pointer up/down or move event: "
+                      "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d",
+                      entry.deviceId, entry.source, entry.displayId, actionMasked);
+            }
             return false;
         }
 
@@ -171,11 +173,11 @@
                 mMotionMementos.erase(mMotionMementos.begin() + index);
                 return true;
             }
-#if DEBUG_OUTBOUND_EVENT_DETAILS
-            ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, "
-                  "displayId=%" PRId32,
-                  entry.deviceId, entry.source, entry.displayId);
-#endif
+            if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+                ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, "
+                      "displayId=%" PRId32,
+                      entry.deviceId, entry.source, entry.displayId);
+            }
             return false;
         }
 
@@ -284,19 +286,30 @@
 
     for (const MotionMemento& memento : mMotionMementos) {
         if (shouldCancelMotion(memento, options)) {
-            const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT
-                                                    : AMOTION_EVENT_ACTION_CANCEL;
-            events.push_back(
-                    std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
-                                                  memento.deviceId, memento.source,
-                                                  memento.displayId, memento.policyFlags, action,
-                                                  0 /*actionButton*/, memento.flags, AMETA_NONE,
-                                                  0 /*buttonState*/, MotionClassification::NONE,
-                                                  AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
-                                                  memento.yPrecision, memento.xCursorPosition,
-                                                  memento.yCursorPosition, memento.downTime,
-                                                  memento.pointerCount, memento.pointerProperties,
-                                                  memento.pointerCoords));
+            if (options.pointerIds == std::nullopt) {
+                const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT
+                                                        : AMOTION_EVENT_ACTION_CANCEL;
+                events.push_back(
+                        std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
+                                                      memento.deviceId, memento.source,
+                                                      memento.displayId, memento.policyFlags,
+                                                      action, 0 /*actionButton*/, memento.flags,
+                                                      AMETA_NONE, 0 /*buttonState*/,
+                                                      MotionClassification::NONE,
+                                                      AMOTION_EVENT_EDGE_FLAG_NONE,
+                                                      memento.xPrecision, memento.yPrecision,
+                                                      memento.xCursorPosition,
+                                                      memento.yCursorPosition, memento.downTime,
+                                                      memento.pointerCount,
+                                                      memento.pointerProperties,
+                                                      memento.pointerCoords));
+            } else {
+                std::vector<std::unique_ptr<MotionEntry>> pointerCancelEvents =
+                        synthesizeCancelationEventsForPointers(memento, options.pointerIds.value(),
+                                                               currentTime);
+                events.insert(events.end(), std::make_move_iterator(pointerCancelEvents.begin()),
+                              std::make_move_iterator(pointerCancelEvents.end()));
+            }
         }
     }
     return events;
@@ -357,6 +370,73 @@
     return events;
 }
 
+std::vector<std::unique_ptr<MotionEntry>> InputState::synthesizeCancelationEventsForPointers(
+        const MotionMemento& memento, const BitSet32 pointerIds, nsecs_t currentTime) {
+    std::vector<std::unique_ptr<MotionEntry>> events;
+    std::vector<uint32_t> canceledPointerIndices;
+    std::vector<PointerProperties> pointerProperties(MAX_POINTERS);
+    std::vector<PointerCoords> pointerCoords(MAX_POINTERS);
+    for (uint32_t pointerIdx = 0; pointerIdx < memento.pointerCount; pointerIdx++) {
+        uint32_t pointerId = uint32_t(memento.pointerProperties[pointerIdx].id);
+        pointerProperties[pointerIdx].copyFrom(memento.pointerProperties[pointerIdx]);
+        pointerCoords[pointerIdx].copyFrom(memento.pointerCoords[pointerIdx]);
+        if (pointerIds.hasBit(pointerId)) {
+            canceledPointerIndices.push_back(pointerIdx);
+        }
+    }
+
+    if (canceledPointerIndices.size() == memento.pointerCount) {
+        const int32_t action =
+                memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL;
+        events.push_back(
+                std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime, memento.deviceId,
+                                              memento.source, memento.displayId,
+                                              memento.policyFlags, action, 0 /*actionButton*/,
+                                              memento.flags, AMETA_NONE, 0 /*buttonState*/,
+                                              MotionClassification::NONE,
+                                              AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
+                                              memento.yPrecision, memento.xCursorPosition,
+                                              memento.yCursorPosition, memento.downTime,
+                                              memento.pointerCount, memento.pointerProperties,
+                                              memento.pointerCoords));
+    } else {
+        // If we aren't canceling all pointers, we need to generated ACTION_POINTER_UP with
+        // FLAG_CANCELED for each of the canceled pointers. For each event, we must remove the
+        // previously canceled pointers from PointerProperties and PointerCoords, and update
+        // pointerCount appropriately. For convenience, sort the canceled pointer indices so that we
+        // can just slide the remaining pointers to the beginning of the array when a pointer is
+        // canceled.
+        std::sort(canceledPointerIndices.begin(), canceledPointerIndices.end(),
+                  std::greater<uint32_t>());
+
+        uint32_t pointerCount = memento.pointerCount;
+        for (const uint32_t pointerIdx : canceledPointerIndices) {
+            const int32_t action = pointerCount == 1 ? AMOTION_EVENT_ACTION_CANCEL
+                                                     : AMOTION_EVENT_ACTION_POINTER_UP |
+                            (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+            events.push_back(
+                    std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
+                                                  memento.deviceId, memento.source,
+                                                  memento.displayId, memento.policyFlags, action,
+                                                  0 /*actionButton*/,
+                                                  memento.flags | AMOTION_EVENT_FLAG_CANCELED,
+                                                  AMETA_NONE, 0 /*buttonState*/,
+                                                  MotionClassification::NONE,
+                                                  AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
+                                                  memento.yPrecision, memento.xCursorPosition,
+                                                  memento.yCursorPosition, memento.downTime,
+                                                  pointerCount, pointerProperties.data(),
+                                                  pointerCoords.data()));
+
+            // Cleanup pointer information
+            pointerProperties.erase(pointerProperties.begin() + pointerIdx);
+            pointerCoords.erase(pointerCoords.begin() + pointerIdx);
+            pointerCount--;
+        }
+    }
+    return events;
+}
+
 void InputState::clear() {
     mKeyMementos.clear();
     mMotionMementos.clear();
diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h
index 74ae21f..77a6db1 100644
--- a/services/inputflinger/dispatcher/InputState.h
+++ b/services/inputflinger/dispatcher/InputState.h
@@ -22,7 +22,8 @@
 
 #include <utils/Timers.h>
 
-namespace android::inputdispatcher {
+namespace android {
+namespace inputdispatcher {
 
 static constexpr int32_t INVALID_POINTER_INDEX = -1;
 
@@ -125,8 +126,13 @@
 
     static bool shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options);
     static bool shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options);
+
+    // Synthesizes pointer cancel events for a particular set of pointers.
+    std::vector<std::unique_ptr<MotionEntry>> synthesizeCancelationEventsForPointers(
+            const MotionMemento& memento, const BitSet32 pointerIds, nsecs_t currentTime);
 };
 
-} // namespace android::inputdispatcher
+} // namespace inputdispatcher
+} // namespace android
 
 #endif // _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H
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/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index 0725389..ac20dab 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -106,6 +106,9 @@
     // The subset of pointer ids to include in motion events dispatched to this input target
     // if FLAG_SPLIT is set.
     BitSet32 pointerIds;
+    // Event time for the first motion event (ACTION_DOWN) dispatched to this input target if
+    // FLAG_SPLIT is set.
+    std::optional<nsecs_t> firstDownTimeInTarget;
     // The data is stored by the pointerId. Use the bit position of pointerIds to look up
     // Transform per pointerId.
     ui::Transform pointerTransforms[MAX_POINTERS];
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index 61e78cc..cf0c38a 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -30,7 +30,7 @@
 }
 
 void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int32_t targetFlags,
-                                   BitSet32 pointerIds) {
+                                   BitSet32 pointerIds, std::optional<nsecs_t> eventTime) {
     if (targetFlags & InputTarget::FLAG_SPLIT) {
         split = true;
     }
@@ -42,17 +42,22 @@
             if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
                 touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS;
             }
+            // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have
+            // downTime set initially. Need to update existing window when an pointer is down for
+            // the window.
             touchedWindow.pointerIds.value |= pointerIds.value;
+            if (!touchedWindow.firstDownTimeInTarget.has_value()) {
+                touchedWindow.firstDownTimeInTarget = eventTime;
+            }
             return;
         }
     }
 
-    if (preventNewTargets) return; // Don't add new TouchedWindows.
-
     TouchedWindow touchedWindow;
     touchedWindow.windowHandle = windowHandle;
     touchedWindow.targetFlags = targetFlags;
     touchedWindow.pointerIds = pointerIds;
+    touchedWindow.firstDownTimeInTarget = eventTime;
     windows.push_back(touchedWindow);
 }
 
@@ -79,6 +84,27 @@
     }
 }
 
+void TouchState::cancelPointersForWindowsExcept(const BitSet32 pointerIds,
+                                                const sp<IBinder>& token) {
+    if (pointerIds.isEmpty()) return;
+    std::for_each(windows.begin(), windows.end(), [&pointerIds, &token](TouchedWindow& w) {
+        if (w.windowHandle->getToken() != token) {
+            w.pointerIds &= BitSet32(~pointerIds.value);
+        }
+    });
+    std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.isEmpty(); });
+}
+
+void TouchState::cancelPointersForNonPilferingWindows(const BitSet32 pointerIds) {
+    if (pointerIds.isEmpty()) return;
+    std::for_each(windows.begin(), windows.end(), [&pointerIds](TouchedWindow& w) {
+        if (!w.isPilferingPointers) {
+            w.pointerIds &= BitSet32(~pointerIds.value);
+        }
+    });
+    std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.isEmpty(); });
+}
+
 void TouchState::filterWindowsExcept(const sp<IBinder>& token) {
     std::erase_if(windows,
                   [&token](const TouchedWindow& w) { return w.windowHandle->getToken() != token; });
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index 9efb280..1fb51e1 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -31,7 +31,6 @@
 struct TouchState {
     bool down = false;
     bool split = false;
-    bool preventNewTargets = false;
 
     // id of the device that is currently down, others are rejected
     int32_t deviceId = -1;
@@ -48,10 +47,18 @@
 
     void reset();
     void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
-                           int32_t targetFlags, BitSet32 pointerIds);
+                           int32_t targetFlags, BitSet32 pointerIds,
+                           std::optional<nsecs_t> eventTime = std::nullopt);
     void removeWindowByToken(const sp<IBinder>& token);
     void filterNonAsIsTouchWindows();
     void filterWindowsExcept(const sp<IBinder>& token);
+
+    // Cancel pointers for current set of windows except the window with particular binder token.
+    void cancelPointersForWindowsExcept(const BitSet32 pointerIds, const sp<IBinder>& token);
+    // Cancel pointers for current set of non-pilfering windows i.e. windows with isPilferingWindow
+    // set to false.
+    void cancelPointersForNonPilferingWindows(const BitSet32 pointerIds);
+
     sp<android::gui::WindowInfoHandle> getFirstForegroundWindowHandle() const;
     bool isSlippery() const;
     sp<android::gui::WindowInfoHandle> getWallpaperWindow() const;
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
index 4c31ec3..a7839db 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -29,7 +29,11 @@
 struct TouchedWindow {
     sp<gui::WindowInfoHandle> windowHandle;
     int32_t targetFlags;
-    BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set
+    BitSet32 pointerIds;
+    bool isPilferingPointers = false;
+    // Time at which the first action down occurred on this window.
+    // NOTE: This is not initialized in case of HOVER entry/exit and DISPATCH_AS_OUTSIDE scenario.
+    std::optional<nsecs_t> firstDownTimeInTarget;
 };
 
 } // namespace inputdispatcher
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index d7bc5fb..32b3ddb 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -20,7 +20,7 @@
 #include <InputListener.h>
 #include <android-base/result.h>
 #include <android/gui/FocusRequest.h>
-#include <android/os/BlockUntrustedTouchesMode.h>
+
 #include <android/os/InputEventInjectionResult.h>
 #include <android/os/InputEventInjectionSync.h>
 #include <gui/InputApplication.h>
@@ -68,10 +68,16 @@
      * input injection to proceed.
      * Returns one of the INPUT_EVENT_INJECTION_XXX constants.
      *
-     * This method may be called on any thread (usually by the input manager).
+     * If a targetUid is provided, InputDispatcher will only consider injecting the input event into
+     * windows owned by the provided uid. If the input event is targeted at a window that is not
+     * owned by the provided uid, input injection will fail. If no targetUid is provided, the input
+     * event will be dispatched as-is.
+     *
+     * This method may be called on any thread (usually by the input manager). The caller must
+     * perform all necessary permission checks prior to injecting events.
      */
     virtual android::os::InputEventInjectionResult injectInputEvent(
-            const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
+            const InputEvent* event, std::optional<int32_t> targetUid,
             android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
             uint32_t policyFlags) = 0;
 
@@ -126,7 +132,8 @@
      *
      * Returns true when changing touch mode state.
      */
-    virtual bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) = 0;
+    virtual bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission,
+                                int32_t displayId) = 0;
 
     /**
      * Sets the maximum allowed obscuring opacity by UID to propagate touches.
@@ -136,13 +143,6 @@
      */
     virtual void setMaximumObscuringOpacityForTouch(float opacity) = 0;
 
-    /**
-     * Sets the mode of the block untrusted touches feature.
-     *
-     * TODO(b/169067926): Clean-up feature modes.
-     */
-    virtual void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) = 0;
-
     /* Transfers touch focus from one window to another window.
      *
      * Returns true on success.  False if the window did not actually have touch focus.
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index de0b6da..7c299b2 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -75,9 +75,6 @@
                                       InputDeviceSensorAccuracy accuracy) = 0;
     virtual void notifyVibratorState(int32_t deviceId, bool isOn) = 0;
 
-    /* Notifies the system that an untrusted touch occurred. */
-    virtual void notifyUntrustedTouch(const std::string& obscuringPackage) = 0;
-
     /* Gets the input dispatcher configuration. */
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
 
@@ -125,15 +122,6 @@
     /* Poke user activity for an event dispatched to a window. */
     virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) = 0;
 
-    /* Checks whether a given application pid/uid has permission to inject input events
-     * into other applications.
-     *
-     * This method is special in that its implementation promises to be non-reentrant and
-     * is safe to call while holding other locks.  (Most other methods make no such guarantees!)
-     */
-    virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid,
-                                                         int32_t injectorUid) = 0;
-
     /* Notifies the policy that a pointer down event has occurred outside the current focused
      * window.
      *
@@ -149,6 +137,9 @@
 
     /* Notifies the policy that the drag window has moved over to another window */
     virtual void notifyDropWindow(const sp<IBinder>& token, float x, float y) = 0;
+
+    /* If touch mode is enabled per display or global */
+    virtual bool isPerDisplayTouchModeEnabled() = 0;
 };
 
 } // namespace android
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
index 2ebdbcf..97d57e4 100644
--- a/services/inputflinger/host/InputDriver.cpp
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -240,19 +240,16 @@
     return nullptr;
 }
 
-input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map,
-        const char* key) {
-    String8 keyString(key);
+input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, const char* key) {
     if (map != nullptr) {
-        if (map->propertyMap->hasProperty(keyString)) {
-            auto prop = new input_property_t();
-            if (!map->propertyMap->tryGetProperty(keyString, prop->value)) {
-                delete prop;
-                return nullptr;
-            }
-            prop->key = keyString;
-            return prop;
+        std::string value;
+        auto prop = std::make_unique<input_property_t>();
+        if (!map->propertyMap->tryGetProperty(key, value)) {
+            return nullptr;
         }
+        prop->key = key;
+        prop->value = value.c_str();
+        return prop.release();
     }
     return nullptr;
 }
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 41ecef3..77c9142 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -95,7 +95,7 @@
 
     /* Determine whether physical keys exist for the given framework-domain key codes. */
     virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
-            size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0;
+                         const std::vector<int32_t>& keyCodes, uint8_t* outFlags) = 0;
 
     /* Requests that a reconfiguration of all input devices.
      * The changes flag is a bitfield that indicates what has changed and whether
diff --git a/services/inputflinger/include/UnwantedInteractionBlockerInterface.h b/services/inputflinger/include/UnwantedInteractionBlockerInterface.h
index 2327266..1a6f847 100644
--- a/services/inputflinger/include/UnwantedInteractionBlockerInterface.h
+++ b/services/inputflinger/include/UnwantedInteractionBlockerInterface.h
@@ -39,11 +39,11 @@
 
     /**
      * Dump the state of the interaction blocker.
-     * This method may be called on any thread (usually by the input manager).
+     * This method may be called on any thread (usually by the input manager on a binder thread).
      */
     virtual void dump(std::string& dump) = 0;
 
-    /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */
+    /* Called by the heatbeat to ensures that the blocker has not deadlocked. */
     virtual void monitor() = 0;
 
     UnwantedInteractionBlockerInterface() {}
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 3bd3275..01146a3 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -71,7 +71,7 @@
         "libstatslog",
         "libui",
         "libutils",
-        "PlatformProperties",
+        "libPlatformProperties",
     ],
     static_libs: [
         "libc++fs",
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index d6a6bd2..bfa44ac 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -452,8 +452,7 @@
         return false;
     }
 
-    std::vector<int32_t> scanCodes;
-    keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes);
+    std::vector<int32_t> scanCodes = keyMap.keyLayoutMap->findScanCodesForKey(keycode);
     const size_t N = scanCodes.size();
     for (size_t i = 0; i < N && i <= KEY_MAX; i++) {
         int32_t sc = scanCodes[i];
@@ -503,7 +502,7 @@
 bool EventHub::Device::isExternalDeviceLocked() {
     if (configuration) {
         bool value;
-        if (configuration->tryGetProperty(String8("device.internal"), value)) {
+        if (configuration->tryGetProperty("device.internal", value)) {
             return !value;
         }
     }
@@ -513,7 +512,7 @@
 bool EventHub::Device::deviceHasMicLocked() {
     if (configuration) {
         bool value;
-        if (configuration->tryGetProperty(String8("audio.mic"), value)) {
+        if (configuration->tryGetProperty("audio.mic", value)) {
             return value;
         }
     }
@@ -548,10 +547,10 @@
         return NAME_NOT_FOUND;
     }
 
-    int32_t scanCode;
-    if (keyMap.keyLayoutMap->findScanCodeForLed(led, &scanCode) != NAME_NOT_FOUND) {
-        if (scanCode >= 0 && scanCode <= LED_MAX && ledBitmask.test(scanCode)) {
-            *outScanCode = scanCode;
+    std::optional<int32_t> scanCode = keyMap.keyLayoutMap->findScanCodeForLed(led);
+    if (scanCode.has_value()) {
+        if (*scanCode >= 0 && *scanCode <= LED_MAX && ledBitmask.test(*scanCode)) {
+            *outScanCode = *scanCode;
             return NO_ERROR;
         }
     }
@@ -688,6 +687,7 @@
     LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
 
     mINotifyFd = inotify_init1(IN_CLOEXEC);
+    LOG_ALWAYS_FATAL_IF(mINotifyFd < 0, "Could not create inotify instance: %s", strerror(errno));
 
     std::error_code errorCode;
     bool isDeviceInotifyAdded = false;
@@ -865,8 +865,7 @@
 
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
-        std::vector<int32_t> scanCodes;
-        device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes);
+        std::vector<int32_t> scanCodes = device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode);
         if (scanCodes.size() != 0) {
             if (device->readDeviceBitMask(EVIOCGKEY(0), device->keyState) >= 0) {
                 for (size_t i = 0; i < scanCodes.size(); i++) {
@@ -890,8 +889,8 @@
         device->keyMap.keyLayoutMap == nullptr) {
         return AKEYCODE_UNKNOWN;
     }
-    std::vector<int32_t> scanCodes;
-    device->keyMap.keyLayoutMap->findScanCodesForKey(locationKeyCode, &scanCodes);
+    std::vector<int32_t> scanCodes =
+            device->keyMap.keyLayoutMap->findScanCodesForKey(locationKeyCode);
     if (scanCodes.empty()) {
         ALOGW("Failed to get key code for key location: no scan code maps to key code %d for input"
               "device %d",
@@ -954,26 +953,22 @@
     return -1;
 }
 
-bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
+bool EventHub::markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes,
                                      uint8_t* outFlags) const {
     std::scoped_lock _l(mLock);
 
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr && device->keyMap.haveKeyLayout()) {
-        std::vector<int32_t> scanCodes;
-        for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
-            scanCodes.clear();
+        for (size_t codeIndex = 0; codeIndex < keyCodes.size(); codeIndex++) {
+            std::vector<int32_t> scanCodes =
+                    device->keyMap.keyLayoutMap->findScanCodesForKey(keyCodes[codeIndex]);
 
-            status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey(keyCodes[codeIndex],
-                                                                            &scanCodes);
-            if (!err) {
-                // check the possible scan codes identified by the layout map against the
-                // map of codes actually emitted by the driver
-                for (size_t sc = 0; sc < scanCodes.size(); sc++) {
-                    if (device->keyBitmask.test(scanCodes[sc])) {
-                        outFlags[codeIndex] = 1;
-                        break;
-                    }
+            // check the possible scan codes identified by the layout map against the
+            // map of codes actually emitted by the driver
+            for (const int32_t scanCode : scanCodes) {
+                if (device->keyBitmask.test(scanCode)) {
+                    outFlags[codeIndex] = 1;
+                    break;
                 }
             }
         }
@@ -1027,14 +1022,15 @@
     std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
 
-    if (device != nullptr && device->keyMap.haveKeyLayout()) {
-        status_t err = device->keyMap.keyLayoutMap->mapAxis(scanCode, outAxisInfo);
-        if (err == NO_ERROR) {
-            return NO_ERROR;
-        }
+    if (device == nullptr || !device->keyMap.haveKeyLayout()) {
+        return NAME_NOT_FOUND;
     }
-
-    return NAME_NOT_FOUND;
+    std::optional<AxisInfo> info = device->keyMap.keyLayoutMap->mapAxis(scanCode);
+    if (!info.has_value()) {
+        return NAME_NOT_FOUND;
+    }
+    *outAxisInfo = *info;
+    return NO_ERROR;
 }
 
 base::Result<std::pair<InputDeviceSensorType, int32_t>> EventHub::mapSensor(int32_t deviceId,
@@ -1314,7 +1310,8 @@
     if (!identifier.uniqueId.empty()) {
         rawDescriptor += "uniqueId:";
         rawDescriptor += identifier.uniqueId;
-    } else if (identifier.nonce != 0) {
+    }
+    if (identifier.nonce != 0) {
         rawDescriptor += StringPrintf("nonce:%04x", identifier.nonce);
     }
 
@@ -1342,16 +1339,20 @@
     // of Android. In practice we sometimes get devices that cannot be uniquely
     // identified. In this case we enforce uniqueness between connected devices.
     // Ideally, we also want the descriptor to be short and relatively opaque.
+    // Note that we explicitly do not use the path or location for external devices
+    // as their path or location will change as they are plugged/unplugged or moved
+    // to different ports. We do fallback to using name and location in the case of
+    // internal devices which are detected by the vendor and product being 0 in
+    // generateDescriptor. If two identical descriptors are detected we will fallback
+    // to using a 'nonce' and incrementing it until the new descriptor no longer has
+    // a match with any existing descriptors.
 
     identifier.nonce = 0;
     std::string rawDescriptor = generateDescriptor(identifier);
-    if (identifier.uniqueId.empty()) {
-        // If it didn't have a unique id check for conflicts and enforce
-        // uniqueness if necessary.
-        while (getDeviceByDescriptorLocked(identifier.descriptor) != nullptr) {
-            identifier.nonce++;
-            rawDescriptor = generateDescriptor(identifier);
-        }
+    // Enforce that the generated descriptor is unique.
+    while (hasDeviceWithDescriptorLocked(identifier.descriptor)) {
+        identifier.nonce++;
+        rawDescriptor = generateDescriptor(identifier);
     }
     ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.c_str(),
           identifier.descriptor.c_str());
@@ -1426,13 +1427,22 @@
     return vibrators;
 }
 
-EventHub::Device* EventHub::getDeviceByDescriptorLocked(const std::string& descriptor) const {
-    for (const auto& [id, device] : mDevices) {
+/**
+ * Checks both mDevices and mOpeningDevices for a device with the descriptor passed.
+ */
+bool EventHub::hasDeviceWithDescriptorLocked(const std::string& descriptor) const {
+    for (const auto& device : mOpeningDevices) {
         if (descriptor == device->identifier.descriptor) {
-            return device.get();
+            return true;
         }
     }
-    return nullptr;
+
+    for (const auto& [id, device] : mDevices) {
+        if (descriptor == device->identifier.descriptor) {
+            return true;
+        }
+    }
+    return false;
 }
 
 EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
@@ -1728,7 +1738,10 @@
         // before closing the devices.
         if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
             mPendingINotify = false;
-            readNotifyLocked();
+            const auto res = readNotifyLocked();
+            if (!res.ok()) {
+                ALOGW("Failed to read from inotify: %s", res.error().message().c_str());
+            }
             deviceChanged = true;
         }
 
@@ -2077,10 +2090,9 @@
     }
 
     // See if this is a rotary encoder type device.
-    String8 deviceType = String8();
-    if (device->configuration &&
-        device->configuration->tryGetProperty(String8("device.type"), deviceType)) {
-        if (!deviceType.compare(String8("rotaryEncoder"))) {
+    std::string deviceType;
+    if (device->configuration && device->configuration->tryGetProperty("device.type", deviceType)) {
+        if (deviceType == "rotaryEncoder") {
             device->classes |= InputDeviceClass::ROTARY_ENCODER;
         }
     }
@@ -2418,53 +2430,56 @@
     mDevices.erase(device.id);
 }
 
-status_t EventHub::readNotifyLocked() {
-    int res;
-    char event_buf[512];
-    int event_size;
-    int event_pos = 0;
-    struct inotify_event* event;
+base::Result<void> EventHub::readNotifyLocked() {
+    static constexpr auto EVENT_SIZE = static_cast<ssize_t>(sizeof(inotify_event));
+    uint8_t eventBuffer[512];
+    ssize_t sizeRead;
 
     ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd);
-    res = read(mINotifyFd, event_buf, sizeof(event_buf));
-    if (res < (int)sizeof(*event)) {
-        if (errno == EINTR) return 0;
-        ALOGW("could not get event, %s\n", strerror(errno));
-        return -1;
-    }
+    do {
+        sizeRead = read(mINotifyFd, eventBuffer, sizeof(eventBuffer));
+    } while (sizeRead < 0 && errno == EINTR);
 
-    while (res >= (int)sizeof(*event)) {
-        event = (struct inotify_event*)(event_buf + event_pos);
-        if (event->len) {
-            if (event->wd == mDeviceInputWd) {
-                std::string filename = std::string(DEVICE_INPUT_PATH) + "/" + event->name;
-                if (event->mask & IN_CREATE) {
-                    openDeviceLocked(filename);
-                } else {
-                    ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
-                    closeDeviceByPathLocked(filename);
-                }
-            } else if (event->wd == mDeviceWd) {
-                if (isV4lTouchNode(event->name)) {
-                    std::string filename = std::string(DEVICE_PATH) + "/" + event->name;
-                    if (event->mask & IN_CREATE) {
-                        openVideoDeviceLocked(filename);
-                    } else {
-                        ALOGI("Removing video device '%s' due to inotify event", filename.c_str());
-                        closeVideoDeviceByPathLocked(filename);
-                    }
-                } else if (strcmp(event->name, "input") == 0 && event->mask & IN_CREATE) {
-                    addDeviceInputInotify();
-                }
-            } else {
-                LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event->wd);
-            }
-        }
-        event_size = sizeof(*event) + event->len;
-        res -= event_size;
-        event_pos += event_size;
+    if (sizeRead < EVENT_SIZE) return Errorf("could not get event, %s", strerror(errno));
+
+    for (ssize_t eventPos = 0; sizeRead >= EVENT_SIZE;) {
+        const inotify_event* event;
+        event = (const inotify_event*)(eventBuffer + eventPos);
+        if (event->len == 0) continue;
+
+        handleNotifyEventLocked(*event);
+
+        const ssize_t eventSize = EVENT_SIZE + event->len;
+        sizeRead -= eventSize;
+        eventPos += eventSize;
     }
-    return 0;
+    return {};
+}
+
+void EventHub::handleNotifyEventLocked(const inotify_event& event) {
+    if (event.wd == mDeviceInputWd) {
+        std::string filename = std::string(DEVICE_INPUT_PATH) + "/" + event.name;
+        if (event.mask & IN_CREATE) {
+            openDeviceLocked(filename);
+        } else {
+            ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
+            closeDeviceByPathLocked(filename);
+        }
+    } else if (event.wd == mDeviceWd) {
+        if (isV4lTouchNode(event.name)) {
+            std::string filename = std::string(DEVICE_PATH) + "/" + event.name;
+            if (event.mask & IN_CREATE) {
+                openVideoDeviceLocked(filename);
+            } else {
+                ALOGI("Removing video device '%s' due to inotify event", filename.c_str());
+                closeVideoDeviceByPathLocked(filename);
+            }
+        } else if (strcmp(event.name, "input") == 0 && event.mask & IN_CREATE) {
+            addDeviceInputInotify();
+        }
+    } else {
+        LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event.wd);
+    }
 }
 
 status_t EventHub::scanDirLocked(const std::string& dirname) {
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index ba5083b..b67777f 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -465,12 +465,12 @@
     return result;
 }
 
-bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-                                        const int32_t* keyCodes, uint8_t* outFlags) {
+bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
+                                        uint8_t* outFlags) {
     bool result = false;
-    for_each_mapper([&result, sourceMask, numCodes, keyCodes, outFlags](InputMapper& mapper) {
+    for_each_mapper([&result, sourceMask, keyCodes, outFlags](InputMapper& mapper) {
         if (sourcesMatchMask(mapper.getSources(), sourceMask)) {
-            result |= mapper.markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
+            result |= mapper.markSupportedKeyCodes(sourceMask, keyCodes, outFlags);
         }
     });
     return result;
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 31d331b..11a2dbe 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -38,6 +38,26 @@
 
 namespace android {
 
+/**
+ * Determines if the identifiers passed are a sub-devices. Sub-devices are physical devices
+ * that expose multiple input device paths such a keyboard that also has a touchpad input.
+ * These are separate devices with unique descriptors in EventHub, but InputReader should
+ * create a single InputDevice for them.
+ * Sub-devices are detected by the following criteria:
+ * 1. The vendor, product, bus, version, and unique id match
+ * 2. The location matches. The location is used to distinguish a single device with multiple
+ *    inputs versus the same device plugged into multiple ports.
+ */
+
+static bool isSubDevice(const InputDeviceIdentifier& identifier1,
+                        const InputDeviceIdentifier& identifier2) {
+    return (identifier1.vendor == identifier2.vendor &&
+            identifier1.product == identifier2.product && identifier1.bus == identifier2.bus &&
+            identifier1.version == identifier2.version &&
+            identifier1.uniqueId == identifier2.uniqueId &&
+            identifier1.location == identifier2.location);
+}
+
 // --- InputReader ---
 
 InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
@@ -47,8 +67,8 @@
         mEventHub(eventHub),
         mPolicy(policy),
         mQueuedListener(listener),
-        mGlobalMetaState(0),
-        mLedMetaState(AMETA_NUM_LOCK_ON),
+        mGlobalMetaState(AMETA_NONE),
+        mLedMetaState(AMETA_NONE),
         mGeneration(1),
         mNextInputDeviceId(END_RESERVED_ID),
         mDisableVirtualKeysTimeout(LLONG_MIN),
@@ -270,8 +290,9 @@
 std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
         int32_t eventHubId, const InputDeviceIdentifier& identifier) {
     auto deviceIt = std::find_if(mDevices.begin(), mDevices.end(), [identifier](auto& devicePair) {
-        return devicePair.second->getDescriptor().size() && identifier.descriptor.size() &&
-                devicePair.second->getDescriptor() == identifier.descriptor;
+        const InputDeviceIdentifier identifier2 =
+                devicePair.second->getDeviceInfo().getIdentifier();
+        return isSubDevice(identifier, identifier2);
     });
 
     std::shared_ptr<InputDevice> device;
@@ -561,28 +582,28 @@
     device->updateMetaState(AKEYCODE_CAPS_LOCK);
 }
 
-bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
-                          const int32_t* keyCodes, uint8_t* outFlags) {
+bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask,
+                          const std::vector<int32_t>& keyCodes, uint8_t* outFlags) {
     std::scoped_lock _l(mLock);
 
-    memset(outFlags, 0, numCodes);
-    return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags);
+    memset(outFlags, 0, keyCodes.size());
+    return markSupportedKeyCodesLocked(deviceId, sourceMask, keyCodes, outFlags);
 }
 
 bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask,
-                                              size_t numCodes, const int32_t* keyCodes,
+                                              const std::vector<int32_t>& keyCodes,
                                               uint8_t* outFlags) {
     bool result = false;
     if (deviceId >= 0) {
         InputDevice* device = findInputDeviceLocked(deviceId);
         if (device && !device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
-            result = device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
+            result = device->markSupportedKeyCodes(sourceMask, keyCodes, outFlags);
         }
     } else {
         for (auto& devicePair : mDevices) {
             std::shared_ptr<InputDevice>& device = devicePair.second;
             if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
-                result |= device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
+                result |= device->markSupportedKeyCodes(sourceMask, keyCodes, outFlags);
             }
         }
     }
diff --git a/services/inputflinger/reader/Macros.h b/services/inputflinger/reader/Macros.h
index d837689..1bbf386 100644
--- a/services/inputflinger/reader/Macros.h
+++ b/services/inputflinger/reader/Macros.h
@@ -20,27 +20,65 @@
 #define LOG_TAG "InputReader"
 
 //#define LOG_NDEBUG 0
+#include <log/log.h>
+#include <log/log_event_list.h>
 
-// Log debug messages for each raw event received from the EventHub.
-static constexpr bool DEBUG_RAW_EVENTS = false;
+namespace android {
+/**
+ * Log debug messages for each raw event received from the EventHub.
+ * Enable this via "adb shell setprop log.tag.InputReaderRawEvents DEBUG" (requires restart)
+ */
+const bool DEBUG_RAW_EVENTS =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "RawEvents", ANDROID_LOG_INFO);
 
-// Log debug messages about virtual key processing.
-static constexpr bool DEBUG_VIRTUAL_KEYS = false;
+/**
+ * Log debug messages about virtual key processing.
+ * Enable this via "adb shell setprop log.tag.InputReaderVirtualKeys DEBUG" (requires restart)
+ */
+const bool DEBUG_VIRTUAL_KEYS =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "VirtualKeys", ANDROID_LOG_INFO);
 
-// Log debug messages about pointers.
-static constexpr bool DEBUG_POINTERS = false;
+/**
+ * Log debug messages about pointers.
+ * Enable this via "adb shell setprop log.tag.InputReaderPointers DEBUG" (requires restart)
+ */
+const bool DEBUG_POINTERS =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Pointers", ANDROID_LOG_INFO);
 
-// Log debug messages about pointer assignment calculations.
-static constexpr bool DEBUG_POINTER_ASSIGNMENT = false;
+/**
+ * Log debug messages about pointer assignment calculations.
+ * Enable this via "adb shell setprop log.tag.InputReaderPointerAssignment DEBUG" (requires restart)
+ */
+const bool DEBUG_POINTER_ASSIGNMENT =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "PointerAssignment", ANDROID_LOG_INFO);
+/**
+ * Log debug messages about gesture detection.
+ * Enable this via "adb shell setprop log.tag.InputReaderGestures DEBUG" (requires restart)
+ */
+const bool DEBUG_GESTURES =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Gestures", ANDROID_LOG_INFO);
 
-// Log debug messages about gesture detection.
-static constexpr bool DEBUG_GESTURES = false;
+/**
+ * Log debug messages about the vibrator.
+ * Enable this via "adb shell setprop log.tag.InputReaderVibrator DEBUG" (requires restart)
+ */
+const bool DEBUG_VIBRATOR =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Vibrator", ANDROID_LOG_INFO);
 
-// Log debug messages about the vibrator.
-static constexpr bool DEBUG_VIBRATOR = false;
+/**
+ * Log debug messages about fusing stylus data.
+ * Enable this via "adb shell setprop log.tag.InputReaderStylusFusion DEBUG" (requires restart)
+ */
+const bool DEBUG_STYLUS_FUSION =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "StylusFusion", ANDROID_LOG_INFO);
 
-// Log debug messages about fusing stylus data.
-static constexpr bool DEBUG_STYLUS_FUSION = false;
+/**
+ * Log detailed debug messages about input device lights.
+ * Enable this via "adb shell setprop log.tag.InputReaderLightDetails DEBUG" (requires restart)
+ */
+const bool DEBUG_LIGHT_DETAILS =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "LightDetails", ANDROID_LOG_INFO);
+} // namespace android
 
 #define INDENT "  "
 #define INDENT2 "    "
diff --git a/services/inputflinger/reader/controller/PeripheralController.cpp b/services/inputflinger/reader/controller/PeripheralController.cpp
index a693496..7673174 100644
--- a/services/inputflinger/reader/controller/PeripheralController.cpp
+++ b/services/inputflinger/reader/controller/PeripheralController.cpp
@@ -22,9 +22,6 @@
 #include "../Macros.h"
 #include "PeripheralController.h"
 
-// Log detailed debug messages about input device lights.
-static constexpr bool DEBUG_LIGHT_DETAILS = false;
-
 namespace android {
 
 static inline int32_t getAlpha(int32_t color) {
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 130c556..4733ecb 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -36,7 +36,6 @@
 #include <sys/epoll.h>
 #include <utils/BitSet.h>
 #include <utils/Errors.h>
-#include <utils/KeyedVector.h>
 #include <utils/List.h>
 #include <utils/Log.h>
 #include <utils/Mutex.h>
@@ -44,6 +43,8 @@
 #include "TouchVideoDevice.h"
 #include "VibrationElement.h"
 
+struct inotify_event;
+
 namespace android {
 
 /* Number of colors : {red, green, blue} */
@@ -311,7 +312,7 @@
     /*
      * Examine key input devices for specific framework keycode support
      */
-    virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
+    virtual bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes,
                                        uint8_t* outFlags) const = 0;
 
     virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0;
@@ -488,7 +489,7 @@
     status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
                                   int32_t* outValue) const override final;
 
-    bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
+    bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes,
                                uint8_t* outFlags) const override final;
 
     size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) override final;
@@ -648,9 +649,9 @@
     status_t scanDirLocked(const std::string& dirname) REQUIRES(mLock);
     status_t scanVideoDirLocked(const std::string& dirname) REQUIRES(mLock);
     void scanDevicesLocked() REQUIRES(mLock);
-    status_t readNotifyLocked() REQUIRES(mLock);
+    base::Result<void> readNotifyLocked() REQUIRES(mLock);
+    void handleNotifyEventLocked(const inotify_event&) REQUIRES(mLock);
 
-    Device* getDeviceByDescriptorLocked(const std::string& descriptor) const REQUIRES(mLock);
     Device* getDeviceLocked(int32_t deviceId) const REQUIRES(mLock);
     Device* getDeviceByPathLocked(const std::string& devicePath) const REQUIRES(mLock);
     /**
@@ -660,6 +661,9 @@
     Device* getDeviceByFdLocked(int fd) const REQUIRES(mLock);
 
     int32_t getNextControllerNumberLocked(const std::string& name) REQUIRES(mLock);
+
+    bool hasDeviceWithDescriptorLocked(const std::string& descriptor) const REQUIRES(mLock);
+
     void releaseControllerNumberLocked(int32_t num) REQUIRES(mLock);
     void reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier,
                                               ftl::Flags<InputDeviceClass> classes) REQUIRES(mLock);
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 728020e..51872ac 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -88,7 +88,7 @@
     int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
     int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
     int32_t getKeyCodeForKeyLocation(int32_t locationKeyCode) const;
-    bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes,
+    bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
                                uint8_t* outFlags);
     void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token);
     void cancelVibrate(int32_t token);
@@ -324,9 +324,9 @@
     inline status_t getAbsoluteAxisValue(int32_t code, int32_t* outValue) const {
         return mEventHub->getAbsoluteAxisValue(mId, code, outValue);
     }
-    inline bool markSupportedKeyCodes(size_t numCodes, const int32_t* keyCodes,
+    inline bool markSupportedKeyCodes(const std::vector<int32_t>& keyCodes,
                                       uint8_t* outFlags) const {
-        return mEventHub->markSupportedKeyCodes(mId, numCodes, keyCodes, outFlags);
+        return mEventHub->markSupportedKeyCodes(mId, keyCodes, outFlags);
     }
     inline bool hasScanCode(int32_t scanCode) const {
         return mEventHub->hasScanCode(mId, scanCode);
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index daeaa1d..ae41e01 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -73,7 +73,7 @@
 
     void toggleCapsLockState(int32_t deviceId) override;
 
-    bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes,
+    bool hasKeys(int32_t deviceId, uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
                  uint8_t* outFlags) override;
 
     void requestRefreshConfiguration(uint32_t changes) override;
@@ -237,8 +237,9 @@
     typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code);
     int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code,
                            GetStateFunc getStateFunc) REQUIRES(mLock);
-    bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
-                                     const int32_t* keyCodes, uint8_t* outFlags) REQUIRES(mLock);
+    bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask,
+                                     const std::vector<int32_t>& keyCodes, uint8_t* outFlags)
+            REQUIRES(mLock);
 
     // find an InputDevice from an InputDevice id
     InputDevice* findInputDeviceLocked(int32_t deviceId) const REQUIRES(mLock);
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index dc5fcec..6058a1e 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -27,6 +27,9 @@
 
 namespace android {
 
+// The default velocity control parameters that has no effect.
+static const VelocityControlParameters FLAT_VELOCITY_CONTROL_PARAMS{};
+
 // --- CursorMotionAccumulator ---
 
 CursorMotionAccumulator::CursorMotionAccumulator() {
@@ -64,7 +67,11 @@
 CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext)
       : InputMapper(deviceContext) {}
 
-CursorInputMapper::~CursorInputMapper() {}
+CursorInputMapper::~CursorInputMapper() {
+    if (mPointerController != nullptr) {
+        mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
+    }
+}
 
 uint32_t CursorInputMapper::getSources() const {
     return mSource;
@@ -73,7 +80,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);
@@ -128,12 +135,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;
@@ -141,7 +148,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;
@@ -154,11 +161,13 @@
         mHWheelScale = 1.0f;
     }
 
-    if ((!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);
@@ -166,8 +175,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");
@@ -180,13 +189,22 @@
         }
     }
 
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
-        mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
-        mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
-        mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters);
+    if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED) ||
+        configurePointerCapture) {
+        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);
+        } else {
+            mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
+            mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
+            mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters);
+        }
     }
 
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+    if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) ||
+        configurePointerCapture) {
         mOrientation = DISPLAY_ORIENTATION_0;
         const bool isOrientedDevice =
                 (mParameters.orientationAware && mParameters.hasAssociatedDisplay);
@@ -195,8 +213,9 @@
         // 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) {
+        // 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 && mParameters.mode != Parameters::Mode::POINTER_RELATIVE) {
             std::optional<DisplayViewport> internalViewport =
                     config->getDisplayViewportByType(ViewportType::INTERNAL);
             if (internalViewport) {
@@ -209,23 +228,22 @@
 }
 
 void CursorInputMapper::configureParameters() {
-    mParameters.mode = Parameters::MODE_POINTER;
-    String8 cursorModeString;
-    if (getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.mode"),
-                                                             cursorModeString)) {
+    mParameters.mode = Parameters::Mode::POINTER;
+    std::string cursorModeString;
+    if (getDeviceContext().getConfiguration().tryGetProperty("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());
+            ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.c_str());
         }
     }
 
     mParameters.orientationAware = false;
-    getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.orientationAware"),
+    getDeviceContext().getConfiguration().tryGetProperty("cursor.orientationAware",
                                                          mParameters.orientationAware);
 
     mParameters.hasAssociatedDisplay = false;
-    if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
+    if (mParameters.mode == Parameters::Mode::POINTER || mParameters.orientationAware) {
         mParameters.hasAssociatedDisplay = true;
     }
 }
@@ -234,21 +252,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));
 }
 
@@ -474,7 +478,7 @@
 
 std::optional<int32_t> CursorInputMapper::getAssociatedDisplayId() {
     if (mParameters.hasAssociatedDisplay) {
-        if (mParameters.mode == Parameters::MODE_POINTER) {
+        if (mParameters.mode == Parameters::Mode::POINTER) {
             return std::make_optional(mPointerController->getDisplayId());
         } else {
             // If the device is orientationAware and not a mouse,
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index c84c6c4..75aeffb 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;
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index 7b185e0..75cebf3 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -55,8 +55,8 @@
     return AKEYCODE_UNKNOWN;
 }
 
-bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-                                        const int32_t* keyCodes, uint8_t* outFlags) {
+bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
+                                        uint8_t* outFlags) {
     return false;
 }
 
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index fce6409..7858728 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -64,8 +64,8 @@
     virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
     virtual int32_t getKeyCodeForKeyLocation(int32_t locationKeyCode) const;
 
-    virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-                                       const int32_t* keyCodes, uint8_t* outFlags);
+    virtual bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
+                                       uint8_t* outFlags);
     virtual void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token);
     virtual void cancelVibrate(int32_t token);
     virtual bool isVibrating();
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 2ac8178..6a406d2 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -160,7 +160,7 @@
 
 static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const* property) {
     int32_t mapped = 0;
-    if (config.tryGetProperty(String8(property), mapped) && mapped > 0) {
+    if (config.tryGetProperty(property, mapped) && mapped > 0) {
         for (size_t i = 0; i < stemKeyRotationMapSize; i++) {
             if (stemKeyRotationMap[i][0] == keyCode) {
                 stemKeyRotationMap[i][1] = mapped;
@@ -173,7 +173,7 @@
 void KeyboardInputMapper::configureParameters() {
     mParameters.orientationAware = false;
     const PropertyMap& config = getDeviceContext().getConfiguration();
-    config.tryGetProperty(String8("keyboard.orientationAware"), mParameters.orientationAware);
+    config.tryGetProperty("keyboard.orientationAware", mParameters.orientationAware);
 
     if (mParameters.orientationAware) {
         mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary");
@@ -183,10 +183,10 @@
     }
 
     mParameters.handlesKeyRepeat = false;
-    config.tryGetProperty(String8("keyboard.handlesKeyRepeat"), mParameters.handlesKeyRepeat);
+    config.tryGetProperty("keyboard.handlesKeyRepeat", mParameters.handlesKeyRepeat);
 
     mParameters.doNotWakeByDefault = false;
-    config.tryGetProperty(String8("keyboard.doNotWakeByDefault"), mParameters.doNotWakeByDefault);
+    config.tryGetProperty("keyboard.doNotWakeByDefault", mParameters.doNotWakeByDefault);
 }
 
 void KeyboardInputMapper::dumpParameters(std::string& dump) {
@@ -379,9 +379,10 @@
     return getDeviceContext().getKeyCodeForKeyLocation(locationKeyCode);
 }
 
-bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-                                                const int32_t* keyCodes, uint8_t* outFlags) {
-    return getDeviceContext().markSupportedKeyCodes(numCodes, keyCodes, outFlags);
+bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask,
+                                                const std::vector<int32_t>& keyCodes,
+                                                uint8_t* outFlags) {
+    return getDeviceContext().markSupportedKeyCodes(keyCodes, outFlags);
 }
 
 int32_t KeyboardInputMapper::getMetaState() {
@@ -433,13 +434,12 @@
     mMetaState |= getContext()->getLedMetaState();
 
     constexpr int32_t META_NUM = 3;
-    const std::array<int32_t, META_NUM> keyCodes = {AKEYCODE_CAPS_LOCK, AKEYCODE_NUM_LOCK,
-                                                    AKEYCODE_SCROLL_LOCK};
+    const std::vector<int32_t> keyCodes{AKEYCODE_CAPS_LOCK, AKEYCODE_NUM_LOCK,
+                                        AKEYCODE_SCROLL_LOCK};
     const std::array<int32_t, META_NUM> metaCodes = {AMETA_CAPS_LOCK_ON, AMETA_NUM_LOCK_ON,
                                                      AMETA_SCROLL_LOCK_ON};
     std::array<uint8_t, META_NUM> flags = {0, 0, 0};
-    bool hasKeyLayout =
-            getDeviceContext().markSupportedKeyCodes(META_NUM, keyCodes.data(), flags.data());
+    bool hasKeyLayout = getDeviceContext().markSupportedKeyCodes(keyCodes, flags.data());
     // If the device doesn't have the physical meta key it shouldn't generate the corresponding
     // meta state.
     if (hasKeyLayout) {
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index 3787696..0a55def 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -36,8 +36,8 @@
 
     virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override;
     virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
-    virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-                                       const int32_t* keyCodes, uint8_t* outFlags) override;
+    virtual bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
+                                       uint8_t* outFlags) override;
     virtual int32_t getKeyCodeForKeyLocation(int32_t locationKeyCode) const override;
 
     virtual int32_t getMetaState() override;
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index eca25f6..05973f7 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -40,10 +40,10 @@
 
     if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) {
         float res = 0.0f;
-        if (!getDeviceContext().getConfiguration().tryGetProperty(String8("device.res"), res)) {
+        if (!getDeviceContext().getConfiguration().tryGetProperty("device.res", res)) {
             ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n");
         }
-        if (!getDeviceContext().getConfiguration().tryGetProperty(String8("device.scalingFactor"),
+        if (!getDeviceContext().getConfiguration().tryGetProperty("device.scalingFactor",
                                                                   mScalingFactor)) {
             ALOGW("Rotary Encoder device configuration file didn't specify scaling factor,"
                   "default to 1.0!\n");
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
index b01c2bc..573f99c 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
@@ -64,7 +64,7 @@
 template <typename T>
 bool SensorInputMapper::tryGetProperty(std::string keyName, T& outValue) {
     const auto& config = getDeviceContext().getConfiguration();
-    return config.tryGetProperty(String8(keyName.c_str()), outValue);
+    return config.tryGetProperty(keyName, outValue);
 }
 
 void SensorInputMapper::parseSensorConfiguration(InputDeviceSensorType sensorType, int32_t absCode,
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index c1934ff..17ee54f 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -42,8 +42,12 @@
 // data.
 static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10);
 
+// Minimum width between two pointers to determine a gesture as freeform gesture in mm
+static const float MIN_FREEFORM_GESTURE_WIDTH_IN_MILLIMETER = 30;
 // --- Static Definitions ---
 
+static const DisplayViewport kUninitializedViewport;
+
 template <typename T>
 inline static void swap(T& a, T& b) {
     T temp = a;
@@ -204,30 +208,30 @@
                                  y.fuzz, y.resolution);
         }
 
-        if (mOrientedRanges.haveSize) {
-            info->addMotionRange(mOrientedRanges.size);
+        if (mOrientedRanges.size) {
+            info->addMotionRange(*mOrientedRanges.size);
         }
 
-        if (mOrientedRanges.haveTouchSize) {
-            info->addMotionRange(mOrientedRanges.touchMajor);
-            info->addMotionRange(mOrientedRanges.touchMinor);
+        if (mOrientedRanges.touchMajor) {
+            info->addMotionRange(*mOrientedRanges.touchMajor);
+            info->addMotionRange(*mOrientedRanges.touchMinor);
         }
 
-        if (mOrientedRanges.haveToolSize) {
-            info->addMotionRange(mOrientedRanges.toolMajor);
-            info->addMotionRange(mOrientedRanges.toolMinor);
+        if (mOrientedRanges.toolMajor) {
+            info->addMotionRange(*mOrientedRanges.toolMajor);
+            info->addMotionRange(*mOrientedRanges.toolMinor);
         }
 
-        if (mOrientedRanges.haveOrientation) {
-            info->addMotionRange(mOrientedRanges.orientation);
+        if (mOrientedRanges.orientation) {
+            info->addMotionRange(*mOrientedRanges.orientation);
         }
 
-        if (mOrientedRanges.haveDistance) {
-            info->addMotionRange(mOrientedRanges.distance);
+        if (mOrientedRanges.distance) {
+            info->addMotionRange(*mOrientedRanges.distance);
         }
 
-        if (mOrientedRanges.haveTilt) {
-            info->addMotionRange(mOrientedRanges.tilt);
+        if (mOrientedRanges.tilt) {
+            info->addMotionRange(*mOrientedRanges.tilt);
         }
 
         if (mCursorScrollAccumulator.haveRelativeVWheel()) {
@@ -390,6 +394,10 @@
     }
 
     if (changes && resetNeeded) {
+        // 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());
@@ -415,15 +423,15 @@
             ? Parameters::GestureMode::SINGLE_TOUCH
             : Parameters::GestureMode::MULTI_TOUCH;
 
-    String8 gestureModeString;
-    if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.gestureMode"),
+    std::string gestureModeString;
+    if (getDeviceContext().getConfiguration().tryGetProperty("touch.gestureMode",
                                                              gestureModeString)) {
         if (gestureModeString == "single-touch") {
             mParameters.gestureMode = Parameters::GestureMode::SINGLE_TOUCH;
         } else if (gestureModeString == "multi-touch") {
             mParameters.gestureMode = Parameters::GestureMode::MULTI_TOUCH;
         } else if (gestureModeString != "default") {
-            ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string());
+            ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.c_str());
         }
     }
 
@@ -445,8 +453,8 @@
 
     mParameters.hasButtonUnderPad = getDeviceContext().hasInputProperty(INPUT_PROP_BUTTONPAD);
 
-    String8 deviceTypeString;
-    if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.deviceType"),
+    std::string deviceTypeString;
+    if (getDeviceContext().getConfiguration().tryGetProperty("touch.deviceType",
                                                              deviceTypeString)) {
         if (deviceTypeString == "touchScreen") {
             mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
@@ -457,17 +465,17 @@
         } else if (deviceTypeString == "pointer") {
             mParameters.deviceType = Parameters::DeviceType::POINTER;
         } else if (deviceTypeString != "default") {
-            ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
+            ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.c_str());
         }
     }
 
     mParameters.orientationAware = mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN;
-    getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientationAware"),
+    getDeviceContext().getConfiguration().tryGetProperty("touch.orientationAware",
                                                          mParameters.orientationAware);
 
     mParameters.orientation = Parameters::Orientation::ORIENTATION_0;
-    String8 orientationString;
-    if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientation"),
+    std::string orientationString;
+    if (getDeviceContext().getConfiguration().tryGetProperty("touch.orientation",
                                                              orientationString)) {
         if (mParameters.deviceType != Parameters::DeviceType::TOUCH_SCREEN) {
             ALOGW("The configuration 'touch.orientation' is only supported for touchscreens.");
@@ -478,7 +486,7 @@
         } else if (orientationString == "ORIENTATION_270") {
             mParameters.orientation = Parameters::Orientation::ORIENTATION_270;
         } else if (orientationString != "ORIENTATION_0") {
-            ALOGW("Invalid value for touch.orientation: '%s'", orientationString.string());
+            ALOGW("Invalid value for touch.orientation: '%s'", orientationString.c_str());
         }
     }
 
@@ -490,8 +498,8 @@
         mParameters.hasAssociatedDisplay = true;
         if (mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN) {
             mParameters.associatedDisplayIsExternal = getDeviceContext().isExternal();
-            String8 uniqueDisplayId;
-            getDeviceContext().getConfiguration().tryGetProperty(String8("touch.displayId"),
+            std::string uniqueDisplayId;
+            getDeviceContext().getConfiguration().tryGetProperty("touch.displayId",
                                                                  uniqueDisplayId);
             mParameters.uniqueDisplayId = uniqueDisplayId.c_str();
         }
@@ -504,7 +512,7 @@
     // Normally we don't do this for internal touch screens to prevent them from waking
     // up in your pocket but you can enable it using the input device configuration.
     mParameters.wake = getDeviceContext().isExternal();
-    getDeviceContext().getConfiguration().tryGetProperty(String8("touch.wake"), mParameters.wake);
+    getDeviceContext().getConfiguration().tryGetProperty("touch.wake", mParameters.wake);
 }
 
 void TouchInputMapper::dumpParameters(std::string& dump) {
@@ -639,57 +647,58 @@
         mSizeScale = 0.0f;
     }
 
-    mOrientedRanges.haveTouchSize = true;
-    mOrientedRanges.haveToolSize = true;
-    mOrientedRanges.haveSize = true;
+    mOrientedRanges.touchMajor = InputDeviceInfo::MotionRange{
+            .axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR,
+            .source = mSource,
+            .min = 0,
+            .max = diagonalSize,
+            .flat = 0,
+            .fuzz = 0,
+            .resolution = 0,
+    };
 
-    mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR;
-    mOrientedRanges.touchMajor.source = mSource;
-    mOrientedRanges.touchMajor.min = 0;
-    mOrientedRanges.touchMajor.max = diagonalSize;
-    mOrientedRanges.touchMajor.flat = 0;
-    mOrientedRanges.touchMajor.fuzz = 0;
-    mOrientedRanges.touchMajor.resolution = 0;
     if (mRawPointerAxes.touchMajor.valid) {
         mRawPointerAxes.touchMajor.resolution =
                 clampResolution("touchMajor", mRawPointerAxes.touchMajor.resolution);
-        mOrientedRanges.touchMajor.resolution = mRawPointerAxes.touchMajor.resolution;
+        mOrientedRanges.touchMajor->resolution = mRawPointerAxes.touchMajor.resolution;
     }
 
     mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
-    mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
+    mOrientedRanges.touchMinor->axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
     if (mRawPointerAxes.touchMinor.valid) {
         mRawPointerAxes.touchMinor.resolution =
                 clampResolution("touchMinor", mRawPointerAxes.touchMinor.resolution);
-        mOrientedRanges.touchMinor.resolution = mRawPointerAxes.touchMinor.resolution;
+        mOrientedRanges.touchMinor->resolution = mRawPointerAxes.touchMinor.resolution;
     }
 
-    mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR;
-    mOrientedRanges.toolMajor.source = mSource;
-    mOrientedRanges.toolMajor.min = 0;
-    mOrientedRanges.toolMajor.max = diagonalSize;
-    mOrientedRanges.toolMajor.flat = 0;
-    mOrientedRanges.toolMajor.fuzz = 0;
-    mOrientedRanges.toolMajor.resolution = 0;
+    mOrientedRanges.toolMajor = InputDeviceInfo::MotionRange{
+            .axis = AMOTION_EVENT_AXIS_TOOL_MAJOR,
+            .source = mSource,
+            .min = 0,
+            .max = diagonalSize,
+            .flat = 0,
+            .fuzz = 0,
+            .resolution = 0,
+    };
     if (mRawPointerAxes.toolMajor.valid) {
         mRawPointerAxes.toolMajor.resolution =
                 clampResolution("toolMajor", mRawPointerAxes.toolMajor.resolution);
-        mOrientedRanges.toolMajor.resolution = mRawPointerAxes.toolMajor.resolution;
+        mOrientedRanges.toolMajor->resolution = mRawPointerAxes.toolMajor.resolution;
     }
 
     mOrientedRanges.toolMinor = mOrientedRanges.toolMajor;
-    mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
+    mOrientedRanges.toolMinor->axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
     if (mRawPointerAxes.toolMinor.valid) {
         mRawPointerAxes.toolMinor.resolution =
                 clampResolution("toolMinor", mRawPointerAxes.toolMinor.resolution);
-        mOrientedRanges.toolMinor.resolution = mRawPointerAxes.toolMinor.resolution;
+        mOrientedRanges.toolMinor->resolution = mRawPointerAxes.toolMinor.resolution;
     }
 
     if (mCalibration.sizeCalibration == Calibration::SizeCalibration::GEOMETRIC) {
-        mOrientedRanges.touchMajor.resolution *= mGeometricScale;
-        mOrientedRanges.touchMinor.resolution *= mGeometricScale;
-        mOrientedRanges.toolMajor.resolution *= mGeometricScale;
-        mOrientedRanges.toolMinor.resolution *= mGeometricScale;
+        mOrientedRanges.touchMajor->resolution *= mGeometricScale;
+        mOrientedRanges.touchMinor->resolution *= mGeometricScale;
+        mOrientedRanges.toolMajor->resolution *= mGeometricScale;
+        mOrientedRanges.toolMinor->resolution *= mGeometricScale;
     } else {
         // Support for other calibrations can be added here.
         ALOGW("%s calibration is not supported for size ranges at the moment. "
@@ -697,13 +706,15 @@
               ftl::enum_string(mCalibration.sizeCalibration).c_str());
     }
 
-    mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE;
-    mOrientedRanges.size.source = mSource;
-    mOrientedRanges.size.min = 0;
-    mOrientedRanges.size.max = 1.0;
-    mOrientedRanges.size.flat = 0;
-    mOrientedRanges.size.fuzz = 0;
-    mOrientedRanges.size.resolution = 0;
+    mOrientedRanges.size = InputDeviceInfo::MotionRange{
+            .axis = AMOTION_EVENT_AXIS_SIZE,
+            .source = mSource,
+            .min = 0,
+            .max = 1.0,
+            .flat = 0,
+            .fuzz = 0,
+            .resolution = 0,
+    };
 }
 
 void TouchInputMapper::initializeOrientedRanges() {
@@ -730,21 +741,23 @@
     float pressureMax = 1.0;
     if (mCalibration.pressureCalibration == Calibration::PressureCalibration::PHYSICAL ||
         mCalibration.pressureCalibration == Calibration::PressureCalibration::AMPLITUDE) {
-        if (mCalibration.havePressureScale) {
-            mPressureScale = mCalibration.pressureScale;
+        if (mCalibration.pressureScale) {
+            mPressureScale = *mCalibration.pressureScale;
             pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue;
         } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) {
             mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue;
         }
     }
 
-    mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
-    mOrientedRanges.pressure.source = mSource;
-    mOrientedRanges.pressure.min = 0;
-    mOrientedRanges.pressure.max = pressureMax;
-    mOrientedRanges.pressure.flat = 0;
-    mOrientedRanges.pressure.fuzz = 0;
-    mOrientedRanges.pressure.resolution = 0;
+    mOrientedRanges.pressure = InputDeviceInfo::MotionRange{
+            .axis = AMOTION_EVENT_AXIS_PRESSURE,
+            .source = mSource,
+            .min = 0,
+            .max = pressureMax,
+            .flat = 0,
+            .fuzz = 0,
+            .resolution = 0,
+    };
 
     // Tilt
     mTiltXCenter = 0;
@@ -765,29 +778,30 @@
             mTiltYScale = 1.0 / mRawPointerAxes.tiltY.resolution;
         }
 
-        mOrientedRanges.haveTilt = true;
-
-        mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT;
-        mOrientedRanges.tilt.source = mSource;
-        mOrientedRanges.tilt.min = 0;
-        mOrientedRanges.tilt.max = M_PI_2;
-        mOrientedRanges.tilt.flat = 0;
-        mOrientedRanges.tilt.fuzz = 0;
-        mOrientedRanges.tilt.resolution = 0;
+        mOrientedRanges.tilt = InputDeviceInfo::MotionRange{
+                .axis = AMOTION_EVENT_AXIS_TILT,
+                .source = mSource,
+                .min = 0,
+                .max = M_PI_2,
+                .flat = 0,
+                .fuzz = 0,
+                .resolution = 0,
+        };
     }
 
     // Orientation
     mOrientationScale = 0;
     if (mHaveTilt) {
-        mOrientedRanges.haveOrientation = true;
+        mOrientedRanges.orientation = InputDeviceInfo::MotionRange{
+                .axis = AMOTION_EVENT_AXIS_ORIENTATION,
+                .source = mSource,
+                .min = -M_PI,
+                .max = M_PI,
+                .flat = 0,
+                .fuzz = 0,
+                .resolution = 0,
+        };
 
-        mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
-        mOrientedRanges.orientation.source = mSource;
-        mOrientedRanges.orientation.min = -M_PI;
-        mOrientedRanges.orientation.max = M_PI;
-        mOrientedRanges.orientation.flat = 0;
-        mOrientedRanges.orientation.fuzz = 0;
-        mOrientedRanges.orientation.resolution = 0;
     } else if (mCalibration.orientationCalibration != Calibration::OrientationCalibration::NONE) {
         if (mCalibration.orientationCalibration ==
             Calibration::OrientationCalibration::INTERPOLATED) {
@@ -802,37 +816,34 @@
             }
         }
 
-        mOrientedRanges.haveOrientation = true;
-
-        mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
-        mOrientedRanges.orientation.source = mSource;
-        mOrientedRanges.orientation.min = -M_PI_2;
-        mOrientedRanges.orientation.max = M_PI_2;
-        mOrientedRanges.orientation.flat = 0;
-        mOrientedRanges.orientation.fuzz = 0;
-        mOrientedRanges.orientation.resolution = 0;
+        mOrientedRanges.orientation = InputDeviceInfo::MotionRange{
+                .axis = AMOTION_EVENT_AXIS_ORIENTATION,
+                .source = mSource,
+                .min = -M_PI_2,
+                .max = M_PI_2,
+                .flat = 0,
+                .fuzz = 0,
+                .resolution = 0,
+        };
     }
 
     // Distance
     mDistanceScale = 0;
     if (mCalibration.distanceCalibration != Calibration::DistanceCalibration::NONE) {
         if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::SCALED) {
-            if (mCalibration.haveDistanceScale) {
-                mDistanceScale = mCalibration.distanceScale;
-            } else {
-                mDistanceScale = 1.0f;
-            }
+            mDistanceScale = mCalibration.distanceScale.value_or(1.0f);
         }
 
-        mOrientedRanges.haveDistance = true;
+        mOrientedRanges.distance = InputDeviceInfo::MotionRange{
 
-        mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE;
-        mOrientedRanges.distance.source = mSource;
-        mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale;
-        mOrientedRanges.distance.max = mRawPointerAxes.distance.maxValue * mDistanceScale;
-        mOrientedRanges.distance.flat = 0;
-        mOrientedRanges.distance.fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale;
-        mOrientedRanges.distance.resolution = 0;
+                .axis = AMOTION_EVENT_AXIS_DISTANCE,
+                .source = mSource,
+                .min = mRawPointerAxes.distance.minValue * mDistanceScale,
+                .max = mRawPointerAxes.distance.maxValue * mDistanceScale,
+                .flat = 0,
+                .fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale,
+                .resolution = 0,
+        };
     }
 
     // Compute oriented precision, scales and ranges.
@@ -877,7 +888,7 @@
 }
 
 void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) {
-    DeviceMode oldDeviceMode = mDeviceMode;
+    const DeviceMode oldDeviceMode = mDeviceMode;
 
     resolveExternalStylusPresence();
 
@@ -906,42 +917,42 @@
         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 int32_t rawXResolution = mRawPointerAxes.x.resolution;
+    const int32_t rawYResolution = mRawPointerAxes.y.resolution;
+    // Calculate the mean resolution when both x and y resolution are set, otherwise set it to 0.
+    const float rawMeanResolution =
+            (rawXResolution > 0 && rawYResolution > 0) ? (rawXResolution + rawYResolution) / 2 : 0;
 
-    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;
-        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.
@@ -1016,8 +1027,9 @@
                     : getInverseRotation(mViewport.orientation);
             // For orientation-aware devices that work in the un-rotated coordinate space, the
             // viewport update should be skipped if it is only a change in the orientation.
-            skipViewportUpdate = mParameters.orientationAware && mDisplayWidth == oldDisplayWidth &&
-                    mDisplayHeight == oldDisplayHeight && viewportOrientationChanged;
+            skipViewportUpdate = !viewportDisplayIdChanged && mParameters.orientationAware &&
+                    mDisplayWidth == oldDisplayWidth && mDisplayHeight == oldDisplayHeight &&
+                    viewportOrientationChanged;
 
             // Apply the input device orientation for the device.
             mInputDeviceOrientation =
@@ -1053,6 +1065,10 @@
             mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
         }
     } else {
+        if (mPointerController != nullptr && mDeviceMode == DeviceMode::DIRECT &&
+            !mConfig.showTouches) {
+            mPointerController->clearSpots();
+        }
         mPointerController.reset();
     }
 
@@ -1090,14 +1106,14 @@
                     mConfig.pointerGestureZoomSpeedRatio * displayDiagonal / rawDiagonal;
             mPointerYZoomScale = mPointerXZoomScale;
 
-            // Max width between pointers to detect a swipe gesture is more than some fraction
-            // of the diagonal axis of the touch pad.  Touches that are wider than this are
-            // translated into freeform gestures.
-            mPointerGestureMaxSwipeWidth = mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal;
+            // Calculate the min freeform gesture width. It will be 0 when the resolution of any
+            // axis is non positive value.
+            const float minFreeformGestureWidth =
+                    rawMeanResolution * MIN_FREEFORM_GESTURE_WIDTH_IN_MILLIMETER;
 
-            // Abort current pointer usages because the state has changed.
-            const nsecs_t readTime = when; // synthetic event
-            abortPointerUsage(when, readTime, 0 /*policyFlags*/);
+            mPointerGestureMaxSwipeWidth =
+                    std::max(mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal,
+                             minFreeformGestureWidth);
         }
 
         // Inform the dispatcher about the changes.
@@ -1188,8 +1204,8 @@
 
     // Size
     out.sizeCalibration = Calibration::SizeCalibration::DEFAULT;
-    String8 sizeCalibrationString;
-    if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) {
+    std::string sizeCalibrationString;
+    if (in.tryGetProperty("touch.size.calibration", sizeCalibrationString)) {
         if (sizeCalibrationString == "none") {
             out.sizeCalibration = Calibration::SizeCalibration::NONE;
         } else if (sizeCalibrationString == "geometric") {
@@ -1201,18 +1217,28 @@
         } else if (sizeCalibrationString == "area") {
             out.sizeCalibration = Calibration::SizeCalibration::AREA;
         } else if (sizeCalibrationString != "default") {
-            ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.string());
+            ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.c_str());
         }
     }
 
-    out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), out.sizeScale);
-    out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), out.sizeBias);
-    out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), out.sizeIsSummed);
+    float sizeScale;
+
+    if (in.tryGetProperty("touch.size.scale", sizeScale)) {
+        out.sizeScale = sizeScale;
+    }
+    float sizeBias;
+    if (in.tryGetProperty("touch.size.bias", sizeBias)) {
+        out.sizeBias = sizeBias;
+    }
+    bool sizeIsSummed;
+    if (in.tryGetProperty("touch.size.isSummed", sizeIsSummed)) {
+        out.sizeIsSummed = sizeIsSummed;
+    }
 
     // Pressure
     out.pressureCalibration = Calibration::PressureCalibration::DEFAULT;
-    String8 pressureCalibrationString;
-    if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) {
+    std::string pressureCalibrationString;
+    if (in.tryGetProperty("touch.pressure.calibration", pressureCalibrationString)) {
         if (pressureCalibrationString == "none") {
             out.pressureCalibration = Calibration::PressureCalibration::NONE;
         } else if (pressureCalibrationString == "physical") {
@@ -1221,16 +1247,19 @@
             out.pressureCalibration = Calibration::PressureCalibration::AMPLITUDE;
         } else if (pressureCalibrationString != "default") {
             ALOGW("Invalid value for touch.pressure.calibration: '%s'",
-                  pressureCalibrationString.string());
+                  pressureCalibrationString.c_str());
         }
     }
 
-    out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), out.pressureScale);
+    float pressureScale;
+    if (in.tryGetProperty("touch.pressure.scale", pressureScale)) {
+        out.pressureScale = pressureScale;
+    }
 
     // Orientation
     out.orientationCalibration = Calibration::OrientationCalibration::DEFAULT;
-    String8 orientationCalibrationString;
-    if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) {
+    std::string orientationCalibrationString;
+    if (in.tryGetProperty("touch.orientation.calibration", orientationCalibrationString)) {
         if (orientationCalibrationString == "none") {
             out.orientationCalibration = Calibration::OrientationCalibration::NONE;
         } else if (orientationCalibrationString == "interpolated") {
@@ -1239,36 +1268,39 @@
             out.orientationCalibration = Calibration::OrientationCalibration::VECTOR;
         } else if (orientationCalibrationString != "default") {
             ALOGW("Invalid value for touch.orientation.calibration: '%s'",
-                  orientationCalibrationString.string());
+                  orientationCalibrationString.c_str());
         }
     }
 
     // Distance
     out.distanceCalibration = Calibration::DistanceCalibration::DEFAULT;
-    String8 distanceCalibrationString;
-    if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) {
+    std::string distanceCalibrationString;
+    if (in.tryGetProperty("touch.distance.calibration", distanceCalibrationString)) {
         if (distanceCalibrationString == "none") {
             out.distanceCalibration = Calibration::DistanceCalibration::NONE;
         } else if (distanceCalibrationString == "scaled") {
             out.distanceCalibration = Calibration::DistanceCalibration::SCALED;
         } else if (distanceCalibrationString != "default") {
             ALOGW("Invalid value for touch.distance.calibration: '%s'",
-                  distanceCalibrationString.string());
+                  distanceCalibrationString.c_str());
         }
     }
 
-    out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), out.distanceScale);
+    float distanceScale;
+    if (in.tryGetProperty("touch.distance.scale", distanceScale)) {
+        out.distanceScale = distanceScale;
+    }
 
     out.coverageCalibration = Calibration::CoverageCalibration::DEFAULT;
-    String8 coverageCalibrationString;
-    if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) {
+    std::string coverageCalibrationString;
+    if (in.tryGetProperty("touch.coverage.calibration", coverageCalibrationString)) {
         if (coverageCalibrationString == "none") {
             out.coverageCalibration = Calibration::CoverageCalibration::NONE;
         } else if (coverageCalibrationString == "box") {
             out.coverageCalibration = Calibration::CoverageCalibration::BOX;
         } else if (coverageCalibrationString != "default") {
             ALOGW("Invalid value for touch.coverage.calibration: '%s'",
-                  coverageCalibrationString.string());
+                  coverageCalibrationString.c_str());
         }
     }
 }
@@ -1322,17 +1354,17 @@
     dump += INDENT4 "touch.size.calibration: ";
     dump += ftl::enum_string(mCalibration.sizeCalibration) + "\n";
 
-    if (mCalibration.haveSizeScale) {
-        dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", mCalibration.sizeScale);
+    if (mCalibration.sizeScale) {
+        dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", *mCalibration.sizeScale);
     }
 
-    if (mCalibration.haveSizeBias) {
-        dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n", mCalibration.sizeBias);
+    if (mCalibration.sizeBias) {
+        dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n", *mCalibration.sizeBias);
     }
 
-    if (mCalibration.haveSizeIsSummed) {
+    if (mCalibration.sizeIsSummed) {
         dump += StringPrintf(INDENT4 "touch.size.isSummed: %s\n",
-                             toString(mCalibration.sizeIsSummed));
+                             toString(*mCalibration.sizeIsSummed));
     }
 
     // Pressure
@@ -1350,8 +1382,8 @@
             ALOG_ASSERT(false);
     }
 
-    if (mCalibration.havePressureScale) {
-        dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n", mCalibration.pressureScale);
+    if (mCalibration.pressureScale) {
+        dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n", *mCalibration.pressureScale);
     }
 
     // Orientation
@@ -1381,8 +1413,8 @@
             ALOG_ASSERT(false);
     }
 
-    if (mCalibration.haveDistanceScale) {
-        dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", mCalibration.distanceScale);
+    if (mCalibration.distanceScale) {
+        dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", *mCalibration.distanceScale);
     }
 
     switch (mCalibration.coverageCalibration) {
@@ -1657,9 +1689,8 @@
 
         dispatchPointerUsage(when, readTime, policyFlags, pointerUsage);
     } else {
-        updateTouchSpots();
-
         if (!mCurrentMotionAborted) {
+            updateTouchSpots();
             dispatchButtonRelease(when, readTime, policyFlags);
             dispatchHoverExit(when, readTime, policyFlags);
             dispatchTouches(when, readTime, policyFlags);
@@ -1927,6 +1958,10 @@
 }
 
 void TouchInputMapper::abortTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+    if (mCurrentMotionAborted) {
+        // Current motion event was already aborted.
+        return;
+    }
     BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
     if (!currentIdBits.isEmpty()) {
         int32_t metaState = getContext()->getGlobalMetaState();
@@ -2172,7 +2207,7 @@
                     size = 0;
                 }
 
-                if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) {
+                if (mCalibration.sizeIsSummed && *mCalibration.sizeIsSummed) {
                     uint32_t touchingCount = mCurrentRawState.rawPointerData.touchingIdBits.count();
                     if (touchingCount > 1) {
                         touchMajor /= touchingCount;
@@ -2198,13 +2233,16 @@
                     toolMinor = toolMajor;
                 }
 
-                mCalibration.applySizeScaleAndBias(&touchMajor);
-                mCalibration.applySizeScaleAndBias(&touchMinor);
-                mCalibration.applySizeScaleAndBias(&toolMajor);
-                mCalibration.applySizeScaleAndBias(&toolMinor);
+                mCalibration.applySizeScaleAndBias(touchMajor);
+                mCalibration.applySizeScaleAndBias(touchMinor);
+                mCalibration.applySizeScaleAndBias(toolMajor);
+                mCalibration.applySizeScaleAndBias(toolMinor);
                 size *= mSizeScale;
                 break;
-            default:
+            case Calibration::SizeCalibration::DEFAULT:
+                LOG_ALWAYS_FATAL("Resolution should not be 'DEFAULT' at this point");
+                break;
+            case Calibration::SizeCalibration::NONE:
                 touchMajor = 0;
                 touchMinor = 0;
                 toolMajor = 0;
@@ -2301,10 +2339,9 @@
                 bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
                 top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
                 orientation -= M_PI_2;
-                if (mOrientedRanges.haveOrientation &&
-                    orientation < mOrientedRanges.orientation.min) {
+                if (mOrientedRanges.orientation && orientation < mOrientedRanges.orientation->min) {
                     orientation +=
-                            (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
+                            (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min);
                 }
                 break;
             case DISPLAY_ORIENTATION_180:
@@ -2313,10 +2350,9 @@
                 bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
                 top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
                 orientation -= M_PI;
-                if (mOrientedRanges.haveOrientation &&
-                    orientation < mOrientedRanges.orientation.min) {
+                if (mOrientedRanges.orientation && orientation < mOrientedRanges.orientation->min) {
                     orientation +=
-                            (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
+                            (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min);
                 }
                 break;
             case DISPLAY_ORIENTATION_270:
@@ -2325,10 +2361,9 @@
                 bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale;
                 top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale;
                 orientation += M_PI_2;
-                if (mOrientedRanges.haveOrientation &&
-                    orientation > mOrientedRanges.orientation.max) {
+                if (mOrientedRanges.orientation && orientation > mOrientedRanges.orientation->max) {
                     orientation -=
-                            (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
+                            (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min);
                 }
                 break;
             default:
@@ -4022,10 +4057,11 @@
     return AKEY_STATE_UNKNOWN;
 }
 
-bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-                                             const int32_t* keyCodes, uint8_t* outFlags) {
+bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask,
+                                             const std::vector<int32_t>& keyCodes,
+                                             uint8_t* outFlags) {
     for (const VirtualKey& virtualKey : mVirtualKeys) {
-        for (size_t i = 0; i < numCodes; i++) {
+        for (size_t i = 0; i < keyCodes.size(); i++) {
             if (virtualKey.keyCode == keyCodes[i]) {
                 outFlags[i] = 1;
             }
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index c948f56..3cb11aa 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -147,7 +147,7 @@
 
     int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override;
     int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
-    bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes,
+    bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
                                uint8_t* outFlags) override;
 
     void cancelTouch(nsecs_t when, nsecs_t readTime) override;
@@ -248,12 +248,9 @@
 
         SizeCalibration sizeCalibration;
 
-        bool haveSizeScale;
-        float sizeScale;
-        bool haveSizeBias;
-        float sizeBias;
-        bool haveSizeIsSummed;
-        bool sizeIsSummed;
+        std::optional<float> sizeScale;
+        std::optional<float> sizeBias;
+        std::optional<bool> sizeIsSummed;
 
         // Pressure
         enum class PressureCalibration {
@@ -264,8 +261,7 @@
         };
 
         PressureCalibration pressureCalibration;
-        bool havePressureScale;
-        float pressureScale;
+        std::optional<float> pressureScale;
 
         // Orientation
         enum class OrientationCalibration {
@@ -285,8 +281,7 @@
         };
 
         DistanceCalibration distanceCalibration;
-        bool haveDistanceScale;
-        float distanceScale;
+        std::optional<float> distanceScale;
 
         enum class CoverageCalibration {
             DEFAULT,
@@ -296,15 +291,15 @@
 
         CoverageCalibration coverageCalibration;
 
-        inline void applySizeScaleAndBias(float* outSize) const {
-            if (haveSizeScale) {
-                *outSize *= sizeScale;
+        inline void applySizeScaleAndBias(float& outSize) const {
+            if (sizeScale) {
+                outSize *= *sizeScale;
             }
-            if (haveSizeBias) {
-                *outSize += sizeBias;
+            if (sizeBias) {
+                outSize += *sizeBias;
             }
-            if (*outSize < 0) {
-                *outSize = 0;
+            if (outSize < 0) {
+                outSize = 0;
             }
         }
     } mCalibration;
@@ -475,35 +470,29 @@
         InputDeviceInfo::MotionRange y;
         InputDeviceInfo::MotionRange pressure;
 
-        bool haveSize;
-        InputDeviceInfo::MotionRange size;
+        std::optional<InputDeviceInfo::MotionRange> size;
 
-        bool haveTouchSize;
-        InputDeviceInfo::MotionRange touchMajor;
-        InputDeviceInfo::MotionRange touchMinor;
+        std::optional<InputDeviceInfo::MotionRange> touchMajor;
+        std::optional<InputDeviceInfo::MotionRange> touchMinor;
 
-        bool haveToolSize;
-        InputDeviceInfo::MotionRange toolMajor;
-        InputDeviceInfo::MotionRange toolMinor;
+        std::optional<InputDeviceInfo::MotionRange> toolMajor;
+        std::optional<InputDeviceInfo::MotionRange> toolMinor;
 
-        bool haveOrientation;
-        InputDeviceInfo::MotionRange orientation;
+        std::optional<InputDeviceInfo::MotionRange> orientation;
 
-        bool haveDistance;
-        InputDeviceInfo::MotionRange distance;
+        std::optional<InputDeviceInfo::MotionRange> distance;
 
-        bool haveTilt;
-        InputDeviceInfo::MotionRange tilt;
-
-        OrientedRanges() { clear(); }
+        std::optional<InputDeviceInfo::MotionRange> tilt;
 
         void clear() {
-            haveSize = false;
-            haveTouchSize = false;
-            haveToolSize = false;
-            haveOrientation = false;
-            haveDistance = false;
-            haveTilt = false;
+            size = std::nullopt;
+            touchMajor = std::nullopt;
+            touchMinor = std::nullopt;
+            toolMajor = std::nullopt;
+            toolMinor = std::nullopt;
+            orientation = std::nullopt;
+            distance = std::nullopt;
+            tilt = std::nullopt;
         }
     } mOrientedRanges;
 
@@ -527,7 +516,9 @@
     float mPointerXZoomScale;
     float mPointerYZoomScale;
 
-    // The maximum swipe width.
+    // The maximum swipe width between pointers to detect a swipe gesture
+    // in the number of pixels.Touches that are wider than this are translated
+    // into freeform gestures.
     float mPointerGestureMaxSwipeWidth;
 
     struct PointerDistanceHeapElement {
diff --git a/services/inputflinger/reporter/InputReporter.cpp b/services/inputflinger/reporter/InputReporter.cpp
index b591d3f..6f1eef6 100644
--- a/services/inputflinger/reporter/InputReporter.cpp
+++ b/services/inputflinger/reporter/InputReporter.cpp
@@ -35,7 +35,7 @@
 }
 
 sp<InputReporterInterface> createInputReporter() {
-    return new InputReporter();
+    return sp<InputReporter>::make();
 }
 
 } // namespace android
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 76a7c19..6da2145 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -41,8 +41,8 @@
         "EventHub_test.cpp",
         "FocusResolver_test.cpp",
         "IInputFlingerQuery.aidl",
-        "InputClassifier_test.cpp",
-        "InputClassifierConverter_test.cpp",
+        "InputProcessor_test.cpp",
+        "InputProcessorConverter_test.cpp",
         "InputDispatcher_test.cpp",
         "InputReader_test.cpp",
         "InputFlingerService_test.cpp",
diff --git a/services/inputflinger/tests/AnrTracker_test.cpp b/services/inputflinger/tests/AnrTracker_test.cpp
index b561da1..f8be48a 100644
--- a/services/inputflinger/tests/AnrTracker_test.cpp
+++ b/services/inputflinger/tests/AnrTracker_test.cpp
@@ -40,8 +40,8 @@
 TEST(AnrTrackerTest, MultipleEntries_RemoveToken) {
     AnrTracker tracker;
 
-    sp<IBinder> token1 = new BBinder();
-    sp<IBinder> token2 = new BBinder();
+    sp<IBinder> token1 = sp<BBinder>::make();
+    sp<IBinder> token2 = sp<BBinder>::make();
 
     tracker.insert(1, token1);
     tracker.insert(2, token2);
@@ -90,8 +90,8 @@
 TEST(AnrTrackerTest, MultipleTokens_MaintainsOrder) {
     AnrTracker tracker;
 
-    sp<IBinder> token1 = new BBinder();
-    sp<IBinder> token2 = new BBinder();
+    sp<IBinder> token1 = sp<BBinder>::make();
+    sp<IBinder> token2 = sp<BBinder>::make();
 
     tracker.insert(2, token1);
     tracker.insert(5, token2);
@@ -104,8 +104,8 @@
 TEST(AnrTrackerTest, MultipleTokens_IdenticalTimes) {
     AnrTracker tracker;
 
-    sp<IBinder> token1 = new BBinder();
-    sp<IBinder> token2 = new BBinder();
+    sp<IBinder> token1 = sp<BBinder>::make();
+    sp<IBinder> token2 = sp<BBinder>::make();
 
     tracker.insert(2, token1);
     tracker.insert(2, token2);
@@ -119,8 +119,8 @@
 TEST(AnrTrackerTest, MultipleTokens_IdenticalTimesRemove) {
     AnrTracker tracker;
 
-    sp<IBinder> token1 = new BBinder();
-    sp<IBinder> token2 = new BBinder();
+    sp<IBinder> token1 = sp<BBinder>::make();
+    sp<IBinder> token2 = sp<BBinder>::make();
 
     tracker.insert(2, token1);
     tracker.insert(2, token2);
@@ -152,12 +152,12 @@
     ASSERT_EQ(nullptr, tracker.firstToken());
 
     // Remove with non-matching token
-    tracker.erase(1, new BBinder());
+    tracker.erase(1, sp<BBinder>::make());
     ASSERT_EQ(1, tracker.firstTimeout());
     ASSERT_EQ(nullptr, tracker.firstToken());
 
     // Remove with both non-matching
-    tracker.erase(2, new BBinder());
+    tracker.erase(2, sp<BBinder>::make());
     ASSERT_EQ(1, tracker.firstTimeout());
     ASSERT_EQ(nullptr, tracker.firstToken());
 }
diff --git a/services/inputflinger/tests/EventHub_test.cpp b/services/inputflinger/tests/EventHub_test.cpp
index ef68a84..6ef6e44 100644
--- a/services/inputflinger/tests/EventHub_test.cpp
+++ b/services/inputflinger/tests/EventHub_test.cpp
@@ -180,6 +180,20 @@
 }
 
 /**
+ * Ensure that two identical devices get assigned unique descriptors from EventHub.
+ */
+TEST_F(EventHubTest, DevicesWithMatchingUniqueIdsAreUnique) {
+    std::unique_ptr<UinputHomeKey> keyboard2 = createUinputDevice<UinputHomeKey>();
+    int32_t deviceId2;
+    ASSERT_NO_FATAL_FAILURE(deviceId2 = waitForDeviceCreation());
+
+    ASSERT_NE(mEventHub->getDeviceIdentifier(mDeviceId).descriptor,
+              mEventHub->getDeviceIdentifier(deviceId2).descriptor);
+    keyboard2.reset();
+    waitForDeviceClose(deviceId2);
+}
+
+/**
  * Ensure that input_events are generated with monotonic clock.
  * That means input_event should receive a timestamp that is in the future of the time
  * before the event was sent.
diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp
index 91be4a3..5d5cf9c 100644
--- a/services/inputflinger/tests/FocusResolver_test.cpp
+++ b/services/inputflinger/tests/FocusResolver_test.cpp
@@ -50,16 +50,16 @@
 };
 
 TEST(FocusResolverTest, SetFocusedWindow) {
-    sp<IBinder> focusableWindowToken = new BBinder();
-    sp<IBinder> invisibleWindowToken = new BBinder();
-    sp<IBinder> unfocusableWindowToken = new BBinder();
+    sp<IBinder> focusableWindowToken = sp<BBinder>::make();
+    sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
+    sp<IBinder> unfocusableWindowToken = sp<BBinder>::make();
     std::vector<sp<WindowInfoHandle>> windows;
-    windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */,
-                                           true /* visible */));
-    windows.push_back(new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */,
-                                           false /* visible */));
-    windows.push_back(new FakeWindowHandle("unfocusable", unfocusableWindowToken,
-                                           false /* focusable */, true /* visible */));
+    windows.push_back(sp<FakeWindowHandle>::make("Focusable", focusableWindowToken,
+                                                 true /* focusable */, true /* visible */));
+    windows.push_back(sp<FakeWindowHandle>::make("Invisible", invisibleWindowToken,
+                                                 true /* focusable */, false /* visible */));
+    windows.push_back(sp<FakeWindowHandle>::make("unfocusable", unfocusableWindowToken,
+                                                 false /* focusable */, true /* visible */));
 
     // focusable window can get focused
     FocusRequest request;
@@ -85,10 +85,10 @@
 }
 
 TEST(FocusResolverTest, RemoveFocusFromFocusedWindow) {
-    sp<IBinder> focusableWindowToken = new BBinder();
+    sp<IBinder> focusableWindowToken = sp<BBinder>::make();
     std::vector<sp<WindowInfoHandle>> windows;
-    windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */,
-                                           true /* visible */));
+    windows.push_back(sp<FakeWindowHandle>::make("Focusable", focusableWindowToken,
+                                                 true /* focusable */, true /* visible */));
 
     FocusRequest request;
     request.displayId = 42;
@@ -109,24 +109,24 @@
 }
 
 TEST(FocusResolverTest, SetFocusedMirroredWindow) {
-    sp<IBinder> focusableWindowToken = new BBinder();
-    sp<IBinder> invisibleWindowToken = new BBinder();
-    sp<IBinder> unfocusableWindowToken = new BBinder();
+    sp<IBinder> focusableWindowToken = sp<BBinder>::make();
+    sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
+    sp<IBinder> unfocusableWindowToken = sp<BBinder>::make();
     std::vector<sp<WindowInfoHandle>> windows;
-    windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
-                                           true /* visible */));
-    windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
-                                           true /* visible */));
+    windows.push_back(sp<FakeWindowHandle>::make("Mirror1", focusableWindowToken,
+                                                 true /* focusable */, true /* visible */));
+    windows.push_back(sp<FakeWindowHandle>::make("Mirror1", focusableWindowToken,
+                                                 true /* focusable */, true /* visible */));
 
-    windows.push_back(new FakeWindowHandle("Mirror2Visible", invisibleWindowToken,
-                                           true /* focusable */, true /* visible */));
-    windows.push_back(new FakeWindowHandle("Mirror2Invisible", invisibleWindowToken,
-                                           true /* focusable */, false /* visible */));
+    windows.push_back(sp<FakeWindowHandle>::make("Mirror2Visible", invisibleWindowToken,
+                                                 true /* focusable */, true /* visible */));
+    windows.push_back(sp<FakeWindowHandle>::make("Mirror2Invisible", invisibleWindowToken,
+                                                 true /* focusable */, false /* visible */));
 
-    windows.push_back(new FakeWindowHandle("Mirror3Focusable", unfocusableWindowToken,
-                                           true /* focusable */, true /* visible */));
-    windows.push_back(new FakeWindowHandle("Mirror3Unfocusable", unfocusableWindowToken,
-                                           false /* focusable */, true /* visible */));
+    windows.push_back(sp<FakeWindowHandle>::make("Mirror3Focusable", unfocusableWindowToken,
+                                                 true /* focusable */, true /* visible */));
+    windows.push_back(sp<FakeWindowHandle>::make("Mirror3Unfocusable", unfocusableWindowToken,
+                                                 false /* focusable */, true /* visible */));
 
     // mirrored window can get focused
     FocusRequest request;
@@ -149,10 +149,11 @@
 }
 
 TEST(FocusResolverTest, SetInputWindows) {
-    sp<IBinder> focusableWindowToken = new BBinder();
+    sp<IBinder> focusableWindowToken = sp<BBinder>::make();
     std::vector<sp<WindowInfoHandle>> windows;
-    sp<FakeWindowHandle> window = new FakeWindowHandle("Focusable", focusableWindowToken,
-                                                       true /* focusable */, true /* visible */);
+    sp<FakeWindowHandle> window =
+            sp<FakeWindowHandle>::make("Focusable", focusableWindowToken, true /* focusable */,
+                                       true /* visible */);
     windows.push_back(window);
 
     // focusable window can get focused
@@ -171,12 +172,12 @@
 }
 
 TEST(FocusResolverTest, FocusRequestsCanBePending) {
-    sp<IBinder> invisibleWindowToken = new BBinder();
+    sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
     std::vector<sp<WindowInfoHandle>> windows;
 
     sp<FakeWindowHandle> invisibleWindow =
-            new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */,
-                                 false /* visible */);
+            sp<FakeWindowHandle>::make("Invisible", invisibleWindowToken, true /* focusable */,
+                                       false /* visible */);
     windows.push_back(invisibleWindow);
 
     // invisible window cannot get focused
@@ -195,11 +196,12 @@
 }
 
 TEST(FocusResolverTest, FocusRequestsArePersistent) {
-    sp<IBinder> windowToken = new BBinder();
+    sp<IBinder> windowToken = sp<BBinder>::make();
     std::vector<sp<WindowInfoHandle>> windows;
 
-    sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
-                                                       false /* focusable */, true /* visible */);
+    sp<FakeWindowHandle> window =
+            sp<FakeWindowHandle>::make("Test Window", windowToken, false /* focusable */,
+                                       true /* visible */);
     windows.push_back(window);
 
     // non-focusable window cannot get focused
@@ -236,17 +238,17 @@
 }
 
 TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) {
-    sp<IBinder> hostWindowToken = new BBinder();
+    sp<IBinder> hostWindowToken = sp<BBinder>::make();
     std::vector<sp<WindowInfoHandle>> windows;
 
     sp<FakeWindowHandle> hostWindow =
-            new FakeWindowHandle("Host Window", hostWindowToken, true /* focusable */,
-                                 true /* visible */);
+            sp<FakeWindowHandle>::make("Host Window", hostWindowToken, true /* focusable */,
+                                       true /* visible */);
     windows.push_back(hostWindow);
-    sp<IBinder> embeddedWindowToken = new BBinder();
+    sp<IBinder> embeddedWindowToken = sp<BBinder>::make();
     sp<FakeWindowHandle> embeddedWindow =
-            new FakeWindowHandle("Embedded Window", embeddedWindowToken, true /* focusable */,
-                                 true /* visible */);
+            sp<FakeWindowHandle>::make("Embedded Window", embeddedWindowToken, true /* focusable */,
+                                       true /* visible */);
     windows.push_back(embeddedWindow);
 
     FocusRequest request;
@@ -287,11 +289,12 @@
     ASSERT_FALSE(changes);
 }
 TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) {
-    sp<IBinder> windowToken = new BBinder();
+    sp<IBinder> windowToken = sp<BBinder>::make();
     std::vector<sp<WindowInfoHandle>> windows;
 
-    sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
-                                                       true /* focusable */, true /* visible */);
+    sp<FakeWindowHandle> window =
+            sp<FakeWindowHandle>::make("Test Window", windowToken, true /* focusable */,
+                                       true /* visible */);
     windows.push_back(window);
 
     FocusRequest request;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index a167271..cd853a6 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -45,10 +45,10 @@
 using namespace ftl::flag_operators;
 
 // An arbitrary time value.
-static const nsecs_t ARBITRARY_TIME = 1234;
+static constexpr nsecs_t ARBITRARY_TIME = 1234;
 
 // An arbitrary device id.
-static const int32_t DEVICE_ID = 1;
+static constexpr int32_t DEVICE_ID = 1;
 
 // An arbitrary display id.
 static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
@@ -58,12 +58,17 @@
         AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
 static constexpr int32_t POINTER_2_DOWN =
         AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+static constexpr int32_t POINTER_3_DOWN =
+        AMOTION_EVENT_ACTION_POINTER_DOWN | (3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
 static constexpr int32_t POINTER_1_UP =
         AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
 
-// An arbitrary injector pid / uid pair that has permission to inject events.
-static const int32_t INJECTOR_PID = 999;
-static const int32_t INJECTOR_UID = 1001;
+// The default pid and uid for windows created by the test.
+static constexpr int32_t WINDOW_PID = 999;
+static constexpr int32_t WINDOW_UID = 1001;
+
+// The default policy flags to use for event injection by tests.
+static constexpr uint32_t DEFAULT_POLICY_FLAGS = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
 
 // An arbitrary pid of the gesture monitor window
 static constexpr int32_t MONITOR_PID = 2001;
@@ -409,7 +414,6 @@
 
     void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) override {}
 
-    void notifyUntrustedTouch(const std::string& obscuringPackage) override {}
     void notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
                            InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
                            const std::vector<float>& values) override {}
@@ -472,10 +476,6 @@
 
     void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
 
-    bool checkInjectEventsPermissionNonReentrant(int32_t pid, int32_t uid) override {
-        return pid == INJECTOR_PID && uid == INJECTOR_UID;
-    }
-
     void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {
         std::scoped_lock lock(mLock);
         mOnPointerDownToken = newToken;
@@ -500,6 +500,11 @@
         verify(*mFilteredEvent);
         mFilteredEvent = nullptr;
     }
+
+    bool isPerDisplayTouchModeEnabled() {
+        // TODO(b/198499018): Make this a regular property once per display touch mode is enabled
+        return false;
+    }
 };
 
 // --- InputDispatcherTest ---
@@ -510,7 +515,7 @@
     std::unique_ptr<InputDispatcher> mDispatcher;
 
     void SetUp() override {
-        mFakePolicy = new FakeInputDispatcherPolicy();
+        mFakePolicy = sp<FakeInputDispatcherPolicy>::make();
         mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy, STALE_EVENT_TIMEOUT);
         mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
         // Start InputDispatcher thread
@@ -560,8 +565,8 @@
                      /*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
                      ARBITRARY_TIME);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject key events with undefined action.";
 
     // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
@@ -569,8 +574,8 @@
                      INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
                      ARBITRARY_TIME, ARBITRARY_TIME);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject key events with ACTION_MULTIPLE.";
 }
 
@@ -599,8 +604,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with undefined action.";
 
     // Rejects pointer down with invalid index.
@@ -611,8 +616,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with pointer down index too large.";
 
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -623,8 +628,8 @@
                      identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with pointer down index too small.";
 
     // Rejects pointer up with invalid index.
@@ -635,8 +640,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with pointer up index too large.";
 
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -647,8 +652,8 @@
                      identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with pointer up index too small.";
 
     // Rejects motion events with invalid number of pointers.
@@ -659,8 +664,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 0, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with 0 pointers.";
 
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -670,8 +675,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with more than MAX_POINTERS pointers.";
 
     // Rejects motion events with invalid pointer ids.
@@ -683,8 +688,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with pointer ids less than 0.";
 
     pointerProperties[0].id = MAX_POINTER_ID + 1;
@@ -695,8 +700,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
 
     // Rejects motion events with duplicate pointer ids.
@@ -709,8 +714,8 @@
                      ARBITRARY_TIME,
                      /*pointerCount*/ 2, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
-              mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
-                                            InputEventInjectionSync::NONE, 0ms, 0))
+              mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+                                            0ms, 0))
             << "Should reject motion events with duplicate pointer ids.";
 }
 
@@ -747,7 +752,7 @@
 public:
     FakeApplicationHandle() {
         mInfo.name = "Fake Application";
-        mInfo.token = new BBinder();
+        mInfo.token = sp<BBinder>::make();
         mInfo.dispatchingTimeoutMillis =
                 std::chrono::duration_cast<std::chrono::milliseconds>(DISPATCHING_TIMEOUT).count();
     }
@@ -1013,8 +1018,8 @@
         mInfo.globalScaleFactor = 1.0;
         mInfo.touchableRegion.clear();
         mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
-        mInfo.ownerPid = INJECTOR_PID;
-        mInfo.ownerUid = INJECTOR_UID;
+        mInfo.ownerPid = WINDOW_PID;
+        mInfo.ownerUid = WINDOW_UID;
         mInfo.displayId = displayId;
         mInfo.inputConfig = WindowInfo::InputConfig::DEFAULT;
     }
@@ -1023,8 +1028,8 @@
             const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
             const std::unique_ptr<InputDispatcher>& dispatcher, int32_t displayId) {
         sp<FakeWindowHandle> handle =
-                new FakeWindowHandle(inputApplicationHandle, dispatcher, mInfo.name + "(Mirror)",
-                                     displayId, mInfo.token);
+                sp<FakeWindowHandle>::make(inputApplicationHandle, dispatcher,
+                                           mInfo.name + "(Mirror)", displayId, mInfo.token);
         return handle;
     }
 
@@ -1296,7 +1301,8 @@
         int32_t displayId = ADISPLAY_ID_NONE,
         InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
         std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
-        bool allowKeyRepeat = true) {
+        bool allowKeyRepeat = true, std::optional<int32_t> targetUid = {},
+        uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
     KeyEvent event;
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
@@ -1305,13 +1311,11 @@
                      INVALID_HMAC, action, /* flags */ 0, AKEYCODE_A, KEY_A, AMETA_NONE,
                      repeatCount, currentTime, currentTime);
 
-    int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
     if (!allowKeyRepeat) {
         policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
     }
     // Inject event until dispatch out.
-    return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, syncMode,
-                                        injectionTimeout, policyFlags);
+    return dispatcher->injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
 }
 
 static InputEventInjectionResult injectKeyDown(const std::unique_ptr<InputDispatcher>& dispatcher,
@@ -1454,10 +1458,10 @@
 static InputEventInjectionResult injectMotionEvent(
         const std::unique_ptr<InputDispatcher>& dispatcher, const MotionEvent& event,
         std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
-        InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT) {
-    return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, injectionMode,
-                                        injectionTimeout,
-                                        POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+        InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
+        std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
+    return dispatcher->injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
+                                        policyFlags);
 }
 
 static InputEventInjectionResult injectMotionEvent(
@@ -1467,7 +1471,8 @@
                                         AMOTION_EVENT_INVALID_CURSOR_POSITION},
         std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
         InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
-        nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC)) {
+        nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
+        std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
     MotionEvent event = MotionEventBuilder(action, source)
                                 .displayId(displayId)
                                 .eventTime(eventTime)
@@ -1479,7 +1484,8 @@
                                 .build();
 
     // Inject event until dispatch out.
-    return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode);
+    return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode, targetUid,
+                             policyFlags);
 }
 
 static InputEventInjectionResult injectMotionDown(
@@ -1557,8 +1563,8 @@
 TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Window that breaks its input channel",
-                                 ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher,
+                                       "Window that breaks its input channel", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
 
@@ -1569,8 +1575,8 @@
 
 TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1583,8 +1589,8 @@
 
 TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     // Inject a MotionEvent to an unknown display.
@@ -1603,8 +1609,8 @@
  */
 TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
     window->setFrame(Rect(0, 0, 100, 100));
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -1622,8 +1628,8 @@
  */
 TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
     window->setFrame(Rect(0, 0, 100, 100));
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -1641,9 +1647,9 @@
 TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> windowTop =
-            new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
     sp<FakeWindowHandle> windowSecond =
-            new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}});
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1665,10 +1671,10 @@
 TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> foregroundWindow =
-            new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
     foregroundWindow->setDupTouchToWallpaper(true);
     sp<FakeWindowHandle> wallpaperWindow =
-            new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
     wallpaperWindow->setIsWallpaper(true);
     constexpr int expectedWallpaperFlags =
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1709,10 +1715,10 @@
 TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> foregroundWindow =
-            new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
     foregroundWindow->setDupTouchToWallpaper(true);
     sp<FakeWindowHandle> wallpaperWindow =
-            new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
     wallpaperWindow->setIsWallpaper(true);
     constexpr int expectedWallpaperFlags =
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1753,11 +1759,11 @@
 TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
     window->setDupTouchToWallpaper(true);
 
     sp<FakeWindowHandle> wallpaperWindow =
-            new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
     wallpaperWindow->setIsWallpaper(true);
     constexpr int expectedWallpaperFlags =
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1808,17 +1814,17 @@
 TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> leftWindow =
-            new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
     leftWindow->setFrame(Rect(0, 0, 200, 200));
     leftWindow->setDupTouchToWallpaper(true);
 
     sp<FakeWindowHandle> rightWindow =
-            new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
     rightWindow->setFrame(Rect(200, 0, 400, 200));
     rightWindow->setDupTouchToWallpaper(true);
 
     sp<FakeWindowHandle> wallpaperWindow =
-            new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
     wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
     wallpaperWindow->setIsWallpaper(true);
     constexpr int expectedWallpaperFlags =
@@ -1895,7 +1901,7 @@
 TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Window", DISPLAY_ID);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Window", DISPLAY_ID);
 
     mDispatcher->setInputWindows({{DISPLAY_ID, {window}}});
     NotifyMotionArgs args;
@@ -1919,11 +1925,11 @@
 TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window1 =
-            new FakeWindowHandle(application, mDispatcher, "Window1", DISPLAY_ID);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
     window1->setTouchableRegion(Region{{0, 0, 100, 100}});
     window1->setTouchable(false);
     sp<FakeWindowHandle> window2 =
-            new FakeWindowHandle(application, mDispatcher, "Window2", DISPLAY_ID);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
     window2->setTouchableRegion(Region{{100, 0, 200, 100}});
 
     mDispatcher->setInputWindows({{DISPLAY_ID, {window1, window2}}});
@@ -1942,13 +1948,84 @@
     window2->consumeMotionDown();
 }
 
+/**
+ * When splitting touch events the downTime should be adjusted such that the downTime corresponds
+ * to the event time of the first ACTION_DOWN sent to the particular window.
+ */
+TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) {
+    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+    sp<FakeWindowHandle> window1 =
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
+    window1->setTouchableRegion(Region{{0, 0, 100, 100}});
+    sp<FakeWindowHandle> window2 =
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
+    window2->setTouchableRegion(Region{{100, 0, 200, 100}});
+
+    mDispatcher->setInputWindows({{DISPLAY_ID, {window1, window2}}});
+
+    NotifyMotionArgs args;
+    // Touch down on the first window
+    mDispatcher->notifyMotion(&(args = generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}})));
+
+    mDispatcher->waitForIdle();
+    InputEvent* inputEvent1 = window1->consume();
+    window2->assertNoEvents();
+    MotionEvent& motionEvent1 = static_cast<MotionEvent&>(*inputEvent1);
+    nsecs_t downTimeForWindow1 = motionEvent1.getDownTime();
+    ASSERT_EQ(motionEvent1.getDownTime(), motionEvent1.getEventTime());
+
+    // Now touch down on the window with another pointer
+    mDispatcher->notifyMotion(&(args = generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}})));
+    mDispatcher->waitForIdle();
+    InputEvent* inputEvent2 = window2->consume();
+    MotionEvent& motionEvent2 = static_cast<MotionEvent&>(*inputEvent2);
+    nsecs_t downTimeForWindow2 = motionEvent2.getDownTime();
+    ASSERT_NE(downTimeForWindow1, downTimeForWindow2);
+    ASSERT_EQ(motionEvent2.getDownTime(), motionEvent2.getEventTime());
+
+    // Now move the pointer on the second window
+    mDispatcher->notifyMotion(
+            &(args = generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}})));
+    mDispatcher->waitForIdle();
+    InputEvent* inputEvent3 = window2->consume();
+    MotionEvent& motionEvent3 = static_cast<MotionEvent&>(*inputEvent3);
+    ASSERT_EQ(motionEvent3.getDownTime(), downTimeForWindow2);
+
+    // Now add new touch down on the second window
+    mDispatcher->notifyMotion(
+            &(args = generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}})));
+    mDispatcher->waitForIdle();
+    InputEvent* inputEvent4 = window2->consume();
+    MotionEvent& motionEvent4 = static_cast<MotionEvent&>(*inputEvent4);
+    ASSERT_EQ(motionEvent4.getDownTime(), downTimeForWindow2);
+
+    // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line
+    window1->consumeMotionMove();
+    window1->assertNoEvents();
+
+    // Now move the pointer on the first window
+    mDispatcher->notifyMotion(
+            &(args = generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}})));
+    mDispatcher->waitForIdle();
+    InputEvent* inputEvent5 = window1->consume();
+    MotionEvent& motionEvent5 = static_cast<MotionEvent&>(*inputEvent5);
+    ASSERT_EQ(motionEvent5.getDownTime(), downTimeForWindow1);
+
+    mDispatcher->notifyMotion(&(
+            args = generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}})));
+    mDispatcher->waitForIdle();
+    InputEvent* inputEvent6 = window1->consume();
+    MotionEvent& motionEvent6 = static_cast<MotionEvent&>(*inputEvent6);
+    ASSERT_EQ(motionEvent6.getDownTime(), downTimeForWindow1);
+}
+
 TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> windowLeft =
-            new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
     windowLeft->setFrame(Rect(0, 0, 600, 800));
     sp<FakeWindowHandle> windowRight =
-            new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
     windowRight->setFrame(Rect(600, 0, 1200, 800));
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -2054,7 +2131,7 @@
 TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
     window->setFrame(Rect(0, 0, 1200, 800));
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -2135,10 +2212,10 @@
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
     sp<FakeWindowHandle> windowLeft =
-            new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
     windowLeft->setFrame(Rect(0, 0, 600, 800));
     sp<FakeWindowHandle> windowRight =
-            new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
     windowRight->setFrame(Rect(600, 0, 1200, 800));
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -2156,8 +2233,8 @@
 
 TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
     window->setFocusable(true);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -2181,8 +2258,8 @@
 
 TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
 
@@ -2204,8 +2281,8 @@
 
 TEST_F(InputDispatcherTest, InterceptKeyByPolicy) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
     window->setFocusable(true);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -2226,8 +2303,8 @@
 
 TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
     window->setFocusable(true);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -2254,15 +2331,17 @@
 TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
     // There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "First Window", ADISPLAY_ID_DEFAULT);
     window->setWatchOutsideTouch(true);
     window->setFrame(Rect{0, 0, 100, 100});
     sp<FakeWindowHandle> secondWindow =
-            new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+                                       ADISPLAY_ID_DEFAULT);
     secondWindow->setFrame(Rect{100, 100, 200, 200});
     sp<FakeWindowHandle> thirdWindow =
-            new FakeWindowHandle(application, mDispatcher, "Third Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window",
+                                       ADISPLAY_ID_DEFAULT);
     thirdWindow->setFrame(Rect{200, 200, 300, 300});
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, secondWindow, thirdWindow}}});
 
@@ -2293,6 +2372,35 @@
     thirdWindow->consumeMotionDown();
 }
 
+TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
+    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(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.
  *
@@ -2335,13 +2443,14 @@
 
         // Add two windows to the display. Their frames are represented in the display space.
         sp<FakeWindowHandle> firstWindow =
-                new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+                sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+                                           ADISPLAY_ID_DEFAULT);
         firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
         addWindow(firstWindow);
 
         sp<FakeWindowHandle> secondWindow =
-                new FakeWindowHandle(application, mDispatcher, "Second Window",
-                                     ADISPLAY_ID_DEFAULT);
+                sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+                                           ADISPLAY_ID_DEFAULT);
         secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
         addWindow(secondWindow);
         return {std::move(firstWindow), std::move(secondWindow)};
@@ -2442,9 +2551,11 @@
 
     // Create a couple of windows
     sp<FakeWindowHandle> firstWindow =
-            new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+                                       ADISPLAY_ID_DEFAULT);
     sp<FakeWindowHandle> secondWindow =
-            new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+                                       ADISPLAY_ID_DEFAULT);
 
     // Add the windows to the dispatcher
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2493,13 +2604,13 @@
 
     // Create a couple of windows + a spy window
     sp<FakeWindowHandle> spyWindow =
-            new FakeWindowHandle(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
     spyWindow->setTrustedOverlay(true);
     spyWindow->setSpy(true);
     sp<FakeWindowHandle> firstWindow =
-            new FakeWindowHandle(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
     sp<FakeWindowHandle> secondWindow =
-            new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
 
     // Add the windows to the dispatcher
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, firstWindow, secondWindow}}});
@@ -2540,10 +2651,12 @@
 
     // Create a couple of windows
     sp<FakeWindowHandle> firstWindow =
-            new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+                                       ADISPLAY_ID_DEFAULT);
     firstWindow->setPreventSplitting(true);
     sp<FakeWindowHandle> secondWindow =
-            new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+                                       ADISPLAY_ID_DEFAULT);
     secondWindow->setPreventSplitting(true);
 
     // Add the windows to the dispatcher
@@ -2615,11 +2728,13 @@
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
     sp<FakeWindowHandle> firstWindow =
-            new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+                                       ADISPLAY_ID_DEFAULT);
     firstWindow->setFrame(Rect(0, 0, 600, 400));
 
     sp<FakeWindowHandle> secondWindow =
-            new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+                                       ADISPLAY_ID_DEFAULT);
     secondWindow->setFrame(Rect(0, 400, 600, 800));
 
     // Add the windows to the dispatcher
@@ -2679,11 +2794,13 @@
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
     sp<FakeWindowHandle> firstWindow =
-            new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+                                       ADISPLAY_ID_DEFAULT);
     firstWindow->setFrame(Rect(0, 0, 600, 400));
 
     sp<FakeWindowHandle> secondWindow =
-            new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+                                       ADISPLAY_ID_DEFAULT);
     secondWindow->setFrame(Rect(0, 400, 600, 800));
 
     // Add the windows to the dispatcher
@@ -2744,10 +2861,10 @@
 TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> firstWindowInPrimary =
-            new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
     firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
     sp<FakeWindowHandle> secondWindowInPrimary =
-            new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
     secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
 
     sp<FakeWindowHandle> mirrorWindowInPrimary =
@@ -2803,10 +2920,10 @@
 TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> firstWindowInPrimary =
-            new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
     firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
     sp<FakeWindowHandle> secondWindowInPrimary =
-            new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
     secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
 
     sp<FakeWindowHandle> mirrorWindowInPrimary =
@@ -2858,8 +2975,8 @@
 
 TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
 
     window->setFocusable(true);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -2876,8 +2993,8 @@
 
 TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
 
@@ -2891,8 +3008,8 @@
 // If a window is touchable, but does not have focus, it should receive motion events, but not keys
 TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
 
@@ -2914,11 +3031,13 @@
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
     sp<FakeWindowHandle> firstWindow =
-            new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+                                       ADISPLAY_ID_DEFAULT);
     firstWindow->setFrame(Rect(0, 0, 600, 400));
 
     sp<FakeWindowHandle> secondWindow =
-            new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+                                       ADISPLAY_ID_DEFAULT);
     secondWindow->setFrame(Rect(0, 400, 600, 800));
 
     // Add the windows to the dispatcher
@@ -2969,7 +3088,7 @@
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
     sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
     graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
@@ -3059,7 +3178,7 @@
 TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
 
     FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
 
@@ -3099,8 +3218,8 @@
 
 TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
 
     FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
@@ -3116,8 +3235,8 @@
     FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
 
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
 
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -3141,8 +3260,8 @@
 
 TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     window->setWindowOffset(20, 40);
     window->setWindowTransform(0, 1, -1, 0);
@@ -3170,8 +3289,8 @@
 
 TEST_F(InputDispatcherTest, TestMoveEvent) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Fake Window", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
 
@@ -3201,8 +3320,8 @@
  */
 TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Test window", ADISPLAY_ID_DEFAULT);
     const WindowInfo& windowInfo = *window->getInfo();
 
     // Set focused application.
@@ -3221,7 +3340,7 @@
 
     SCOPED_TRACE("Disable touch mode");
     mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid,
-                                /* hasPermission */ true);
+                                true /*hasPermission*/, ADISPLAY_ID_DEFAULT);
     window->consumeTouchModeEvent(false);
     window->setFocusable(true);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -3235,7 +3354,7 @@
 
     SCOPED_TRACE("Enable touch mode again");
     mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid,
-                                /* hasPermission */ true);
+                                true /*hasPermission*/, ADISPLAY_ID_DEFAULT);
     window->consumeTouchModeEvent(true);
     window->setFocusable(true);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -3247,8 +3366,8 @@
 
 TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Test window", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
     window->setFocusable(true);
@@ -3286,8 +3405,8 @@
 
 TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Test window", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
@@ -3391,9 +3510,9 @@
 TEST_F(InputDispatcherTest, SetFocusedWindow) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> windowTop =
-            new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
     sp<FakeWindowHandle> windowSecond =
-            new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
     // Top window is also focusable but is not granted focus.
@@ -3414,7 +3533,7 @@
 TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
     window->setFocusable(true);
@@ -3434,7 +3553,7 @@
 TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
     window->setFocusable(false);
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
@@ -3452,9 +3571,9 @@
 TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> windowTop =
-            new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
     sp<FakeWindowHandle> windowSecond =
-            new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
     windowTop->setFocusable(true);
@@ -3477,9 +3596,9 @@
 TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestFocusTokenNotFocused) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> windowTop =
-            new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
     sp<FakeWindowHandle> windowSecond =
-            new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
     windowTop->setFocusable(true);
@@ -3498,10 +3617,10 @@
 TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
     sp<FakeWindowHandle> previousFocusedWindow =
-            new FakeWindowHandle(application, mDispatcher, "previousFocusedWindow",
-                                 ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow",
+                                       ADISPLAY_ID_DEFAULT);
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
     window->setFocusable(true);
@@ -3536,7 +3655,7 @@
 TEST_F(InputDispatcherTest, DisplayRemoved) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT);
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
     // window is granted focus.
@@ -3574,14 +3693,14 @@
  * FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
  */
 TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
-    constexpr int32_t SLIPPERY_PID = INJECTOR_PID + 1;
-    constexpr int32_t SLIPPERY_UID = INJECTOR_UID + 1;
+    constexpr int32_t SLIPPERY_PID = WINDOW_PID + 1;
+    constexpr int32_t SLIPPERY_UID = WINDOW_UID + 1;
 
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
     sp<FakeWindowHandle> slipperyExitWindow =
-            new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
     slipperyExitWindow->setSlippery(true);
     // Make sure this one overlaps the bottom window
     slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
@@ -3590,7 +3709,7 @@
     slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID);
 
     sp<FakeWindowHandle> slipperyEnterWindow =
-            new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
     slipperyExitWindow->setFrame(Rect(0, 0, 100, 100));
 
     mDispatcher->setInputWindows(
@@ -3624,7 +3743,7 @@
     sp<FakeWindowHandle> mWindow;
 
     virtual void SetUp() override {
-        mFakePolicy = new FakeInputDispatcherPolicy();
+        mFakePolicy = sp<FakeInputDispatcherPolicy>::make();
         mFakePolicy->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
         mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy);
         mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
@@ -3635,7 +3754,7 @@
 
     void setUpWindow() {
         mApp = std::make_shared<FakeApplicationHandle>();
-        mWindow = new FakeWindowHandle(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+        mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
 
         mWindow->setFocusable(true);
         mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
@@ -3772,7 +3891,7 @@
 
         application1 = std::make_shared<FakeApplicationHandle>();
         windowInPrimary =
-                new FakeWindowHandle(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT);
+                sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT);
 
         // Set focus window for primary display, but focused display would be second one.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
@@ -3783,7 +3902,7 @@
 
         application2 = std::make_shared<FakeApplicationHandle>();
         windowInSecondary =
-                new FakeWindowHandle(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
+                sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
         // Set focus to second display window.
         // Set focus display to second one.
         mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
@@ -3912,7 +4031,7 @@
 
 TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) {
     sp<FakeWindowHandle> secondWindowInPrimary =
-            new FakeWindowHandle(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
     secondWindowInPrimary->setFocusable(true);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowInPrimary, secondWindowInPrimary}}});
     setFocusedWindow(secondWindowInPrimary);
@@ -4081,8 +4200,8 @@
 
         std::shared_ptr<InputApplicationHandle> application =
                 std::make_shared<FakeApplicationHandle>();
-        mWindow =
-                new FakeWindowHandle(application, mDispatcher, "Test Window", ADISPLAY_ID_DEFAULT);
+        mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window",
+                                             ADISPLAY_ID_DEFAULT);
 
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
         mWindow->setFocusable(true);
@@ -4102,7 +4221,7 @@
         const int32_t additionalPolicyFlags =
                 POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
         ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-                  mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+                  mDispatcher->injectInputEvent(&event, {} /*targetUid*/,
                                                 InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
                                                 policyFlags | additionalPolicyFlags));
 
@@ -4137,7 +4256,7 @@
 
         const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
         ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-                  mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+                  mDispatcher->injectInputEvent(&event, {} /*targetUid*/,
                                                 InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
                                                 policyFlags | additionalPolicyFlags));
 
@@ -4186,11 +4305,11 @@
         std::shared_ptr<FakeApplicationHandle> application =
                 std::make_shared<FakeApplicationHandle>();
         mUnfocusedWindow =
-                new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+                sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
         mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
 
         mFocusedWindow =
-                new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+                sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
         mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
 
         // Set focused application.
@@ -4296,12 +4415,12 @@
 
         std::shared_ptr<FakeApplicationHandle> application =
                 std::make_shared<FakeApplicationHandle>();
-        mWindow1 = new FakeWindowHandle(application, mDispatcher, "Fake Window 1",
-                                        ADISPLAY_ID_DEFAULT);
+        mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1",
+                                              ADISPLAY_ID_DEFAULT);
         mWindow1->setFrame(Rect(0, 0, 100, 100));
 
-        mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2",
-                                        ADISPLAY_ID_DEFAULT, mWindow1->getToken());
+        mWindow2 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 2",
+                                              ADISPLAY_ID_DEFAULT, mWindow1->getToken());
         mWindow2->setFrame(Rect(100, 100, 200, 200));
 
         mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}});
@@ -4483,8 +4602,8 @@
 
         mApplication = std::make_shared<FakeApplicationHandle>();
         mApplication->setDispatchingTimeout(20ms);
-        mWindow =
-                new FakeWindowHandle(mApplication, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+        mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow",
+                                             ADISPLAY_ID_DEFAULT);
         mWindow->setFrame(Rect(0, 0, 30, 30));
         mWindow->setDispatchingTimeout(30ms);
         mWindow->setFocusable(true);
@@ -4518,7 +4637,7 @@
 
     sp<FakeWindowHandle> addSpyWindow() {
         sp<FakeWindowHandle> spy =
-                new FakeWindowHandle(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
+                sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
         spy->setTrustedOverlay(true);
         spy->setFocusable(false);
         spy->setSpy(true);
@@ -4599,6 +4718,36 @@
 
 // We have a focused application, but no focused window
 TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
+    FocusRequest request;
+    request.token = nullptr;
+    request.windowName = "";
+    request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+    request.displayId = mWindow->getInfo()->displayId;
+    mDispatcher->setFocusedWindow(request);
+    mWindow->consumeFocusEvent(false);
+
+    // taps on the window work as normal
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               WINDOW_LOCATION));
+    ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
+    mDispatcher->waitForIdle();
+    mFakePolicy->assertNotifyAnrWasNotCalled();
+
+    // Once a focused event arrives, we get an ANR for this application
+    // We specify the injection timeout to be smaller than the application timeout, to ensure that
+    // injection times out (instead of failing).
+    const InputEventInjectionResult result =
+            injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT,
+                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
+    ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
+    const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
+    mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
+    ASSERT_TRUE(mDispatcher->waitForIdle());
+}
+
+// We have a focused application, but we are waiting on the requested window to become focusable
+TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_PendingFocusedRequest) {
     mWindow->setFocusable(false);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
     mWindow->consumeFocusEvent(false);
@@ -4619,7 +4768,7 @@
                       InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
     ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
     const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
     ASSERT_TRUE(mDispatcher->waitForIdle());
 }
 
@@ -4644,7 +4793,7 @@
     const int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
 
     InputEventInjectionResult result =
-            mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+            mDispatcher->injectInputEvent(&event, {} /* targetUid */,
                                           InputEventInjectionSync::WAIT_FOR_RESULT,
                                           INJECT_EVENT_TIMEOUT, policyFlags);
     ASSERT_EQ(InputEventInjectionResult::FAILED, result)
@@ -4669,11 +4818,10 @@
             injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT,
                       InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
     ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
-    const std::chrono::duration appTimeout =
-            mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(appTimeout, mApplication);
+    const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
 
-    std::this_thread::sleep_for(appTimeout);
+    std::this_thread::sleep_for(timeout);
     // ANR should not be raised again. It is up to policy to do that if it desires.
     mFakePolicy->assertNotifyAnrWasNotCalled();
 
@@ -4694,8 +4842,8 @@
                       InputEventInjectionSync::WAIT_FOR_RESULT, 10ms);
     ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
 
-    const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
+    const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
 
     // Future focused events get dropped right away
     ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(mDispatcher));
@@ -4964,14 +5112,14 @@
 
         mApplication = std::make_shared<FakeApplicationHandle>();
         mApplication->setDispatchingTimeout(10ms);
-        mUnfocusedWindow =
-                new FakeWindowHandle(mApplication, mDispatcher, "Unfocused", ADISPLAY_ID_DEFAULT);
+        mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused",
+                                                      ADISPLAY_ID_DEFAULT);
         mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
         // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
         mUnfocusedWindow->setWatchOutsideTouch(true);
 
-        mFocusedWindow =
-                new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT);
+        mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused",
+                                                    ADISPLAY_ID_DEFAULT);
         mFocusedWindow->setDispatchingTimeout(30ms);
         mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
 
@@ -5338,16 +5486,17 @@
         InputDispatcherTest::SetUp();
 
         mApplication = std::make_shared<FakeApplicationHandle>();
-        mNoInputWindow = new FakeWindowHandle(mApplication, mDispatcher,
-                                              "Window without input channel", ADISPLAY_ID_DEFAULT,
-                                              std::make_optional<sp<IBinder>>(nullptr) /*token*/);
+        mNoInputWindow =
+                sp<FakeWindowHandle>::make(mApplication, mDispatcher,
+                                           "Window without input channel", ADISPLAY_ID_DEFAULT,
+                                           std::make_optional<sp<IBinder>>(nullptr) /*token*/);
 
         mNoInputWindow->setNoInputChannel(true);
         mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
         // It's perfectly valid for this window to not have an associated input channel
 
-        mBottomWindow = new FakeWindowHandle(mApplication, mDispatcher, "Bottom window",
-                                             ADISPLAY_ID_DEFAULT);
+        mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window",
+                                                   ADISPLAY_ID_DEFAULT);
         mBottomWindow->setFrame(Rect(0, 0, 100, 100));
 
         mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mNoInputWindow, mBottomWindow}}});
@@ -5380,9 +5529,9 @@
  */
 TEST_F(InputDispatcherMultiWindowOcclusionTests,
        NoInputChannelFeature_DropsTouchesWithValidChannel) {
-    mNoInputWindow = new FakeWindowHandle(mApplication, mDispatcher,
-                                          "Window with input channel and NO_INPUT_CHANNEL",
-                                          ADISPLAY_ID_DEFAULT);
+    mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
+                                                "Window with input channel and NO_INPUT_CHANNEL",
+                                                ADISPLAY_ID_DEFAULT);
 
     mNoInputWindow->setNoInputChannel(true);
     mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
@@ -5408,9 +5557,9 @@
     virtual void SetUp() override {
         InputDispatcherTest::SetUp();
         mApp = std::make_shared<FakeApplicationHandle>();
-        mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
-        mMirror = new FakeWindowHandle(mApp, mDispatcher, "TestWindowMirror", ADISPLAY_ID_DEFAULT,
-                                       mWindow->getToken());
+        mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+        mMirror = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindowMirror",
+                                             ADISPLAY_ID_DEFAULT, mWindow->getToken());
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
         mWindow->setFocusable(true);
         mMirror->setFocusable(true);
@@ -5552,9 +5701,10 @@
     void SetUp() override {
         InputDispatcherTest::SetUp();
         mApp = std::make_shared<FakeApplicationHandle>();
-        mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+        mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
         mWindow->setFocusable(true);
-        mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
+        mSecondWindow =
+                sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
         mSecondWindow->setFocusable(true);
 
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
@@ -5671,6 +5821,25 @@
     mWindow->consumeCaptureEvent(true);
 }
 
+TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) {
+    requestAndVerifyPointerCapture(mWindow, true);
+
+    // App toggles pointer capture off and on.
+    mDispatcher->requestPointerCapture(mWindow->getToken(), false);
+    mFakePolicy->assertSetPointerCaptureCalled(false);
+
+    mDispatcher->requestPointerCapture(mWindow->getToken(), true);
+    auto enableRequest = mFakePolicy->assertSetPointerCaptureCalled(true);
+
+    // InputReader notifies that the latest "enable" request was processed, while skipping over the
+    // preceding "disable" request.
+    notifyPointerCaptureChanged(enableRequest);
+
+    // Since pointer capture was never disabled during the rapid toggle, the window does not receive
+    // any notifications.
+    mWindow->assertNoEvents();
+}
+
 class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
 protected:
     constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
@@ -5696,7 +5865,6 @@
     virtual void SetUp() override {
         InputDispatcherTest::SetUp();
         mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
-        mDispatcher->setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode::BLOCK);
         mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
     }
 
@@ -5717,7 +5885,7 @@
     sp<FakeWindowHandle> getWindow(int32_t uid, std::string name) {
         std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
         sp<FakeWindowHandle> window =
-                new FakeWindowHandle(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
+                sp<FakeWindowHandle>::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
         // Generate an arbitrary PID based on the UID
         window->setOwnerInfo(1777 + (uid % 10000), uid);
         return window;
@@ -6077,71 +6245,101 @@
     sp<FakeWindowHandle> mWindow;
     sp<FakeWindowHandle> mSecondWindow;
     sp<FakeWindowHandle> mDragWindow;
+    sp<FakeWindowHandle> mSpyWindow;
+    // 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();
         mApp = std::make_shared<FakeApplicationHandle>();
-        mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+        mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
         mWindow->setFrame(Rect(0, 0, 100, 100));
 
-        mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
+        mSecondWindow =
+                sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
         mSecondWindow->setFrame(Rect(100, 0, 200, 100));
 
+        mSpyWindow =
+                sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT);
+        mSpyWindow->setSpy(true);
+        mSpyWindow->setTrustedOverlay(true);
+        mSpyWindow->setFrame(Rect(0, 0, 200, 100));
+
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
-        mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
+        mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mSpyWindow, mWindow, mSecondWindow}}});
     }
 
-    // Start performing drag, we will create a drag window and transfer touch to it.
-    void performDrag() {
-        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);
-
-        // 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();
+        // Spy window should also receive motion event
+        mSpyWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
     }
 
     // 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);
+    // @param sendDown : if true, send a motion down on first window before perform drag and drop.
+    // Returns true on success.
+    bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
+        if (sendDown) {
+            injectDown(fromSource);
+        }
 
         // The drag window covers the entire display
-        mDragWindow = new FakeWindowHandle(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
+        mDragWindow =
+                sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
+        mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
         mDispatcher->setInputWindows(
-                {{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}});
+                {{ADISPLAY_ID_DEFAULT, {mDragWindow, mSpyWindow, mWindow, mSecondWindow}}});
 
         // Transfer touch focus to the drag window
-        mDispatcher->transferTouchFocus(mWindow->getToken(), mDragWindow->getToken(),
-                                        true /* isDragDrop */);
-        mWindow->consumeMotionCancel();
-        mDragWindow->consumeMotionDown();
+        bool transferred =
+                mDispatcher->transferTouchFocus(mWindow->getToken(), mDragWindow->getToken(),
+                                                true /* isDragDrop */);
+        if (transferred) {
+            mWindow->consumeMotionCancel();
+            mDragWindow->consumeMotionDown();
+        }
+        return transferred;
     }
 };
 
 TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
-    performDrag();
+    startDrag();
 
     // Move on window.
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6178,8 +6376,32 @@
     mSecondWindow->assertNoEvents();
 }
 
+TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
+    startDrag();
+
+    // No cancel event after drag start
+    mSpyWindow->assertNoEvents();
+
+    const MotionEvent secondFingerDownEvent =
+            MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+                    .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(60).y(60))
+                    .build();
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+                                InputEventInjectionSync::WAIT_FOR_RESULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+    // Receives cancel for first pointer after next pointer down
+    mSpyWindow->consumeMotionCancel();
+    mSpyWindow->consumeMotionDown();
+
+    mSpyWindow->assertNoEvents();
+}
+
 TEST_F(InputDispatcherDragTests, DragAndDrop) {
-    performDrag();
+    startDrag();
 
     // Move on window.
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6211,7 +6433,7 @@
 }
 
 TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
-    performStylusDrag();
+    startDrag(true, AINPUT_SOURCE_STYLUS);
 
     // Move on window and keep button pressed.
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6257,8 +6479,8 @@
     mSecondWindow->assertNoEvents();
 }
 
-TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) {
-    performDrag();
+TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
+    startDrag();
 
     // Set second window invisible.
     mSecondWindow->setVisible(false);
@@ -6293,12 +6515,199 @@
     mSecondWindow->assertNoEvents();
 }
 
+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}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+    const MotionEvent secondFingerDownEvent =
+            MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+                    .displayId(ADISPLAY_ID_DEFAULT)
+                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+                    .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(75).y(50))
+                    .build();
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+                                InputEventInjectionSync::WAIT_FOR_RESULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    mWindow->consumeMotionPointerDown(1 /* pointerIndex */);
+
+    // Should not perform drag and drop when window has multi fingers.
+    ASSERT_FALSE(startDrag(false));
+}
+
+TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
+    // First down on second window.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {150, 50}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+    mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+    // Second down on first window.
+    const MotionEvent secondFingerDownEvent =
+            MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+                    .displayId(ADISPLAY_ID_DEFAULT)
+                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+                    .pointer(
+                            PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
+                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+                    .build();
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+                                InputEventInjectionSync::WAIT_FOR_RESULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+    // Perform drag and drop from first window.
+    ASSERT_TRUE(startDrag(false));
+
+    // Move on window.
+    const MotionEvent secondFingerMoveEvent =
+            MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
+                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+                    .pointer(
+                            PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
+                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+                    .build();
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
+                                InputEventInjectionSync::WAIT_FOR_RESULT));
+    mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+    mWindow->consumeDragEvent(false, 50, 50);
+    mSecondWindow->consumeMotionMove();
+
+    // Release the drag pointer should perform drop.
+    const MotionEvent secondFingerUpEvent =
+            MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
+                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+                    .pointer(
+                            PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
+                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+                    .build();
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
+                                InputEventInjectionSync::WAIT_FOR_RESULT));
+    mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+    mFakePolicy->assertDropTargetEquals(mWindow->getToken());
+    mWindow->assertNoEvents();
+    mSecondWindow->consumeMotionMove();
+}
+
+TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
+    startDrag();
+
+    // Update window of second display.
+    sp<FakeWindowHandle> windowInSecondary =
+            sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
+    mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}});
+
+    // Let second display has a touch state.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher,
+                                MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
+                                                   AINPUT_SOURCE_TOUCHSCREEN)
+                                        .displayId(SECOND_DISPLAY_ID)
+                                        .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+                                                         .x(100)
+                                                         .y(100))
+                                        .build()));
+    windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN,
+                                    SECOND_DISPLAY_ID, 0 /* expectedFlag */);
+    // Update window again.
+    mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}});
+
+    // Move on window.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+                                ADISPLAY_ID_DEFAULT, {50, 50}))
+            << "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, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+                                ADISPLAY_ID_DEFAULT, {150, 50}))
+            << "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,
+              injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                             {150, 50}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+    mFakePolicy->assertDropTargetEquals(mSecondWindow->getToken());
+    mWindow->assertNoEvents();
+    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) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Test window", ADISPLAY_ID_DEFAULT);
     window->setDropInput(true);
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
     window->setFocusable(true);
@@ -6336,14 +6745,14 @@
     std::shared_ptr<FakeApplicationHandle> obscuringApplication =
             std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> obscuringWindow =
-            new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow",
-                                 ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
+                                       ADISPLAY_ID_DEFAULT);
     obscuringWindow->setFrame(Rect(0, 0, 50, 50));
     obscuringWindow->setOwnerInfo(111, 111);
     obscuringWindow->setTouchable(false);
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Test window", ADISPLAY_ID_DEFAULT);
     window->setDropInputIfObscured(true);
     window->setOwnerInfo(222, 222);
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -6382,14 +6791,14 @@
     std::shared_ptr<FakeApplicationHandle> obscuringApplication =
             std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> obscuringWindow =
-            new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow",
-                                 ADISPLAY_ID_DEFAULT);
+            sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
+                                       ADISPLAY_ID_DEFAULT);
     obscuringWindow->setFrame(Rect(0, 0, 50, 50));
     obscuringWindow->setOwnerInfo(111, 111);
     obscuringWindow->setTouchable(false);
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                             "Test window", ADISPLAY_ID_DEFAULT);
     window->setDropInputIfObscured(true);
     window->setOwnerInfo(222, 222);
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -6433,10 +6842,11 @@
         InputDispatcherTest::SetUp();
 
         mApp = std::make_shared<FakeApplicationHandle>();
-        mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+        mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
         mWindow->setFocusable(true);
         setFocusedWindow(mWindow);
-        mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
+        mSecondWindow =
+                sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
         mSecondWindow->setFocusable(true);
 
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
@@ -6444,15 +6854,16 @@
         mWindow->consumeFocusEvent(true);
 
         // Set initial touch mode to InputDispatcher::kDefaultInTouchMode.
-        if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
-                                        INJECTOR_UID, /* hasPermission */ true)) {
+        if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
+                                        WINDOW_UID, true /*hasPermission*/, ADISPLAY_ID_DEFAULT)) {
             mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
             mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
         }
     }
 
     void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) {
-        ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission));
+        ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
+                                                ADISPLAY_ID_DEFAULT));
         mWindow->consumeTouchModeEvent(inTouchMode);
         mSecondWindow->consumeTouchModeEvent(inTouchMode);
     }
@@ -6461,7 +6872,7 @@
 TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
     const WindowInfo& windowInfo = *mWindow->getInfo();
     changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid,
-                             windowInfo.ownerUid, /* hasPermission */ false);
+                             windowInfo.ownerUid, false /*hasPermission*/);
 }
 
 TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
@@ -6470,7 +6881,8 @@
     int32_t ownerUid = windowInfo.ownerUid;
     mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1);
     ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
-                                             ownerUid, /* hasPermission */ false));
+                                             ownerUid, false /*hasPermission*/,
+                                             ADISPLAY_ID_DEFAULT));
     mWindow->assertNoEvents();
     mSecondWindow->assertNoEvents();
 }
@@ -6481,14 +6893,14 @@
     int32_t ownerUid = windowInfo.ownerUid;
     mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1);
     changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, ownerPid, ownerUid,
-                             /* hasPermission */ true);
+                             true /*hasPermission*/);
 }
 
 TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
     const WindowInfo& windowInfo = *mWindow->getInfo();
     ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode,
                                              windowInfo.ownerPid, windowInfo.ownerUid,
-                                             /* hasPermission */ true));
+                                             true /*hasPermission*/, ADISPLAY_ID_DEFAULT));
     mWindow->assertNoEvents();
     mSecondWindow->assertNoEvents();
 }
@@ -6507,7 +6919,7 @@
     const WindowInfo& windowInfo = *mWindow->getInfo();
     ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
                                             windowInfo.ownerPid, windowInfo.ownerUid,
-                                            /* hasPermission= */ false));
+                                            false /*hasPermission*/, ADISPLAY_ID_DEFAULT));
 }
 
 class InputDispatcherSpyWindowTest : public InputDispatcherTest {
@@ -6517,8 +6929,8 @@
                 std::make_shared<FakeApplicationHandle>();
         std::string name = "Fake Spy ";
         name += std::to_string(mSpyCount++);
-        sp<FakeWindowHandle> spy =
-                new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT);
+        sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher,
+                                                              name.c_str(), ADISPLAY_ID_DEFAULT);
         spy->setSpy(true);
         spy->setTrustedOverlay(true);
         return spy;
@@ -6528,7 +6940,8 @@
         std::shared_ptr<FakeApplicationHandle> application =
                 std::make_shared<FakeApplicationHandle>();
         sp<FakeWindowHandle> window =
-                new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+                sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
+                                           ADISPLAY_ID_DEFAULT);
         window->setFocusable(true);
         return window;
     }
@@ -6696,123 +7109,6 @@
 }
 
 /**
- * A spy window can pilfer pointers. When this happens, touch gestures that are currently sent to
- * any other windows - including other spy windows - will also be cancelled.
- */
-TEST_F(InputDispatcherSpyWindowTest, PilferPointers) {
-    auto window = createForeground();
-    auto spy1 = createSpy();
-    auto spy2 = createSpy();
-    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window}}});
-
-    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
-            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
-    window->consumeMotionDown();
-    spy1->consumeMotionDown();
-    spy2->consumeMotionDown();
-
-    // Pilfer pointers from the second spy window.
-    EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
-    spy2->assertNoEvents();
-    spy1->consumeMotionCancel();
-    window->consumeMotionCancel();
-
-    // The rest of the gesture should only be sent to the second spy window.
-    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-              injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
-                                ADISPLAY_ID_DEFAULT))
-            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
-    spy2->consumeMotionMove();
-    spy1->assertNoEvents();
-    window->assertNoEvents();
-}
-
-/**
- * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
- * in the middle of the gesture.
- */
-TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) {
-    auto window = createForeground();
-    auto spy = createSpy();
-    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
-
-    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
-            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
-    window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
-    spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
-
-    window->releaseChannel();
-
-    EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
-
-    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-              injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
-            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
-    spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
-}
-
-/**
- * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
- * the spy, but not to any other windows.
- */
-TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) {
-    auto spy = createSpy();
-    auto window = createForeground();
-
-    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
-
-    // First finger down on the window and the spy.
-    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
-                               {100, 200}))
-            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
-    spy->consumeMotionDown();
-    window->consumeMotionDown();
-
-    // Spy window pilfers the pointers.
-    EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
-    window->consumeMotionCancel();
-
-    // Second finger down on the window and spy, but the window should not receive the pointer down.
-    const MotionEvent secondFingerDownEvent =
-            MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
-                    .displayId(ADISPLAY_ID_DEFAULT)
-                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
-                    .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
-                                     .x(100)
-                                     .y(200))
-                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
-                    .build();
-    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-              injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
-                                InputEventInjectionSync::WAIT_FOR_RESULT))
-            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
-
-    spy->consumeMotionPointerDown(1 /*pointerIndex*/);
-
-    // Third finger goes down outside all windows, so injection should fail.
-    const MotionEvent thirdFingerDownEvent =
-            MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
-                    .displayId(ADISPLAY_ID_DEFAULT)
-                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
-                    .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
-                                     .x(100)
-                                     .y(200))
-                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
-                    .pointer(PointerBuilder(/* id */ 2, AMOTION_EVENT_TOOL_TYPE_FINGER).x(-5).y(-5))
-                    .build();
-    ASSERT_EQ(InputEventInjectionResult::FAILED,
-              injectMotionEvent(mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
-                                InputEventInjectionSync::WAIT_FOR_RESULT))
-            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
-
-    spy->assertNoEvents();
-    window->assertNoEvents();
-}
-
-/**
  * Even when a spy window spans over multiple foreground windows, the spy should receive all
  * pointers that are down within its bounds.
  */
@@ -6946,14 +7242,285 @@
     spy->assertNoEvents();
 }
 
+using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest;
+
+/**
+ * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that
+ * are currently sent to any other windows - including other spy windows - will also be cancelled.
+ */
+TEST_F(InputDispatcherPilferPointersTest, PilferPointers) {
+    auto window = createForeground();
+    auto spy1 = createSpy();
+    auto spy2 = createSpy();
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window}}});
+
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    window->consumeMotionDown();
+    spy1->consumeMotionDown();
+    spy2->consumeMotionDown();
+
+    // Pilfer pointers from the second spy window.
+    EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
+    spy2->assertNoEvents();
+    spy1->consumeMotionCancel();
+    window->consumeMotionCancel();
+
+    // The rest of the gesture should only be sent to the second spy window.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+                                ADISPLAY_ID_DEFAULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    spy2->consumeMotionMove();
+    spy1->assertNoEvents();
+    window->assertNoEvents();
+}
+
+/**
+ * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
+ * in the middle of the gesture.
+ */
+TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) {
+    auto window = createForeground();
+    auto spy = createSpy();
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+    spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+    window->releaseChannel();
+
+    EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
+
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+}
+
+/**
+ * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
+ * the spy, but not to any other windows.
+ */
+TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) {
+    auto spy = createSpy();
+    auto window = createForeground();
+
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+    // First finger down on the window and the spy.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {100, 200}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    spy->consumeMotionDown();
+    window->consumeMotionDown();
+
+    // Spy window pilfers the pointers.
+    EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
+    window->consumeMotionCancel();
+
+    // Second finger down on the window and spy, but the window should not receive the pointer down.
+    const MotionEvent secondFingerDownEvent =
+            MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+                    .displayId(ADISPLAY_ID_DEFAULT)
+                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+                    .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+                                     .x(100)
+                                     .y(200))
+                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+                    .build();
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+                                InputEventInjectionSync::WAIT_FOR_RESULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+    spy->consumeMotionPointerDown(1 /*pointerIndex*/);
+
+    // Third finger goes down outside all windows, so injection should fail.
+    const MotionEvent thirdFingerDownEvent =
+            MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+                    .displayId(ADISPLAY_ID_DEFAULT)
+                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+                    .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+                                     .x(100)
+                                     .y(200))
+                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+                    .pointer(PointerBuilder(/* id */ 2, AMOTION_EVENT_TOOL_TYPE_FINGER).x(-5).y(-5))
+                    .build();
+    ASSERT_EQ(InputEventInjectionResult::FAILED,
+              injectMotionEvent(mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
+                                InputEventInjectionSync::WAIT_FOR_RESULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+    spy->assertNoEvents();
+    window->assertNoEvents();
+}
+
+/**
+ * After a spy window pilfers pointers, only the pointers used by the spy should be canceled
+ */
+TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) {
+    auto spy = createSpy();
+    spy->setFrame(Rect(0, 0, 100, 100));
+    auto window = createForeground();
+    window->setFrame(Rect(0, 0, 200, 200));
+
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+    // First finger down on the window only
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {150, 150}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    window->consumeMotionDown();
+
+    // Second finger down on the spy and window
+    const MotionEvent secondFingerDownEvent =
+            MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+                    .displayId(ADISPLAY_ID_DEFAULT)
+                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+                    .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+                                     .x(150)
+                                     .y(150))
+                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10))
+                    .build();
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+                                InputEventInjectionSync::WAIT_FOR_RESULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    spy->consumeMotionDown();
+    window->consumeMotionPointerDown(1);
+
+    // Third finger down on the spy and window
+    const MotionEvent thirdFingerDownEvent =
+            MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+                    .displayId(ADISPLAY_ID_DEFAULT)
+                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+                    .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+                                     .x(150)
+                                     .y(150))
+                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10))
+                    .pointer(PointerBuilder(/* id */ 2, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+                    .build();
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
+                                InputEventInjectionSync::WAIT_FOR_RESULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    spy->consumeMotionPointerDown(1);
+    window->consumeMotionPointerDown(2);
+
+    // Spy window pilfers the pointers.
+    EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
+    window->consumeMotionPointerUp(/* idx */ 2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
+    window->consumeMotionPointerUp(/* idx */ 1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
+
+    spy->assertNoEvents();
+    window->assertNoEvents();
+}
+
+/**
+ * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to
+ * other windows should be canceled. If this results in the cancellation of all pointers for some
+ * window, then that window should receive ACTION_CANCEL.
+ */
+TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) {
+    auto spy = createSpy();
+    spy->setFrame(Rect(0, 0, 100, 100));
+    auto window = createForeground();
+    window->setFrame(Rect(0, 0, 200, 200));
+
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+    // First finger down on both spy and window
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {10, 10}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    window->consumeMotionDown();
+    spy->consumeMotionDown();
+
+    // Second finger down on the spy and window
+    const MotionEvent secondFingerDownEvent =
+            MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+                    .displayId(ADISPLAY_ID_DEFAULT)
+                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+                    .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10))
+                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+                    .build();
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+                                InputEventInjectionSync::WAIT_FOR_RESULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    spy->consumeMotionPointerDown(1);
+    window->consumeMotionPointerDown(1);
+
+    // Spy window pilfers the pointers.
+    EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
+    window->consumeMotionCancel();
+
+    spy->assertNoEvents();
+    window->assertNoEvents();
+}
+
+/**
+ * After a spy window pilfers pointers, new pointers that are not touching the spy window can still
+ * be sent to other windows
+ */
+TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) {
+    auto spy = createSpy();
+    spy->setFrame(Rect(0, 0, 100, 100));
+    auto window = createForeground();
+    window->setFrame(Rect(0, 0, 200, 200));
+
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+    // First finger down on both window and spy
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {10, 10}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    window->consumeMotionDown();
+    spy->consumeMotionDown();
+
+    // Spy window pilfers the pointers.
+    EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
+    window->consumeMotionCancel();
+
+    // Second finger down on the window only
+    const MotionEvent secondFingerDownEvent =
+            MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+                    .displayId(ADISPLAY_ID_DEFAULT)
+                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+                    .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10))
+                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER)
+                                     .x(150)
+                                     .y(150))
+                    .build();
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+                                InputEventInjectionSync::WAIT_FOR_RESULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    window->consumeMotionDown();
+    window->assertNoEvents();
+
+    // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line
+    spy->consumeMotionMove();
+    spy->assertNoEvents();
+}
+
 class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
 public:
     std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
         std::shared_ptr<FakeApplicationHandle> overlayApplication =
                 std::make_shared<FakeApplicationHandle>();
         sp<FakeWindowHandle> overlay =
-                new FakeWindowHandle(overlayApplication, mDispatcher, "Stylus interceptor window",
-                                     ADISPLAY_ID_DEFAULT);
+                sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
+                                           "Stylus interceptor window", ADISPLAY_ID_DEFAULT);
         overlay->setFocusable(false);
         overlay->setOwnerInfo(111, 111);
         overlay->setTouchable(false);
@@ -6963,8 +7530,8 @@
         std::shared_ptr<FakeApplicationHandle> application =
                 std::make_shared<FakeApplicationHandle>();
         sp<FakeWindowHandle> window =
-                new FakeWindowHandle(application, mDispatcher, "Application window",
-                                     ADISPLAY_ID_DEFAULT);
+                sp<FakeWindowHandle>::make(application, mDispatcher, "Application window",
+                                           ADISPLAY_ID_DEFAULT);
         window->setFocusable(true);
         window->setOwnerInfo(222, 222);
 
@@ -7076,4 +7643,150 @@
     window->assertNoEvents();
 }
 
+struct User {
+    int32_t mPid;
+    int32_t mUid;
+    uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
+    std::unique_ptr<InputDispatcher>& mDispatcher;
+
+    User(std::unique_ptr<InputDispatcher>& dispatcher, int32_t pid, int32_t uid)
+          : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
+
+    InputEventInjectionResult injectTargetedMotion(int32_t action) const {
+        return injectMotionEvent(mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
+                                 ADISPLAY_ID_DEFAULT, {100, 200},
+                                 {AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                  AMOTION_EVENT_INVALID_CURSOR_POSITION},
+                                 INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
+                                 systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
+    }
+
+    InputEventInjectionResult injectTargetedKey(int32_t action) const {
+        return inputdispatcher::injectKey(mDispatcher, action, 0 /* repeatCount*/, ADISPLAY_ID_NONE,
+                                          InputEventInjectionSync::WAIT_FOR_RESULT,
+                                          INJECT_EVENT_TIMEOUT, false /*allowKeyRepeat*/, {mUid},
+                                          mPolicyFlags);
+    }
+
+    sp<FakeWindowHandle> createWindow() const {
+        std::shared_ptr<FakeApplicationHandle> overlayApplication =
+                std::make_shared<FakeApplicationHandle>();
+        sp<FakeWindowHandle> window =
+                sp<FakeWindowHandle>::make(overlayApplication, mDispatcher, "Owned Window",
+                                           ADISPLAY_ID_DEFAULT);
+        window->setOwnerInfo(mPid, mUid);
+        return window;
+    }
+};
+
+using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
+    auto owner = User(mDispatcher, 10, 11);
+    auto window = owner.createWindow();
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+              owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+    window->consumeMotionDown();
+
+    setFocusedWindow(window);
+    window->consumeFocusEvent(true);
+
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+              owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
+    window->consumeKeyDown(ADISPLAY_ID_NONE);
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
+    auto owner = User(mDispatcher, 10, 11);
+    auto window = owner.createWindow();
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+    auto rando = User(mDispatcher, 20, 21);
+    EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
+              rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+
+    setFocusedWindow(window);
+    window->consumeFocusEvent(true);
+
+    EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
+              rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
+    window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
+    auto owner = User(mDispatcher, 10, 11);
+    auto window = owner.createWindow();
+    auto spy = owner.createWindow();
+    spy->setSpy(true);
+    spy->setTrustedOverlay(true);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+              owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+    spy->consumeMotionDown();
+    window->consumeMotionDown();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
+    auto owner = User(mDispatcher, 10, 11);
+    auto window = owner.createWindow();
+
+    auto rando = User(mDispatcher, 20, 21);
+    auto randosSpy = rando.createWindow();
+    randosSpy->setSpy(true);
+    randosSpy->setTrustedOverlay(true);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}});
+
+    // The event is targeted at owner's window, so injection should succeed, but the spy should
+    // not receive the event.
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+              owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+    randosSpy->assertNoEvents();
+    window->consumeMotionDown();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
+    auto owner = User(mDispatcher, 10, 11);
+    auto window = owner.createWindow();
+
+    auto rando = User(mDispatcher, 20, 21);
+    auto randosSpy = rando.createWindow();
+    randosSpy->setSpy(true);
+    randosSpy->setTrustedOverlay(true);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}});
+
+    // A user that has injection permission can inject into any window.
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                                ADISPLAY_ID_DEFAULT));
+    randosSpy->consumeMotionDown();
+    window->consumeMotionDown();
+
+    setFocusedWindow(randosSpy);
+    randosSpy->consumeFocusEvent(true);
+
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher));
+    randosSpy->consumeKeyDown(ADISPLAY_ID_NONE);
+    window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanGenerateActionOutsideToOtherUids) {
+    auto owner = User(mDispatcher, 10, 11);
+    auto window = owner.createWindow();
+
+    auto rando = User(mDispatcher, 20, 21);
+    auto randosWindow = rando.createWindow();
+    randosWindow->setFrame(Rect{-10, -10, -5, -5});
+    randosWindow->setWatchOutsideTouch(true);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosWindow, window}}});
+
+    // We allow generation of ACTION_OUTSIDE events into windows owned by different uids.
+    EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+              owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+    window->consumeMotionDown();
+    randosWindow->consumeMotionOutside();
+}
+
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
index 454e531..22ae894 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -223,8 +223,10 @@
 
     if (forkPid == 0) {
         // Server process
-        android::sp<android::TestInputManager> manager = new android::TestInputManager();
-        android::sp<android::TestInputQuery> query = new android::TestInputQuery(manager);
+        android::sp<android::TestInputManager> manager =
+                android::sp<android::TestInputManager>::make();
+        android::sp<android::TestInputQuery> query =
+                android::sp<android::TestInputQuery>::make(manager);
 
         android::defaultServiceManager()->addService(android::kTestServiceName, manager,
                                                      false /*allowIsolated*/);
diff --git a/services/inputflinger/tests/InputClassifierConverter_test.cpp b/services/inputflinger/tests/InputProcessorConverter_test.cpp
similarity index 93%
rename from services/inputflinger/tests/InputClassifierConverter_test.cpp
rename to services/inputflinger/tests/InputProcessorConverter_test.cpp
index 81ef9b9..040c8da 100644
--- a/services/inputflinger/tests/InputClassifierConverter_test.cpp
+++ b/services/inputflinger/tests/InputProcessorConverter_test.cpp
@@ -24,7 +24,7 @@
 
 namespace android {
 
-// --- InputClassifierConverterTest ---
+// --- InputProcessorConverterTest ---
 
 static NotifyMotionArgs generateBasicMotionArgs() {
     // Create a basic motion event for testing
@@ -52,7 +52,7 @@
 
 static float getMotionEventAxis(common::PointerCoords coords, common::Axis axis) {
     uint32_t index = BitSet64::getIndexOfBit(static_cast<uint64_t>(coords.bits),
-            static_cast<uint64_t>(axis));
+                                             static_cast<uint64_t>(axis));
     return coords.values[index];
 }
 
@@ -60,7 +60,7 @@
  * Check that coordinates get converted properly from the framework's PointerCoords
  * to the hidl PointerCoords in input::common.
  */
-TEST(InputClassifierConverterTest, PointerCoordsAxes) {
+TEST(InputProcessorConverterTest, PointerCoordsAxes) {
     const NotifyMotionArgs motionArgs = generateBasicMotionArgs();
     ASSERT_EQ(1, motionArgs.pointerCoords[0].getX());
     ASSERT_EQ(2, motionArgs.pointerCoords[0].getY());
@@ -76,7 +76,7 @@
     ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::Axis::SIZE),
               motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SIZE));
     ASSERT_EQ(BitSet64::count(motionArgs.pointerCoords[0].bits),
-            BitSet64::count(motionEvent.pointerCoords[0].bits));
+              BitSet64::count(motionEvent.pointerCoords[0].bits));
 }
 
 } // namespace android
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputProcessor_test.cpp
similarity index 75%
rename from services/inputflinger/tests/InputClassifier_test.cpp
rename to services/inputflinger/tests/InputProcessor_test.cpp
index 3a77127..380001c 100644
--- a/services/inputflinger/tests/InputClassifier_test.cpp
+++ b/services/inputflinger/tests/InputProcessor_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "../InputClassifier.h"
+#include "../InputProcessor.h"
 #include <gtest/gtest.h>
 #include <gui/constants.h>
 
@@ -31,7 +31,7 @@
 
 namespace android {
 
-// --- InputClassifierTest ---
+// --- InputProcessorTest ---
 
 static NotifyMotionArgs generateBasicMotionArgs() {
     // Create a basic motion event for testing
@@ -56,105 +56,104 @@
     return motionArgs;
 }
 
-class InputClassifierTest : public testing::Test {
+class InputProcessorTest : public testing::Test {
 protected:
     TestInputListener mTestListener;
-    std::unique_ptr<InputClassifierInterface> mClassifier;
+    std::unique_ptr<InputProcessorInterface> mProcessor;
 
-    void SetUp() override { mClassifier = std::make_unique<InputClassifier>(mTestListener); }
+    void SetUp() override { mProcessor = std::make_unique<InputProcessor>(mTestListener); }
 };
 
 /**
- * Create a basic configuration change and send it to input classifier.
+ * Create a basic configuration change and send it to input processor.
  * Expect that the event is received by the next input stage, unmodified.
  */
-TEST_F(InputClassifierTest, SendToNextStage_NotifyConfigurationChangedArgs) {
-    // Create a basic configuration change and send to classifier
-    NotifyConfigurationChangedArgs args(1/*sequenceNum*/, 2/*eventTime*/);
+TEST_F(InputProcessorTest, SendToNextStage_NotifyConfigurationChangedArgs) {
+    // Create a basic configuration change and send to processor
+    NotifyConfigurationChangedArgs args(1 /*sequenceNum*/, 2 /*eventTime*/);
 
-    mClassifier->notifyConfigurationChanged(&args);
+    mProcessor->notifyConfigurationChanged(&args);
     NotifyConfigurationChangedArgs outArgs;
     ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyConfigurationChangedWasCalled(&outArgs));
     ASSERT_EQ(args, outArgs);
 }
 
-TEST_F(InputClassifierTest, SendToNextStage_NotifyKeyArgs) {
-    // Create a basic key event and send to classifier
+TEST_F(InputProcessorTest, SendToNextStage_NotifyKeyArgs) {
+    // Create a basic key event and send to processor
     NotifyKeyArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 21 /*readTime*/, 3 /*deviceId*/,
                        AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_DEFAULT, 0 /*policyFlags*/,
                        AKEY_EVENT_ACTION_DOWN, 4 /*flags*/, AKEYCODE_HOME, 5 /*scanCode*/,
                        AMETA_NONE, 6 /*downTime*/);
 
-    mClassifier->notifyKey(&args);
+    mProcessor->notifyKey(&args);
     NotifyKeyArgs outArgs;
     ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyKeyWasCalled(&outArgs));
     ASSERT_EQ(args, outArgs);
 }
 
-
 /**
- * Create a basic motion event and send it to input classifier.
+ * Create a basic motion event and send it to input processor.
  * Expect that the event is received by the next input stage, unmodified.
  */
-TEST_F(InputClassifierTest, SendToNextStage_NotifyMotionArgs) {
+TEST_F(InputProcessorTest, SendToNextStage_NotifyMotionArgs) {
     NotifyMotionArgs motionArgs = generateBasicMotionArgs();
-    mClassifier->notifyMotion(&motionArgs);
+    mProcessor->notifyMotion(&motionArgs);
     NotifyMotionArgs args;
     ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyMotionWasCalled(&args));
     ASSERT_EQ(motionArgs, args);
 }
 
 /**
- * Create a basic switch event and send it to input classifier.
+ * Create a basic switch event and send it to input processor.
  * Expect that the event is received by the next input stage, unmodified.
  */
-TEST_F(InputClassifierTest, SendToNextStage_NotifySwitchArgs) {
-    NotifySwitchArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*policyFlags*/, 4/*switchValues*/,
-            5/*switchMask*/);
+TEST_F(InputProcessorTest, SendToNextStage_NotifySwitchArgs) {
+    NotifySwitchArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 3 /*policyFlags*/, 4 /*switchValues*/,
+                          5 /*switchMask*/);
 
-    mClassifier->notifySwitch(&args);
+    mProcessor->notifySwitch(&args);
     NotifySwitchArgs outArgs;
     ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifySwitchWasCalled(&outArgs));
     ASSERT_EQ(args, outArgs);
 }
 
 /**
- * Create a basic device reset event and send it to input classifier.
+ * Create a basic device reset event and send it to input processor.
  * Expect that the event is received by the next input stage, unmodified.
  */
-TEST_F(InputClassifierTest, SendToNextStage_NotifyDeviceResetArgs) {
-    NotifyDeviceResetArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*deviceId*/);
+TEST_F(InputProcessorTest, SendToNextStage_NotifyDeviceResetArgs) {
+    NotifyDeviceResetArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 3 /*deviceId*/);
 
-    mClassifier->notifyDeviceReset(&args);
+    mProcessor->notifyDeviceReset(&args);
     NotifyDeviceResetArgs outArgs;
     ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyDeviceResetWasCalled(&outArgs));
     ASSERT_EQ(args, outArgs);
 }
 
-TEST_F(InputClassifierTest, SetMotionClassifier_Enabled) {
-    mClassifier->setMotionClassifierEnabled(true);
+TEST_F(InputProcessorTest, SetMotionClassifier_Enabled) {
+    mProcessor->setMotionClassifierEnabled(true);
 }
 
-TEST_F(InputClassifierTest, SetMotionClassifier_Disabled) {
-    mClassifier->setMotionClassifierEnabled(false);
+TEST_F(InputProcessorTest, SetMotionClassifier_Disabled) {
+    mProcessor->setMotionClassifierEnabled(false);
 }
 
 /**
  * Try to break it by calling setMotionClassifierEnabled multiple times.
  */
-TEST_F(InputClassifierTest, SetMotionClassifier_Multiple) {
-    mClassifier->setMotionClassifierEnabled(true);
-    mClassifier->setMotionClassifierEnabled(true);
-    mClassifier->setMotionClassifierEnabled(true);
-    mClassifier->setMotionClassifierEnabled(false);
-    mClassifier->setMotionClassifierEnabled(false);
-    mClassifier->setMotionClassifierEnabled(true);
-    mClassifier->setMotionClassifierEnabled(true);
-    mClassifier->setMotionClassifierEnabled(true);
+TEST_F(InputProcessorTest, SetMotionClassifier_Multiple) {
+    mProcessor->setMotionClassifierEnabled(true);
+    mProcessor->setMotionClassifierEnabled(true);
+    mProcessor->setMotionClassifierEnabled(true);
+    mProcessor->setMotionClassifierEnabled(false);
+    mProcessor->setMotionClassifierEnabled(false);
+    mProcessor->setMotionClassifierEnabled(true);
+    mProcessor->setMotionClassifierEnabled(true);
+    mProcessor->setMotionClassifierEnabled(true);
 }
 
 /**
- * A minimal implementation of IInputClassifier.
+ * A minimal implementation of IInputProcessor.
  */
 class TestHal : public aidl::android::hardware::input::processor::BnInputProcessor {
     ::ndk::ScopedAStatus classify(
@@ -212,7 +211,7 @@
     NotifyMotionArgs motionArgs = generateBasicMotionArgs();
 
     std::vector<int16_t> videoData = {1, 2, 3, 4};
-    timeval timestamp = { 1, 1};
+    timeval timestamp = {1, 1};
     TouchVideoFrame frame(2, 2, std::move(videoData), timestamp);
     motionArgs.videoFrames = {frame};
 
@@ -228,11 +227,11 @@
     NotifyMotionArgs motionArgs = generateBasicMotionArgs();
 
     std::vector<int16_t> videoData1 = {1, 2, 3, 4};
-    timeval timestamp1 = { 1, 1};
+    timeval timestamp1 = {1, 1};
     TouchVideoFrame frame1(2, 2, std::move(videoData1), timestamp1);
 
     std::vector<int16_t> videoData2 = {6, 6, 6, 6};
-    timeval timestamp2 = { 1, 2};
+    timeval timestamp2 = {1, 2};
     TouchVideoFrame frame2(2, 2, std::move(videoData2), timestamp2);
 
     motionArgs.videoFrames = {frame1, frame2};
@@ -253,7 +252,7 @@
  * Make sure MotionClassifier does not crash when a device is reset.
  */
 TEST_F(MotionClassifierTest, DeviceReset_DoesNotCrash) {
-    NotifyDeviceResetArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*deviceId*/);
+    NotifyDeviceResetArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 3 /*deviceId*/);
     ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset(args));
 }
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index bda7755..a0e6192 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -219,7 +219,7 @@
         mSpotsByDisplay[displayId] = newSpots;
     }
 
-    void clearSpots() override {}
+    void clearSpots() override { mSpotsByDisplay.clear(); }
 
     std::map<int32_t, std::vector<int32_t>> mSpotsByDisplay;
 };
@@ -373,8 +373,17 @@
         mConfig.defaultPointerDisplayId = pointerDisplayId;
     }
 
+    void setPointerGestureEnabled(bool enabled) { mConfig.pointerGesturesEnabled = enabled; }
+
     float getPointerGestureMovementSpeedRatio() { return mConfig.pointerGestureMovementSpeedRatio; }
 
+    float getPointerGestureZoomSpeedRatio() { return mConfig.pointerGestureZoomSpeedRatio; }
+
+    void setVelocityControlParams(const VelocityControlParameters& params) {
+        mConfig.pointerVelocityControlParameters = params;
+        mConfig.wheelVelocityControlParameters = params;
+    }
+
 private:
     uint32_t mNextPointerCaptureSequenceNumber = 0;
 
@@ -541,7 +550,7 @@
         enqueueEvent(ARBITRARY_TIME, READ_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0);
     }
 
-    void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) {
+    void addConfigurationProperty(int32_t deviceId, const char* key, const char* value) {
         Device* device = getDevice(deviceId);
         device->configuration.addProperty(key, value);
     }
@@ -882,13 +891,13 @@
     }
 
     // Return true if the device has non-empty key layout.
-    bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
+    bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes,
                                uint8_t* outFlags) const override {
         bool result = false;
         Device* device = getDevice(deviceId);
         if (device) {
             result = device->keysByScanCode.size() > 0 || device->keysByUsageCode.size() > 0;
-            for (size_t i = 0; i < numCodes; i++) {
+            for (size_t i = 0; i < keyCodes.size(); i++) {
                 for (size_t j = 0; j < device->keysByScanCode.size(); j++) {
                     if (keyCodes[i] == device->keysByScanCode.valueAt(j).keyCode) {
                         outFlags[i] = 1;
@@ -1204,9 +1213,9 @@
     }
 
     // Return true if the device has non-empty key layout.
-    bool markSupportedKeyCodes(uint32_t, size_t numCodes, const int32_t* keyCodes,
+    bool markSupportedKeyCodes(uint32_t, const std::vector<int32_t>& keyCodes,
                                uint8_t* outFlags) override {
-        for (size_t i = 0; i < numCodes; i++) {
+        for (size_t i = 0; i < keyCodes.size(); i++) {
             for (size_t j = 0; j < mSupportedKeyCodes.size(); j++) {
                 if (keyCodes[i] == mSupportedKeyCodes[j]) {
                     outFlags[i] = 1;
@@ -1323,7 +1332,7 @@
 protected:
     sp<FakeInputReaderPolicy> mFakePolicy;
 
-    void SetUp() override { mFakePolicy = new FakeInputReaderPolicy(); }
+    void SetUp() override { mFakePolicy = sp<FakeInputReaderPolicy>::make(); }
     void TearDown() override { mFakePolicy.clear(); }
 };
 
@@ -1561,7 +1570,7 @@
 
     void SetUp() override {
         mFakeEventHub = std::make_unique<FakeEventHub>();
-        mFakePolicy = new FakeInputReaderPolicy();
+        mFakePolicy = sp<FakeInputReaderPolicy>::make();
         mFakeListener = std::make_unique<TestInputListener>();
 
         mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
@@ -1850,34 +1859,37 @@
     mapper.addSupportedKeyCode(AKEYCODE_A);
     mapper.addSupportedKeyCode(AKEYCODE_B);
 
-    const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 };
+    const std::vector<int32_t> keyCodes{AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2};
     uint8_t flags[4] = { 0, 0, 0, 1 };
 
-    ASSERT_FALSE(mReader->hasKeys(0, AINPUT_SOURCE_ANY, 4, keyCodes, flags))
+    ASSERT_FALSE(mReader->hasKeys(0, AINPUT_SOURCE_ANY, keyCodes, flags))
             << "Should return false when device id is >= 0 but unknown.";
     ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]);
 
     flags[3] = 1;
-    ASSERT_FALSE(mReader->hasKeys(deviceId, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags))
+    ASSERT_FALSE(mReader->hasKeys(deviceId, AINPUT_SOURCE_TRACKBALL, keyCodes, flags))
             << "Should return false when device id is valid but the sources are not supported by "
                "the device.";
     ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]);
 
     flags[3] = 1;
-    ASSERT_TRUE(mReader->hasKeys(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4,
+    ASSERT_TRUE(mReader->hasKeys(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL,
                                  keyCodes, flags))
             << "Should return value provided by mapper when device id is valid and the device "
                "supports some of the sources.";
     ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]);
 
     flags[3] = 1;
-    ASSERT_FALSE(mReader->hasKeys(-1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags))
-            << "Should return false when the device id is < 0 but the sources are not supported by any device.";
+    ASSERT_FALSE(mReader->hasKeys(-1, AINPUT_SOURCE_TRACKBALL, keyCodes, flags))
+            << "Should return false when the device id is < 0 but the sources are not supported by "
+               "any device.";
     ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]);
 
     flags[3] = 1;
-    ASSERT_TRUE(mReader->hasKeys(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags))
-            << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources.";
+    ASSERT_TRUE(
+            mReader->hasKeys(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, keyCodes, flags))
+            << "Should return value provided by mapper when device id is < 0 and one of the "
+               "devices supports some of the sources.";
     ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]);
 }
 
@@ -2242,7 +2254,7 @@
     std::shared_ptr<FakePointerController> mFakePointerController;
 
     void SetUp() override {
-        mFakePolicy = new FakeInputReaderPolicy();
+        mFakePolicy = sp<FakeInputReaderPolicy>::make();
         mFakePointerController = std::make_shared<FakePointerController>();
         mFakePolicy->setPointerController(mFakePointerController);
         mTestListener = std::make_unique<TestInputListener>(2000ms /*eventHappenedTimeout*/,
@@ -2641,7 +2653,7 @@
 
     void SetUp() override {
         mFakeEventHub = std::make_unique<FakeEventHub>();
-        mFakePolicy = new FakeInputReaderPolicy();
+        mFakePolicy = sp<FakeInputReaderPolicy>::make();
         mFakeListener = std::make_unique<TestInputListener>();
         mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
                                                             *mFakeListener);
@@ -2713,9 +2725,9 @@
     ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 0))
             << "Ignored device should return unknown switch state.";
 
-    const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B };
+    const std::vector<int32_t> keyCodes{AKEYCODE_A, AKEYCODE_B};
     uint8_t flags[2] = { 0, 1 };
-    ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 2, keyCodes, flags))
+    ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, keyCodes, flags))
             << "Ignored device should never mark any key codes.";
     ASSERT_EQ(0, flags[0]) << "Flag for unsupported key should be unchanged.";
     ASSERT_EQ(1, flags[1]) << "Flag for unsupported key should be unchanged.";
@@ -2723,7 +2735,7 @@
 
 TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) {
     // Configuration.
-    mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, String8("key"), String8("value"));
+    mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "key", "value");
 
     FakeInputMapper& mapper1 =
             mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD);
@@ -2744,10 +2756,10 @@
     InputReaderConfiguration config;
     mDevice->configure(ARBITRARY_TIME, &config, 0);
 
-    String8 propertyValue;
-    ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue))
+    std::string propertyValue;
+    ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty("key", propertyValue))
             << "Device should have read configuration during configuration phase.";
-    ASSERT_STREQ("value", propertyValue.string());
+    ASSERT_EQ("value", propertyValue);
 
     ASSERT_NO_FATAL_FAILURE(mapper1.assertConfigureWasCalled());
     ASSERT_NO_FATAL_FAILURE(mapper2.assertConfigureWasCalled());
@@ -2790,16 +2802,16 @@
     ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 4))
             << "Should query mapper when source is supported.";
 
-    const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 };
+    const std::vector<int32_t> keyCodes{AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2};
     uint8_t flags[4] = { 0, 0, 0, 1 };
-    ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags))
+    ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_TRACKBALL, keyCodes, flags))
             << "Should do nothing when source is unsupported.";
     ASSERT_EQ(0, flags[0]) << "Flag should be unchanged when source is unsupported.";
     ASSERT_EQ(0, flags[1]) << "Flag should be unchanged when source is unsupported.";
     ASSERT_EQ(0, flags[2]) << "Flag should be unchanged when source is unsupported.";
     ASSERT_EQ(1, flags[3]) << "Flag should be unchanged when source is unsupported.";
 
-    ASSERT_TRUE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 4, keyCodes, flags))
+    ASSERT_TRUE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, keyCodes, flags))
             << "Should query mapper when source is supported.";
     ASSERT_EQ(1, flags[0]) << "Flag for supported key should be set.";
     ASSERT_EQ(1, flags[1]) << "Flag for supported key should be set.";
@@ -2928,11 +2940,13 @@
 
     virtual void SetUp(ftl::Flags<InputDeviceClass> classes) {
         mFakeEventHub = std::make_unique<FakeEventHub>();
-        mFakePolicy = new FakeInputReaderPolicy();
+        mFakePolicy = sp<FakeInputReaderPolicy>::make();
         mFakeListener = std::make_unique<TestInputListener>();
         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 {
@@ -2945,15 +2959,20 @@
     }
 
     void addConfigurationProperty(const char* key, const char* value) {
-        mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, String8(key), String8(value));
+        mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, key, value);
     }
 
     void configureDevice(uint32_t changes) {
-        if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+        if (!changes ||
+            (changes &
+             (InputReaderConfiguration::CHANGE_DISPLAY_INFO |
+              InputReaderConfiguration::CHANGE_POINTER_CAPTURE))) {
             mReader->requestRefreshConfiguration(changes);
             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,
@@ -2977,6 +2996,8 @@
         configureDevice(0);
         mDevice->reset(ARBITRARY_TIME);
         mapper.reset(ARBITRARY_TIME);
+        // Loop the reader to flush the input listener queue.
+        mReader->loopOnce();
         return mapper;
     }
 
@@ -3002,6 +3023,7 @@
         event.code = code;
         event.value = value;
         mapper.process(&event);
+        // Loop the reader to flush the input listener queue.
         mReader->loopOnce();
     }
 
@@ -3364,9 +3386,8 @@
     KeyboardInputMapper& mapper =
             addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
                                                        AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    // Initial metastate to AMETA_NONE.
-    ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
-    mapper.updateMetaState(AKEYCODE_NUM_LOCK);
+    // Initial metastate is AMETA_NONE.
+    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
 
     // Key down by scan code.
     process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
@@ -3491,9 +3512,8 @@
             addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
                                                        AINPUT_KEYBOARD_TYPE_ALPHABETIC);
 
-    // Initial metastate to AMETA_NONE.
-    ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
-    mapper.updateMetaState(AKEYCODE_NUM_LOCK);
+    // Initial metastate is AMETA_NONE.
+    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
 
     // Metakey down.
     process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_LEFTSHIFT, 1);
@@ -3720,9 +3740,8 @@
 
     mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
 
-    const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B };
     uint8_t flags[2] = { 0, 0 };
-    ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, 1, keyCodes, flags));
+    ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, {AKEYCODE_A, AKEYCODE_B}, flags));
     ASSERT_TRUE(flags[0]);
     ASSERT_FALSE(flags[1]);
 }
@@ -3738,9 +3757,8 @@
     KeyboardInputMapper& mapper =
             addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
                                                        AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    // Initialize metastate to AMETA_NUM_LOCK_ON.
-    ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
-    mapper.updateMetaState(AKEYCODE_NUM_LOCK);
+    // Initial metastate is AMETA_NONE.
+    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
 
     // Initialization should have turned all of the lights off.
     ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
@@ -3806,8 +3824,6 @@
             addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
                                                        AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC);
 
-    // Initial metastate should be AMETA_NONE as no meta keys added.
-    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
     // Meta state should be AMETA_NONE after reset
     mapper.reset(ARBITRARY_TIME);
     ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
@@ -3922,9 +3938,8 @@
     KeyboardInputMapper& mapper =
             addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
                                                        AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    // Initial metastate to AMETA_NONE.
-    ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
-    mapper.updateMetaState(AKEYCODE_NUM_LOCK);
+    // Initial metastate is AMETA_NONE.
+    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
 
     // Initialization should have turned all of the lights off.
     ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
@@ -3991,9 +4006,8 @@
     KeyboardInputMapper& mapper =
             addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
                                                        AINPUT_KEYBOARD_TYPE_ALPHABETIC);
-    // Initialize metastate to AMETA_NUM_LOCK_ON.
-    ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
-    mapper.updateMetaState(AKEYCODE_NUM_LOCK);
+    // Initial metastate is AMETA_NONE.
+    ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
 
     mReader->toggleCapsLockState(DEVICE_ID);
     ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
@@ -4033,7 +4047,13 @@
     device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
     device2->reset(ARBITRARY_TIME);
 
-    // Initial metastate is AMETA_NUM_LOCK_ON, turn it off.
+    // Initial metastate is AMETA_NONE.
+    ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+    ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+
+    // Toggle num lock on and off.
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
+    process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
     ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
     ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper1.getMetaState());
     ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper2.getMetaState());
@@ -4900,7 +4920,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);
@@ -4914,6 +4933,96 @@
     ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
 }
 
+/**
+ * When Pointer Capture is enabled, we expect to report unprocessed relative movements, so any
+ * pointer acceleration or speed processing should not be applied.
+ */
+TEST_F(CursorInputMapperTest, PointerCaptureDisablesVelocityProcessing) {
+    addConfigurationProperty("cursor.mode", "pointer");
+    const VelocityControlParameters testParams(5.f /*scale*/, 0.f /*low threshold*/,
+                                               100.f /*high threshold*/, 10.f /*acceleration*/);
+    mFakePolicy->setVelocityControlParams(testParams);
+    CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+    NotifyDeviceResetArgs resetArgs;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+    ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+    ASSERT_EQ(DEVICE_ID, resetArgs.deviceId);
+
+    NotifyMotionArgs args;
+
+    // Move and verify scale is 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, args.source);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
+    const float relX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
+    const float relY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
+    ASSERT_GT(relX, 10);
+    ASSERT_GT(relY, 20);
+
+    // 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 scale 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, PointerCaptureDisablesOrientationChanges) {
+    addConfigurationProperty("cursor.mode", "pointer");
+    CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+    NotifyDeviceResetArgs resetArgs;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+    ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+    ASSERT_EQ(DEVICE_ID, resetArgs.deviceId);
+
+    // 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_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, Process_ShouldHandleDisplayId) {
     CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
 
@@ -5308,9 +5417,9 @@
     prepareVirtualKeys();
     SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
 
-    const int32_t keys[2] = { AKEYCODE_HOME, AKEYCODE_A };
     uint8_t flags[2] = { 0, 0 };
-    ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, 2, keys, flags));
+    ASSERT_TRUE(
+            mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, {AKEYCODE_HOME, AKEYCODE_A}, flags));
     ASSERT_TRUE(flags[0]);
     ASSERT_FALSE(flags[1]);
 }
@@ -6593,6 +6702,89 @@
             toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
 }
 
+TEST_F(SingleTouchInputMapperTest,
+       Process_WhenViewportDisplayIdChanged_TouchIsCanceledAndDeviceIsReset) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareButtons();
+    prepareAxes(POSITION);
+    SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+    NotifyMotionArgs motionArgs;
+
+    // Down.
+    processDown(mapper, 100, 200);
+    processSync(mapper);
+
+    // We should receive a down event
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+
+    // Change display id
+    clearViewports();
+    prepareSecondaryDisplay(ViewportType::INTERNAL);
+
+    // We should receive a cancel event
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+    // Then receive reset called
+    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 {
@@ -8450,27 +8642,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) {
@@ -8523,7 +8715,8 @@
 
     // Default device will reconfigure above, need additional reconfiguration for another device.
     device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                       InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+                       InputReaderConfiguration::CHANGE_DISPLAY_INFO |
+                               InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
 
     // Two fingers down at default display.
     int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500;
@@ -8550,6 +8743,13 @@
     iter = fakePointerController->getSpots().find(SECONDARY_DISPLAY_ID);
     ASSERT_TRUE(iter != fakePointerController->getSpots().end());
     ASSERT_EQ(size_t(2), iter->second.size());
+
+    // Disable the show touches configuration and ensure the spots are cleared.
+    mFakePolicy->setShowTouches(false);
+    device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                       InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
+
+    ASSERT_TRUE(fakePointerController->getSpots().empty());
 }
 
 TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) {
@@ -8628,6 +8828,10 @@
         // window's coordinate space.
         frames[0].rotate(getInverseRotation(orientation));
         ASSERT_EQ(frames, motionArgs.videoFrames);
+
+        // Release finger.
+        processSync(mapper);
+        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
     }
 }
 
@@ -9357,6 +9561,258 @@
     ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
 }
 
+class MultiTouchPointerModeTest : public MultiTouchInputMapperTest {
+protected:
+    float mPointerMovementScale;
+    float mPointerXZoomScale;
+    void preparePointerMode(int xAxisResolution, int yAxisResolution) {
+        addConfigurationProperty("touch.deviceType", "pointer");
+        std::shared_ptr<FakePointerController> fakePointerController =
+                std::make_shared<FakePointerController>();
+        fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
+        fakePointerController->setPosition(0, 0);
+        fakePointerController->setButtonState(0);
+        prepareDisplay(DISPLAY_ORIENTATION_0);
+
+        prepareAxes(POSITION);
+        prepareAbsoluteAxisResolution(xAxisResolution, yAxisResolution);
+        // In order to enable swipe and freeform gesture in pointer mode, pointer capture
+        // needs to be disabled, and the pointer gesture needs to be enabled.
+        mFakePolicy->setPointerCapture(false);
+        mFakePolicy->setPointerGestureEnabled(true);
+        mFakePolicy->setPointerController(fakePointerController);
+
+        float rawDiagonal = hypotf(RAW_X_MAX - RAW_X_MIN, RAW_Y_MAX - RAW_Y_MIN);
+        float displayDiagonal = hypotf(DISPLAY_WIDTH, DISPLAY_HEIGHT);
+        mPointerMovementScale =
+                mFakePolicy->getPointerGestureMovementSpeedRatio() * displayDiagonal / rawDiagonal;
+        mPointerXZoomScale =
+                mFakePolicy->getPointerGestureZoomSpeedRatio() * displayDiagonal / rawDiagonal;
+    }
+
+    void prepareAbsoluteAxisResolution(int xAxisResolution, int yAxisResolution) {
+        mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX,
+                                       /*flat*/ 0,
+                                       /*fuzz*/ 0, /*resolution*/ xAxisResolution);
+        mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX,
+                                       /*flat*/ 0,
+                                       /*fuzz*/ 0, /*resolution*/ yAxisResolution);
+    }
+};
+
+/**
+ * Two fingers down on a pointer mode touch pad. The width
+ * of the two finger is larger than 1/4 of the touch pack diagnal length. However, it
+ * is smaller than the fixed min physical length 30mm. Two fingers' distance must
+ * be greater than the both value to be freeform gesture, so that after two
+ * fingers start to move downwards, the gesture should be swipe.
+ */
+TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthSwipe) {
+    // The min freeform gesture width is 25units/mm x 30mm = 750
+    // which is greater than fraction of the diagnal length of the touchpad (349).
+    // Thus, MaxSwipWidth is 750.
+    preparePointerMode(25 /*xResolution*/, 25 /*yResolution*/);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+    NotifyMotionArgs motionArgs;
+
+    // Two fingers down at once.
+    // The two fingers are 450 units apart, expects the current gesture to be PRESS
+    // Pointer's initial position is used the [0,0] coordinate.
+    int32_t x1 = 100, y1 = 125, x2 = 550, y2 = 125;
+
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1, y1);
+    processMTSync(mapper);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2, y2);
+    processMTSync(mapper);
+    processSync(mapper);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(1U, motionArgs.pointerCount);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    ASSERT_NO_FATAL_FAILURE(
+            assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0));
+
+    // It should be recognized as a SWIPE gesture when two fingers start to move down,
+    // that there should be 1 pointer.
+    int32_t movingDistance = 200;
+    y1 += movingDistance;
+    y2 += movingDistance;
+
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1, y1);
+    processMTSync(mapper);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2, y2);
+    processMTSync(mapper);
+    processSync(mapper);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(1U, motionArgs.pointerCount);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 0,
+                                                movingDistance * mPointerMovementScale, 1, 0, 0, 0,
+                                                0, 0, 0, 0));
+}
+
+/**
+ * Two fingers down on a pointer mode touch pad. The width of the two finger is larger
+ * than the minimum freeform gesture width, 30mm. However, it is smaller than 1/4 of
+ * the touch pack diagnal length. Two fingers' distance must be greater than the both
+ * value to be freeform gesture, so that after two fingers start to move downwards,
+ * the gesture should be swipe.
+ */
+TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthLowResolutionSwipe) {
+    // The min freeform gesture width is 5units/mm x 30mm = 150
+    // which is greater than fraction of the diagnal length of the touchpad (349).
+    // Thus, MaxSwipWidth is the fraction of the diagnal length, 349.
+    preparePointerMode(5 /*xResolution*/, 5 /*yResolution*/);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+    NotifyMotionArgs motionArgs;
+
+    // Two fingers down at once.
+    // The two fingers are 250 units apart, expects the current gesture to be PRESS
+    // Pointer's initial position is used the [0,0] coordinate.
+    int32_t x1 = 100, y1 = 125, x2 = 350, y2 = 125;
+
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1, y1);
+    processMTSync(mapper);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2, y2);
+    processMTSync(mapper);
+    processSync(mapper);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(1U, motionArgs.pointerCount);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    ASSERT_NO_FATAL_FAILURE(
+            assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0));
+
+    // It should be recognized as a SWIPE gesture when two fingers start to move down,
+    // and there should be 1 pointer.
+    int32_t movingDistance = 200;
+    y1 += movingDistance;
+    y2 += movingDistance;
+
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1, y1);
+    processMTSync(mapper);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2, y2);
+    processMTSync(mapper);
+    processSync(mapper);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(1U, motionArgs.pointerCount);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    // New coordinate is the scaled relative coordinate from the initial coordinate.
+    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 0,
+                                                movingDistance * mPointerMovementScale, 1, 0, 0, 0,
+                                                0, 0, 0, 0));
+}
+
+/**
+ * Touch the touch pad with two fingers with a distance wider than the minimum freeform
+ * gesture width and 1/4 of the diagnal length of the touchpad. Expect to receive
+ * freeform gestures after two fingers start to move downwards.
+ */
+TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthFreeform) {
+    preparePointerMode(25 /*xResolution*/, 25 /*yResolution*/);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    NotifyMotionArgs motionArgs;
+
+    // Two fingers down at once. Wider than the max swipe width.
+    // The gesture is expected to be PRESS, then transformed to FREEFORM
+    int32_t x1 = 100, y1 = 125, x2 = 900, y2 = 125;
+
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1, y1);
+    processMTSync(mapper);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2, y2);
+    processMTSync(mapper);
+    processSync(mapper);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(1U, motionArgs.pointerCount);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    // One pointer for PRESS, and its coordinate is used as the origin for pointer coordinates.
+    ASSERT_NO_FATAL_FAILURE(
+            assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0));
+
+    int32_t movingDistance = 200;
+
+    // Move two fingers down, expect a cancel event because gesture is changing to freeform,
+    // then two down events for two pointers.
+    y1 += movingDistance;
+    y2 += movingDistance;
+
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1, y1);
+    processMTSync(mapper);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2, y2);
+    processMTSync(mapper);
+    processSync(mapper);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    // The previous PRESS gesture is cancelled, because it is transformed to freeform
+    ASSERT_EQ(1U, motionArgs.pointerCount);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    ASSERT_EQ(1U, motionArgs.pointerCount);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    ASSERT_EQ(2U, motionArgs.pointerCount);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN, motionArgs.action & AMOTION_EVENT_ACTION_MASK);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    // Two pointers' scaled relative coordinates from their initial centroid.
+    // Initial y coordinates are 0 as y1 and y2 have the same value.
+    float cookedX1 = (x1 - x2) / 2 * mPointerXZoomScale;
+    float cookedX2 = (x2 - x1) / 2 * mPointerXZoomScale;
+    // When pointers move,  the new coordinates equal to the initial coordinates plus
+    // scaled moving distance.
+    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], cookedX1,
+                                                movingDistance * mPointerMovementScale, 1, 0, 0, 0,
+                                                0, 0, 0, 0));
+    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], cookedX2,
+                                                movingDistance * mPointerMovementScale, 1, 0, 0, 0,
+                                                0, 0, 0, 0));
+
+    // Move two fingers down again, expect one MOVE motion event.
+    y1 += movingDistance;
+    y2 += movingDistance;
+
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1, y1);
+    processMTSync(mapper);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2, y2);
+    processMTSync(mapper);
+    processSync(mapper);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(2U, motionArgs.pointerCount);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], cookedX1,
+                                                movingDistance * 2 * mPointerMovementScale, 1, 0, 0,
+                                                0, 0, 0, 0, 0));
+    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], cookedX2,
+                                                movingDistance * 2 * mPointerMovementScale, 1, 0, 0,
+                                                0, 0, 0, 0, 0));
+}
+
 // --- JoystickInputMapperTest ---
 
 class JoystickInputMapperTest : public InputMapperTest {
@@ -9438,7 +9894,7 @@
 
     virtual void SetUp(ftl::Flags<InputDeviceClass> classes) {
         mFakeEventHub = std::make_unique<FakeEventHub>();
-        mFakePolicy = new FakeInputReaderPolicy();
+        mFakePolicy = sp<FakeInputReaderPolicy>::make();
         mFakeListener = std::make_unique<TestInputListener>();
         mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
                                                             *mFakeListener);
diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp
index 89c0741..1f4b248 100644
--- a/services/inputflinger/tests/LatencyTracker_test.cpp
+++ b/services/inputflinger/tests/LatencyTracker_test.cpp
@@ -44,7 +44,7 @@
     graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 9;
     graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 10;
     expectedCT.setGraphicsTimeline(std::move(graphicsTimeline));
-    t.connectionTimelines.emplace(new BBinder(), std::move(expectedCT));
+    t.connectionTimelines.emplace(sp<BBinder>::make(), std::move(expectedCT));
     return t;
 }
 
@@ -56,8 +56,8 @@
     sp<IBinder> connection2;
 
     void SetUp() override {
-        connection1 = new BBinder();
-        connection2 = new BBinder();
+        connection1 = sp<BBinder>::make();
+        connection2 = sp<BBinder>::make();
 
         mTracker = std::make_unique<LatencyTracker>(this);
     }
diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
index e378096..f2a3964 100644
--- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
+++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
@@ -19,6 +19,7 @@
 #include <gtest/gtest.h>
 #include <gui/constants.h>
 #include <linux/input.h>
+#include <thread>
 
 #include "TestInputListener.h"
 
@@ -46,6 +47,10 @@
 constexpr int UP = AMOTION_EVENT_ACTION_UP;
 constexpr int CANCEL = AMOTION_EVENT_ACTION_CANCEL;
 
+static nsecs_t toNs(std::chrono::nanoseconds duration) {
+    return duration.count();
+}
+
 struct PointerData {
     float x;
     float y;
@@ -383,7 +388,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 ---
@@ -400,11 +405,11 @@
 };
 
 /**
- * Create a basic configuration change and send it to input classifier.
+ * Create a basic configuration change and send it to input processor.
  * Expect that the event is received by the next input stage, unmodified.
  */
 TEST_F(UnwantedInteractionBlockerTest, ConfigurationChangedIsPassedToNextListener) {
-    // Create a basic configuration change and send to classifier
+    // Create a basic configuration change and send to blocker
     NotifyConfigurationChangedArgs args(1 /*sequenceNum*/, 2 /*eventTime*/);
 
     mBlocker->notifyConfigurationChanged(&args);
@@ -418,7 +423,7 @@
  * to next stage unmodified.
  */
 TEST_F(UnwantedInteractionBlockerTest, KeyIsPassedToNextListener) {
-    // Create a basic key event and send to classifier
+    // Create a basic key event and send to blocker
     NotifyKeyArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 21 /*readTime*/, 3 /*deviceId*/,
                        AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_DEFAULT, 0 /*policyFlags*/,
                        AKEY_EVENT_ACTION_DOWN, 4 /*flags*/, AKEYCODE_HOME, 5 /*scanCode*/,
@@ -547,6 +552,27 @@
     mBlocker->notifyMotion(&args);
 }
 
+/**
+ * Call dump, and on another thread, try to send some motions. The blocker should
+ * not crash. On 2022 hardware, this test requires ~ 13K executions (about 20 seconds) to reproduce
+ * the original bug. This is meant to be run with "--gtest_repeat=100000 --gtest_break_on_failure"
+ * options
+ */
+TEST_F(UnwantedInteractionBlockerTest, DumpCanBeAccessedOnAnotherThread) {
+    mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()});
+    NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
+    mBlocker->notifyMotion(&args1);
+    std::thread dumpThread([this]() {
+        std::string dump;
+        mBlocker->dump(dump);
+    });
+    NotifyMotionArgs args2 = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, MOVE, {{4, 5, 6}});
+    mBlocker->notifyMotion(&args2);
+    NotifyMotionArgs args3 = generateMotionArgs(0 /*downTime*/, 2 /*eventTime*/, UP, {{4, 5, 6}});
+    mBlocker->notifyMotion(&args3);
+    dumpThread.join();
+}
+
 using UnwantedInteractionBlockerTestDeathTest = UnwantedInteractionBlockerTest;
 
 /**
@@ -608,41 +634,41 @@
  */
 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);
@@ -652,94 +678,94 @@
     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());
 }
 
diff --git a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
index 4f066ad..72780fb 100644
--- a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
@@ -42,7 +42,7 @@
     if (useExistingToken) {
         return tokens[fdp.ConsumeIntegralInRange<size_t>(0ul, tokens.size() - 1)];
     }
-    return new BBinder();
+    return sp<BBinder>::make();
 }
 
 extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
@@ -54,7 +54,7 @@
     // Make some pre-defined tokens to ensure that some timelines are complete.
     std::array<sp<IBinder> /*token*/, 10> predefinedTokens;
     for (size_t i = 0; i < predefinedTokens.size(); i++) {
-        predefinedTokens[i] = new BBinder();
+        predefinedTokens[i] = sp<BBinder>::make();
     }
 
     // Randomly invoke LatencyTracker api's until randomness is exhausted.
diff --git a/services/powermanager/WorkSource.cpp b/services/powermanager/WorkSource.cpp
index 1006a06..64a5499 100644
--- a/services/powermanager/WorkSource.cpp
+++ b/services/powermanager/WorkSource.cpp
@@ -28,9 +28,16 @@
         return BAD_VALUE;
     }
     int32_t num;
+    int32_t workChainCount;
     status_t ret = parcel->readInt32(&num)
                 ?: parcel->readInt32Vector(&mUids)
-                ?: parcel->readString16Vector(&mNames);
+                ?: parcel->readString16Vector(&mNames)
+                ?: parcel->readInt32(&workChainCount);
+
+    if (ret == OK && workChainCount > 0) {
+        // We don't yet support WorkChains in native WorkSources.
+        return BAD_VALUE;
+    }
 
     return ret;
 }
@@ -43,7 +50,8 @@
 
     return parcel->writeInt32(mUids.size())
         ?: parcel->writeInt32Vector(mUids)
-        ?: parcel->writeString16Vector(mNames);
+        ?: parcel->writeString16Vector(mNames)
+        ?: parcel->writeInt32(-1);
 }
 
 } // namespace android::os
diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp
index 2d1558a..962784c 100644
--- a/services/powermanager/tests/Android.bp
+++ b/services/powermanager/tests/Android.bp
@@ -31,6 +31,7 @@
         "PowerHalWrapperAidlTest.cpp",
         "PowerHalWrapperHidlV1_0Test.cpp",
         "PowerHalWrapperHidlV1_1Test.cpp",
+        "WorkSourceTest.cpp",
     ],
     cflags: [
         "-Wall",
diff --git a/services/powermanager/tests/IThermalManagerTest.cpp b/services/powermanager/tests/IThermalManagerTest.cpp
index b62be5f..7414958 100644
--- a/services/powermanager/tests/IThermalManagerTest.cpp
+++ b/services/powermanager/tests/IThermalManagerTest.cpp
@@ -33,26 +33,38 @@
 using namespace android::os;
 using namespace std::chrono_literals;
 
-class IThermalServiceTest : public testing::Test,
-                            public BnThermalStatusListener{
+class IThermalServiceTestListener : public BnThermalStatusListener {
+    public:
+        virtual binder::Status onStatusChange(int status) override;
+        std::condition_variable mCondition;
+        int mListenerStatus = 0;
+        std::mutex mMutex;
+};
+
+binder::Status IThermalServiceTestListener::onStatusChange(int status) {
+    std::unique_lock<std::mutex> lock(mMutex);
+    mListenerStatus = status;
+    ALOGI("IThermalServiceTestListener::notifyListener %d", mListenerStatus);
+    mCondition.notify_all();
+    return binder::Status::ok();
+}
+
+class IThermalServiceTest : public testing::Test {
     public:
         IThermalServiceTest();
         void setThermalOverride(int level);
-        virtual binder::Status onStatusChange(int status) override;
         int getStatusFromService();
         void SetUp() override;
         void TearDown() override;
     protected:
         sp<IThermalService> mThermalSvc;
-        std::condition_variable mCondition;
-        int mListenerStatus;
         int mServiceStatus;
-        std::mutex mMutex;
+        sp<IThermalServiceTestListener> mCallback;
 };
 
 IThermalServiceTest::IThermalServiceTest()
- : mListenerStatus(0),
-   mServiceStatus(0) {
+ : mServiceStatus(0),
+   mCallback(sp<IThermalServiceTestListener>::make()) {
 }
 
 void IThermalServiceTest::setThermalOverride(int level) {
@@ -60,14 +72,6 @@
     system(cmdStr.c_str());
 }
 
-binder::Status IThermalServiceTest::onStatusChange(int status) {
-    std::unique_lock<std::mutex> lock(mMutex);
-    mListenerStatus = status;
-    ALOGI("IThermalServiceTest::notifyListener %d", mListenerStatus);
-    mCondition.notify_all();
-    return binder::Status::ok();
-}
-
 int IThermalServiceTest::getStatusFromService() {
     int status;
     binder::Status ret = mThermalSvc->getCurrentThermalStatus(&status);
@@ -87,19 +91,19 @@
     mThermalSvc = interface_cast<IThermalService>(binder);
     EXPECT_NE(mThermalSvc, nullptr);
     // Lock mutex for operation, so listener will only be processed after wait_for is called
-    std::unique_lock<std::mutex> lock(mMutex);
+    std::unique_lock<std::mutex> lock(mCallback->mMutex);
     bool success = false;
-    binder::Status ret = mThermalSvc->registerThermalStatusListener(this, &success);
+    binder::Status ret = mThermalSvc->registerThermalStatusListener(mCallback, &success);
     // Check the result
     ASSERT_TRUE(success);
     ASSERT_TRUE(ret.isOk());
     // Wait for listener called after registration, shouldn't timeout
-    EXPECT_NE(mCondition.wait_for(lock, 1s), std::cv_status::timeout);
+    EXPECT_NE(mCallback->mCondition.wait_for(lock, 1s), std::cv_status::timeout);
 }
 
 void IThermalServiceTest::TearDown() {
     bool success = false;
-    binder::Status ret = mThermalSvc->unregisterThermalStatusListener(this, &success);
+    binder::Status ret = mThermalSvc->unregisterThermalStatusListener(mCallback, &success);
     ASSERT_TRUE(success);
     ASSERT_TRUE(ret.isOk());
 }
@@ -114,14 +118,14 @@
 TEST_P(IThermalListenerTest, TestListener) {
     int level = GetParam();
     // Lock mutex for operation, so listener will only be processed after wait_for is called
-    std::unique_lock<std::mutex> lock(mMutex);
+    std::unique_lock<std::mutex> lock(mCallback->mMutex);
     // Set the override thermal status
     setThermalOverride(level);
     // Wait for listener called, shouldn't timeout
-    EXPECT_NE(mCondition.wait_for(lock, 1s), std::cv_status::timeout);
+    EXPECT_NE(mCallback->mCondition.wait_for(lock, 1s), std::cv_status::timeout);
     // Check the result
-    EXPECT_EQ(level, mListenerStatus);
-    ALOGI("Thermal listener status %d, expecting %d", mListenerStatus, level);
+    EXPECT_EQ(level, mCallback->mListenerStatus);
+    ALOGI("Thermal listener status %d, expecting %d", mCallback->mListenerStatus, level);
 }
 
 INSTANTIATE_TEST_SUITE_P(TestListenerLevels, IThermalListenerTest, testing::Range(
@@ -158,4 +162,4 @@
     ALOGV("Test result = %d\n", status);
 
     return status;
-}
\ No newline at end of file
+}
diff --git a/services/powermanager/tests/WorkSourceTest.cpp b/services/powermanager/tests/WorkSourceTest.cpp
new file mode 100644
index 0000000..bb9164a
--- /dev/null
+++ b/services/powermanager/tests/WorkSourceTest.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 <optional>
+#define LOG_TAG "PowerHalLoaderTest"
+
+#include <android-base/logging.h>
+#include <android/WorkSource.h>
+#include <binder/Parcel.h>
+#include <gtest/gtest.h>
+
+#include <future>
+
+using namespace android;
+using namespace testing;
+
+TEST(WorkSourceTest, Parcel) {
+    std::vector<int32_t> uids = {1, 2};
+    using Names = std::vector<std::optional<String16>>;
+    std::optional<Names> names = std::make_optional<Names>({std::make_optional(String16("name"))});
+    os::WorkSource ws{uids, names};
+
+    Parcel p;
+    ws.writeToParcel(&p);
+    p.setDataPosition(0);
+
+    os::WorkSource otherWs;
+    otherWs.readFromParcel(&p);
+
+    EXPECT_EQ(ws, otherWs);
+    EXPECT_EQ(uids, otherWs.getUids());
+    EXPECT_EQ(names, otherWs.getNames());
+}
diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp
index 14f9a12..94de55c 100644
--- a/services/sensorservice/BatteryService.cpp
+++ b/services/sensorservice/BatteryService.cpp
@@ -74,23 +74,6 @@
     }
 }
 
-void BatteryService::cleanupImpl(uid_t uid) {
-    if (checkService()) {
-        Mutex::Autolock _l(mActivationsLock);
-        int64_t identity = IPCThreadState::self()->clearCallingIdentity();
-        for (size_t i=0 ; i<mActivations.size() ; ) {
-            const Info& info(mActivations[i]);
-            if (info.uid == uid) {
-                mBatteryStatService->noteStopSensor(info.uid, info.handle);
-                mActivations.removeAt(i);
-            } else {
-              i++;
-            }
-        }
-        IPCThreadState::self()->restoreCallingIdentity(identity);
-    }
-}
-
 bool BatteryService::checkService() {
     if (mBatteryStatService == nullptr) {
         const sp<IServiceManager> sm(defaultServiceManager());
diff --git a/services/sensorservice/BatteryService.h b/services/sensorservice/BatteryService.h
index 09eb2c1..13fc58a 100644
--- a/services/sensorservice/BatteryService.h
+++ b/services/sensorservice/BatteryService.h
@@ -32,7 +32,6 @@
 
     void enableSensorImpl(uid_t uid, int handle);
     void disableSensorImpl(uid_t uid, int handle);
-    void cleanupImpl(uid_t uid);
 
     struct Info {
         uid_t uid;
@@ -58,9 +57,6 @@
     static void disableSensor(uid_t uid, int handle) {
         BatteryService::getInstance().disableSensorImpl(uid, handle);
     }
-    static void cleanup(uid_t uid) {
-        BatteryService::getInstance().cleanupImpl(uid);
-    }
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 53a3025..de050e0 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -612,8 +612,10 @@
     return SENSORS_DEVICE_API_VERSION_1_4;
 }
 
-status_t SensorDevice::flush(void* /*ident*/, int handle) {
+status_t SensorDevice::flush(void* ident, int handle) {
     if (mHalWrapper == nullptr) return NO_INIT;
+    if (isClientDisabled(ident)) return INVALID_OPERATION;
+    ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
     return mHalWrapper->flush(handle);
 }
 
@@ -754,6 +756,13 @@
 
 status_t SensorDevice::injectSensorData(const sensors_event_t* injected_sensor_event) {
     if (mHalWrapper == nullptr) return NO_INIT;
+    ALOGD_IF(DEBUG_CONNECTIONS,
+             "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
+             injected_sensor_event->sensor, injected_sensor_event->timestamp,
+             injected_sensor_event->data[0], injected_sensor_event->data[1],
+             injected_sensor_event->data[2], injected_sensor_event->data[3],
+             injected_sensor_event->data[4], injected_sensor_event->data[5]);
+
     return mHalWrapper->injectSensorData(injected_sensor_event);
 }
 
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index fae16f6..2dd12e9 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -157,7 +157,7 @@
     }
 
     const Sensor& s = si->getSensor();
-    if (!SensorService::canAccessSensor(s, "config direct channel", mOpPackageName)) {
+    if (!mService->canAccessSensor(s, "config direct channel", mOpPackageName)) {
         return PERMISSION_DENIED;
     }
 
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 6948895..f06f947 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -162,7 +162,8 @@
     Mutex::Autolock _l(mConnectionLock);
     sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
     if (si == nullptr ||
-        !canAccessSensor(si->getSensor(), "Add to SensorEventConnection: ", mOpPackageName) ||
+        !mService->canAccessSensor(si->getSensor(), "Add to SensorEventConnection: ",
+                                   mOpPackageName) ||
         mSensorInfo.count(handle) > 0) {
         return false;
     }
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 8b81d48..948692b 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -814,6 +814,12 @@
         return handleResetUidState(args, err);
     } else if (args[0] == String16("get-uid-state")) {
         return handleGetUidState(args, out, err);
+    } else if (args[0] == String16("unrestrict-ht")) {
+        mHtRestricted = false;
+        return NO_ERROR;
+    } else if (args[0] == String16("restrict-ht")) {
+        mHtRestricted = true;
+        return NO_ERROR;
     } else if (args.size() == 1 && args[0] == String16("help")) {
         printHelp(out);
         return NO_ERROR;
@@ -1338,11 +1344,11 @@
 Vector<Sensor> SensorService::getDynamicSensorList(const String16& opPackageName) {
     Vector<Sensor> accessibleSensorList;
     mSensors.forEachSensor(
-            [&opPackageName, &accessibleSensorList] (const Sensor& sensor) -> bool {
+            [this, &opPackageName, &accessibleSensorList] (const Sensor& sensor) -> bool {
                 if (sensor.isDynamicSensor()) {
-                    if (canAccessSensor(sensor, "getDynamicSensorList", opPackageName)) {
+                    if (canAccessSensor(sensor, "can't see", opPackageName)) {
                         accessibleSensorList.add(sensor);
-                    } else {
+                    } else if (sensor.getType() != SENSOR_TYPE_HEAD_TRACKER) {
                         ALOGI("Skipped sensor %s because it requires permission %s and app op %" PRId32,
                               sensor.getName().string(),
                               sensor.getRequiredPermission().string(),
@@ -1611,7 +1617,9 @@
             } else {
                 ALOGE("sensor interface of handle=0x%08x is null!", handle);
             }
-            c->removeSensor(handle);
+            if (c->removeSensor(handle)) {
+                BatteryService::disableSensor(c->getUid(), handle);
+            }
         }
         SensorRecord* rec = mActiveSensors.valueAt(i);
         ALOGE_IF(!rec, "mActiveSensors[%zu] is null (handle=0x%08x)!", i, handle);
@@ -1631,7 +1639,6 @@
     }
     c->updateLooperRegistration(mLooper);
     mConnectionHolder.removeEventConnection(connection);
-    BatteryService::cleanup(c->getUid());
     if (c->needsWakeLock()) {
         checkWakeLockStateLocked(&connLock);
     }
@@ -1988,6 +1995,20 @@
 
 bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation,
         const String16& opPackageName) {
+    // Special case for Head Tracker sensor type: currently restricted to system usage only, unless
+    // the restriction is specially lifted for testing
+    if (sensor.getType() == SENSOR_TYPE_HEAD_TRACKER &&
+            !isAudioServerOrSystemServerUid(IPCThreadState::self()->getCallingUid())) {
+        if (!mHtRestricted) {
+            ALOGI("Permitting access to HT sensor type outside system (%s)",
+                  String8(opPackageName).string());
+        } else {
+            ALOGW("%s %s a sensor (%s) as a non-system client", String8(opPackageName).string(),
+                  operation, sensor.getName().string());
+            return false;
+        }
+    }
+
     // Check if a permission is required for this sensor
     if (sensor.getRequiredPermission().length() <= 0) {
         return true;
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index b18d204..234dc9c 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -373,7 +373,7 @@
     status_t cleanupWithoutDisableLocked(const sp<SensorEventConnection>& connection, int handle);
     void cleanupAutoDisabledSensorLocked(const sp<SensorEventConnection>& connection,
             sensors_event_t const* buffer, const int count);
-    static bool canAccessSensor(const Sensor& sensor, const char* operation,
+    bool canAccessSensor(const Sensor& sensor, const char* operation,
             const String16& opPackageName);
     static bool hasPermissionForSensor(const Sensor& sensor);
     static int getTargetSdkVersion(const String16& opPackageName);
@@ -492,6 +492,10 @@
     std::unordered_map<int, SensorServiceUtil::RecentEventLogger*> mRecentEvent;
     Mode mCurrentOperatingMode;
 
+    // true if the head tracker sensor type is currently restricted to system usage only
+    // (can only be unrestricted for testing, via shell cmd)
+    bool mHtRestricted = true;
+
     // This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only
     // applications with this packageName are allowed to activate/deactivate or call flush on
     // sensors. To run CTS this is can be set to ".cts." and only CTS tests will get access to
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 000a2cb..76429ff 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -18,6 +18,7 @@
         "-Wunused",
         "-Wunreachable-code",
         "-Wconversion",
+        "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
     ],
 }
 
@@ -141,14 +142,10 @@
     name: "libsurfaceflinger_sources",
     srcs: [
         "BackgroundExecutor.cpp",
-        "BufferLayer.cpp",
-        "BufferLayerConsumer.cpp",
-        "BufferQueueLayer.cpp",
         "BufferStateLayer.cpp",
         "ClientCache.cpp",
         "Client.cpp",
         "EffectLayer.cpp",
-        "ContainerLayer.cpp",
         "DisplayDevice.cpp",
         "DisplayHardware/AidlComposerHal.cpp",
         "DisplayHardware/HidlComposerHal.cpp",
@@ -166,13 +163,12 @@
         "FrameTracer/FrameTracer.cpp",
         "FrameTracker.cpp",
         "HdrLayerInfoReporter.cpp",
+        "HwcSlotGenerator.cpp",
         "WindowInfosListenerInvoker.cpp",
         "Layer.cpp",
         "LayerProtoHelper.cpp",
-        "LayerRejecter.cpp",
         "LayerRenderArea.cpp",
         "LayerVector.cpp",
-        "MonitoredProducer.cpp",
         "NativeWindowSurface.cpp",
         "RefreshRateOverlay.cpp",
         "RegionSamplingThread.cpp",
@@ -280,7 +276,7 @@
         "liblog",
     ],
     static_libs: [
-        "SurfaceFlingerProperties",
+        "libSurfaceFlingerProperties",
     ],
     export_shared_lib_headers: [
         "android.hardware.graphics.common@1.2",
@@ -288,6 +284,6 @@
         "libui",
     ],
     export_static_lib_headers: [
-        "SurfaceFlingerProperties",
+        "libSurfaceFlingerProperties",
     ],
 }
diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp
index de8e6b3..a15de2b 100644
--- a/services/surfaceflinger/BackgroundExecutor.cpp
+++ b/services/surfaceflinger/BackgroundExecutor.cpp
@@ -19,6 +19,8 @@
 #define LOG_TAG "BackgroundExecutor"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
+#include <utils/Log.h>
+
 #include "BackgroundExecutor.h"
 
 namespace android {
@@ -27,41 +29,49 @@
 
 BackgroundExecutor::BackgroundExecutor() : Singleton<BackgroundExecutor>() {
     mThread = std::thread([&]() {
-        bool done = false;
-        while (!done) {
-            std::vector<std::function<void()>> tasks;
-            {
-                std::unique_lock lock(mMutex);
-                android::base::ScopedLockAssertion assumeLock(mMutex);
-                mWorkAvailableCv.wait(lock,
-                                      [&]() REQUIRES(mMutex) { return mDone || !mTasks.empty(); });
-                tasks = std::move(mTasks);
-                mTasks.clear();
-                done = mDone;
-            } // unlock mMutex
+        LOG_ALWAYS_FATAL_IF(sem_init(&mSemaphore, 0, 0), "sem_init failed");
+        while (!mDone) {
+            LOG_ALWAYS_FATAL_IF(sem_wait(&mSemaphore), "sem_wait failed (%d)", errno);
 
-            for (auto& task : tasks) {
-                task();
+            ftl::SmallVector<Work*, 10> workItems;
+
+            Work* work = mWorks.pop();
+            while (work) {
+                workItems.push_back(work);
+                work = mWorks.pop();
+            }
+
+            // Sequence numbers are guaranteed to be in intended order, as we assume a single
+            // producer and single consumer.
+            std::stable_sort(workItems.begin(), workItems.end(), [](Work* left, Work* right) {
+                return left->sequence < right->sequence;
+            });
+            for (Work* work : workItems) {
+                for (auto& task : work->tasks) {
+                    task();
+                }
+                delete work;
             }
         }
     });
 }
 
 BackgroundExecutor::~BackgroundExecutor() {
-    {
-        std::scoped_lock lock(mMutex);
-        mDone = true;
-        mWorkAvailableCv.notify_all();
-    }
+    mDone = true;
+    LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed");
     if (mThread.joinable()) {
         mThread.join();
+        LOG_ALWAYS_FATAL_IF(sem_destroy(&mSemaphore), "sem_destroy failed");
     }
 }
 
-void BackgroundExecutor::execute(std::function<void()> task) {
-    std::scoped_lock lock(mMutex);
-    mTasks.emplace_back(std::move(task));
-    mWorkAvailableCv.notify_all();
+void BackgroundExecutor::sendCallbacks(Callbacks&& tasks) {
+    Work* work = new Work();
+    work->sequence = mSequence;
+    work->tasks = std::move(tasks);
+    mWorks.push(work);
+    mSequence++;
+    LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed");
 }
 
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h
index 6db7dda..eeaf3bd 100644
--- a/services/surfaceflinger/BackgroundExecutor.h
+++ b/services/surfaceflinger/BackgroundExecutor.h
@@ -16,9 +16,11 @@
 
 #pragma once
 
+#include <Tracing/LocklessStack.h>
 #include <android-base/thread_annotations.h>
+#include <ftl/small_vector.h>
+#include <semaphore.h>
 #include <utils/Singleton.h>
-#include <condition_variable>
 #include <mutex>
 #include <queue>
 #include <thread>
@@ -30,13 +32,26 @@
 public:
     BackgroundExecutor();
     ~BackgroundExecutor();
-    void execute(std::function<void()>);
+    using Callbacks = ftl::SmallVector<std::function<void()>, 10>;
+    // Queues callbacks onto a work queue to be executed by a background thread.
+    // Note that this is not thread-safe - a single producer is assumed.
+    void sendCallbacks(Callbacks&& tasks);
 
 private:
-    std::mutex mMutex;
-    std::condition_variable mWorkAvailableCv GUARDED_BY(mMutex);
-    bool mDone GUARDED_BY(mMutex) = false;
-    std::vector<std::function<void()>> mTasks GUARDED_BY(mMutex);
+    sem_t mSemaphore;
+    std::atomic_bool mDone = false;
+
+    // Sequence number for work items.
+    // Work items are batched by sequence number. Work items for earlier sequence numbers are
+    // executed first. Work items with the same sequence number are executed in the same order they
+    // were added to the stack (meaning the stack must reverse the order after popping from the
+    // queue)
+    int32_t mSequence = 0;
+    struct Work {
+        int32_t sequence = 0;
+        Callbacks tasks;
+    };
+    LocklessStack<Work> mWorks;
     std::thread mThread;
 };
 
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
deleted file mode 100644
index 635b088..0000000
--- a/services/surfaceflinger/BufferLayer.cpp
+++ /dev/null
@@ -1,825 +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.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-//#define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "BufferLayer"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "BufferLayer.h"
-
-#include <compositionengine/CompositionEngine.h>
-#include <compositionengine/LayerFECompositionState.h>
-#include <compositionengine/OutputLayer.h>
-#include <compositionengine/impl/OutputLayerCompositionState.h>
-#include <cutils/compiler.h>
-#include <cutils/native_handle.h>
-#include <cutils/properties.h>
-#include <gui/BufferItem.h>
-#include <gui/BufferQueue.h>
-#include <gui/GLConsumer.h>
-#include <gui/LayerDebugInfo.h>
-#include <gui/Surface.h>
-#include <renderengine/RenderEngine.h>
-#include <ui/DebugUtils.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/NativeHandle.h>
-#include <utils/StopWatch.h>
-#include <utils/Trace.h>
-
-#include <cmath>
-#include <cstdlib>
-#include <mutex>
-#include <sstream>
-
-#include "Colorizer.h"
-#include "DisplayDevice.h"
-#include "FrameTracer/FrameTracer.h"
-#include "LayerRejecter.h"
-#include "TimeStats/TimeStats.h"
-
-namespace android {
-
-using gui::WindowInfo;
-
-static constexpr float defaultMaxLuminance = 1000.0;
-
-BufferLayer::BufferLayer(const LayerCreationArgs& args)
-      : Layer(args),
-        mTextureName(args.textureName),
-        mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {
-    ALOGV("Creating Layer %s", getDebugName());
-
-    mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
-
-    mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow;
-    mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp;
-}
-
-BufferLayer::~BufferLayer() {
-    if (!isClone()) {
-        // The original layer and the clone layer share the same texture. Therefore, only one of
-        // the layers, in this case the original layer, needs to handle the deletion. The original
-        // layer and the clone should be removed at the same time so there shouldn't be any issue
-        // with the clone layer trying to use the deleted texture.
-        mFlinger->deleteTextureAsync(mTextureName);
-    }
-    const int32_t layerId = getSequence();
-    mFlinger->mTimeStats->onDestroy(layerId);
-    mFlinger->mFrameTracer->onDestroy(layerId);
-}
-
-void BufferLayer::useSurfaceDamage() {
-    if (mFlinger->mForceFullDamage) {
-        surfaceDamageRegion = Region::INVALID_REGION;
-    } else {
-        surfaceDamageRegion = mBufferInfo.mSurfaceDamage;
-    }
-}
-
-void BufferLayer::useEmptyDamage() {
-    surfaceDamageRegion.clear();
-}
-
-bool BufferLayer::isOpaque(const Layer::State& s) const {
-    // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
-    // layer's opaque flag.
-    if ((mSidebandStream == nullptr) && (mBufferInfo.mBuffer == nullptr)) {
-        return false;
-    }
-
-    // if the layer has the opaque flag, then we're always opaque,
-    // otherwise we use the current buffer's format.
-    return ((s.flags & layer_state_t::eLayerOpaque) != 0) || getOpacityForFormat(getPixelFormat());
-}
-
-bool BufferLayer::canReceiveInput() const {
-    return !isHiddenByPolicy() && (mBufferInfo.mBuffer == nullptr || getAlpha() > 0.0f);
-}
-
-bool BufferLayer::isVisible() const {
-    return !isHiddenByPolicy() && getAlpha() > 0.0f &&
-            (mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr);
-}
-
-bool BufferLayer::isFixedSize() const {
-    return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE;
-}
-
-bool BufferLayer::usesSourceCrop() const {
-    return true;
-}
-
-static constexpr mat4 inverseOrientation(uint32_t transform) {
-    const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
-    const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
-    const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
-    mat4 tr;
-
-    if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-        tr = tr * rot90;
-    }
-    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
-        tr = tr * flipH;
-    }
-    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
-        tr = tr * flipV;
-    }
-    return inverse(tr);
-}
-
-std::optional<compositionengine::LayerFE::LayerSettings> BufferLayer::prepareClientComposition(
-        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
-    ATRACE_CALL();
-
-    std::optional<compositionengine::LayerFE::LayerSettings> result =
-            Layer::prepareClientComposition(targetSettings);
-    if (!result) {
-        return result;
-    }
-
-    if (CC_UNLIKELY(mBufferInfo.mBuffer == 0) && mSidebandStream != nullptr) {
-        // For surfaceview of tv sideband, there is no activeBuffer
-        // in bufferqueue, we need return LayerSettings.
-        return result;
-    }
-    const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
-            ((isSecure() || isProtected()) && !targetSettings.isSecure);
-    const bool bufferCanBeUsedAsHwTexture =
-            mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE;
-    compositionengine::LayerFE::LayerSettings& layer = *result;
-    if (blackOutLayer || !bufferCanBeUsedAsHwTexture) {
-        ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable",
-                 mName.c_str());
-        prepareClearClientComposition(layer, true /* blackout */);
-        return layer;
-    }
-
-    const State& s(getDrawingState());
-    layer.source.buffer.buffer = mBufferInfo.mBuffer;
-    layer.source.buffer.isOpaque = isOpaque(s);
-    layer.source.buffer.fence = mBufferInfo.mFence;
-    layer.source.buffer.textureName = mTextureName;
-    layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
-    layer.source.buffer.isY410BT2020 = isHdrY410();
-    bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086;
-    bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3;
-    float maxLuminance = 0.f;
-    if (hasSmpte2086 && hasCta861_3) {
-        maxLuminance = std::min(mBufferInfo.mHdrMetadata.smpte2086.maxLuminance,
-                                mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel);
-    } else if (hasSmpte2086) {
-        maxLuminance = mBufferInfo.mHdrMetadata.smpte2086.maxLuminance;
-    } else if (hasCta861_3) {
-        maxLuminance = mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel;
-    } else {
-        switch (layer.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) {
-            case HAL_DATASPACE_TRANSFER_ST2084:
-            case HAL_DATASPACE_TRANSFER_HLG:
-                // Behavior-match previous releases for HDR content
-                maxLuminance = defaultMaxLuminance;
-                break;
-        }
-    }
-    layer.source.buffer.maxLuminanceNits = maxLuminance;
-    layer.frameNumber = mCurrentFrameNumber;
-    layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
-
-    const bool useFiltering =
-            targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering();
-
-    // Query the texture matrix given our current filtering mode.
-    float textureMatrix[16];
-    getDrawingTransformMatrix(useFiltering, textureMatrix);
-
-    if (getTransformToDisplayInverse()) {
-        /*
-         * the code below applies the primary display's inverse transform to
-         * the texture transform
-         */
-        uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
-        mat4 tr = inverseOrientation(transform);
-
-        /**
-         * TODO(b/36727915): This is basically a hack.
-         *
-         * Ensure that regardless of the parent transformation,
-         * this buffer is always transformed from native display
-         * orientation to display orientation. For example, in the case
-         * of a camera where the buffer remains in native orientation,
-         * we want the pixels to always be upright.
-         */
-        sp<Layer> p = mDrawingParent.promote();
-        if (p != nullptr) {
-            const auto parentTransform = p->getTransform();
-            tr = tr * inverseOrientation(parentTransform.getOrientation());
-        }
-
-        // and finally apply it to the original texture matrix
-        const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
-        memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
-    }
-
-    const Rect win{getBounds()};
-    float bufferWidth = getBufferSize(s).getWidth();
-    float bufferHeight = getBufferSize(s).getHeight();
-
-    // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has
-    // been set and there is no parent layer bounds. In that case, the scale is meaningless so
-    // ignore them.
-    if (!getBufferSize(s).isValid()) {
-        bufferWidth = float(win.right) - float(win.left);
-        bufferHeight = float(win.bottom) - float(win.top);
-    }
-
-    const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
-    const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
-    const float translateY = float(win.top) / bufferHeight;
-    const float translateX = float(win.left) / bufferWidth;
-
-    // Flip y-coordinates because GLConsumer expects OpenGL convention.
-    mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) *
-            mat4::translate(vec4(-.5, -.5, 0, 1)) *
-            mat4::translate(vec4(translateX, translateY, 0, 1)) *
-            mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0));
-
-    layer.source.buffer.useTextureFiltering = useFiltering;
-    layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr;
-
-    return layer;
-}
-
-bool BufferLayer::isHdrY410() const {
-    // pixel format is HDR Y410 masquerading as RGBA_1010102
-    return (mBufferInfo.mDataspace == ui::Dataspace::BT2020_ITU_PQ &&
-            mBufferInfo.mApi == NATIVE_WINDOW_API_MEDIA &&
-            mBufferInfo.mPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102);
-}
-
-sp<compositionengine::LayerFE> BufferLayer::getCompositionEngineLayerFE() const {
-    return asLayerFE();
-}
-
-compositionengine::LayerFECompositionState* BufferLayer::editCompositionState() {
-    return mCompositionState.get();
-}
-
-const compositionengine::LayerFECompositionState* BufferLayer::getCompositionState() const {
-    return mCompositionState.get();
-}
-
-void BufferLayer::preparePerFrameCompositionState() {
-    Layer::preparePerFrameCompositionState();
-
-    // Sideband layers
-    auto* compositionState = editCompositionState();
-    if (compositionState->sidebandStream.get() && !compositionState->sidebandStreamHasFrame) {
-        compositionState->compositionType =
-                aidl::android::hardware::graphics::composer3::Composition::SIDEBAND;
-        return;
-    } else if ((mDrawingState.flags & layer_state_t::eLayerIsDisplayDecoration) != 0) {
-        compositionState->compositionType =
-                aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
-    } else {
-        // Normal buffer layers
-        compositionState->hdrMetadata = mBufferInfo.mHdrMetadata;
-        compositionState->compositionType = mPotentialCursor
-                ? aidl::android::hardware::graphics::composer3::Composition::CURSOR
-                : aidl::android::hardware::graphics::composer3::Composition::DEVICE;
-    }
-
-    compositionState->buffer = getBuffer();
-    compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT)
-            ? 0
-            : mBufferInfo.mBufferSlot;
-    compositionState->acquireFence = mBufferInfo.mFence;
-    compositionState->frameNumber = mBufferInfo.mFrameNumber;
-    compositionState->sidebandStreamHasFrame = false;
-}
-
-bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
-    if (mBufferInfo.mBuffer != nullptr) {
-        Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
-    }
-    return hasReadyFrame();
-}
-namespace {
-TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) {
-    using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility;
-    using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness;
-    const auto frameRateCompatibility = [frameRate] {
-        switch (frameRate.type) {
-            case Layer::FrameRateCompatibility::Default:
-                return FrameRateCompatibility::Default;
-            case Layer::FrameRateCompatibility::ExactOrMultiple:
-                return FrameRateCompatibility::ExactOrMultiple;
-            default:
-                return FrameRateCompatibility::Undefined;
-        }
-    }();
-
-    const auto seamlessness = [frameRate] {
-        switch (frameRate.seamlessness) {
-            case scheduler::Seamlessness::OnlySeamless:
-                return Seamlessness::ShouldBeSeamless;
-            case scheduler::Seamlessness::SeamedAndSeamless:
-                return Seamlessness::NotRequired;
-            default:
-                return Seamlessness::Undefined;
-        }
-    }();
-
-    return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(),
-                                       .frameRateCompatibility = frameRateCompatibility,
-                                       .seamlessness = seamlessness};
-}
-} // namespace
-
-void BufferLayer::onPostComposition(const DisplayDevice* display,
-                                    const std::shared_ptr<FenceTime>& glDoneFence,
-                                    const std::shared_ptr<FenceTime>& presentFence,
-                                    const CompositorTiming& compositorTiming) {
-    // mFrameLatencyNeeded is true when a new frame was latched for the
-    // composition.
-    if (!mBufferInfo.mFrameLatencyNeeded) return;
-
-    mAlreadyDisplayedThisCompose = false;
-
-    // Update mFrameEventHistory.
-    {
-        Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence,
-                                              compositorTiming);
-        finalizeFrameEventHistory(glDoneFence, compositorTiming);
-    }
-
-    // Update mFrameTracker.
-    nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime;
-    mFrameTracker.setDesiredPresentTime(desiredPresentTime);
-
-    const int32_t layerId = getSequence();
-    mFlinger->mTimeStats->setDesiredTime(layerId, mCurrentFrameNumber, desiredPresentTime);
-
-    const auto outputLayer = findOutputLayerForDisplay(display);
-    if (outputLayer && outputLayer->requiresClientComposition()) {
-        nsecs_t clientCompositionTimestamp = outputLayer->getState().clientCompositionTimestamp;
-        mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber,
-                                               clientCompositionTimestamp,
-                                               FrameTracer::FrameEvent::FALLBACK_COMPOSITION);
-        // Update the SurfaceFrames in the drawing state
-        if (mDrawingState.bufferSurfaceFrameTX) {
-            mDrawingState.bufferSurfaceFrameTX->setGpuComposition();
-        }
-        for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) {
-            surfaceFrame->setGpuComposition();
-        }
-    }
-
-    std::shared_ptr<FenceTime> frameReadyFence = mBufferInfo.mFenceTime;
-    if (frameReadyFence->isValid()) {
-        mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
-    } else {
-        // There was no fence for this frame, so assume that it was ready
-        // to be presented at the desired present time.
-        mFrameTracker.setFrameReadyTime(desiredPresentTime);
-    }
-
-    if (display) {
-        const Fps refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
-        const std::optional<Fps> renderRate =
-                mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
-
-        const auto vote = frameRateToSetFrameRateVotePayload(mDrawingState.frameRate);
-        const auto gameMode = getGameMode();
-
-        if (presentFence->isValid()) {
-            mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence,
-                                                  refreshRate, renderRate, vote, gameMode);
-            mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber,
-                                               presentFence,
-                                               FrameTracer::FrameEvent::PRESENT_FENCE);
-            mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
-        } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId());
-                   displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
-            // The HWC doesn't support present fences, so use the refresh
-            // timestamp instead.
-            const nsecs_t actualPresentTime = display->getRefreshTimestamp();
-            mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime,
-                                                 refreshRate, renderRate, vote, gameMode);
-            mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(),
-                                                   mCurrentFrameNumber, actualPresentTime,
-                                                   FrameTracer::FrameEvent::PRESENT_FENCE);
-            mFrameTracker.setActualPresentTime(actualPresentTime);
-        }
-    }
-
-    mFrameTracker.advanceFrame();
-    mBufferInfo.mFrameLatencyNeeded = false;
-}
-
-void BufferLayer::gatherBufferInfo() {
-    mBufferInfo.mPixelFormat =
-            !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat();
-    mBufferInfo.mFrameLatencyNeeded = true;
-}
-
-bool BufferLayer::shouldPresentNow(nsecs_t expectedPresentTime) const {
-    // If this is not a valid vsync for the layer's uid, return and try again later
-    const bool isVsyncValidForUid =
-            mFlinger->mScheduler->isVsyncValid(expectedPresentTime, mOwnerUid);
-    if (!isVsyncValidForUid) {
-        ATRACE_NAME("!isVsyncValidForUid");
-        return false;
-    }
-
-    // AutoRefresh layers and sideband streams should always be presented
-    if (getSidebandStreamChanged() || getAutoRefresh()) {
-        return true;
-    }
-
-    // If this layer doesn't have a frame is shouldn't be presented
-    if (!hasFrameUpdate()) {
-        return false;
-    }
-
-    // Defer to the derived class to decide whether the next buffer is due for
-    // presentation.
-    return isBufferDue(expectedPresentTime);
-}
-
-bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                              nsecs_t expectedPresentTime) {
-    ATRACE_CALL();
-
-    bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
-
-    if (refreshRequired) {
-        return refreshRequired;
-    }
-
-    // If the head buffer's acquire fence hasn't signaled yet, return and
-    // try again later
-    if (!fenceHasSignaled()) {
-        ATRACE_NAME("!fenceHasSignaled()");
-        mFlinger->onLayerUpdate();
-        return false;
-    }
-
-    // Capture the old state of the layer for comparisons later
-    const State& s(getDrawingState());
-    const bool oldOpacity = isOpaque(s);
-
-    BufferInfo oldBufferInfo = mBufferInfo;
-
-    status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime);
-    if (err != NO_ERROR) {
-        return false;
-    }
-
-    err = updateActiveBuffer();
-    if (err != NO_ERROR) {
-        return false;
-    }
-
-    err = updateFrameNumber(latchTime);
-    if (err != NO_ERROR) {
-        return false;
-    }
-
-    gatherBufferInfo();
-
-    if (oldBufferInfo.mBuffer == nullptr) {
-        // the first time we receive a buffer, we need to trigger a
-        // geometry invalidation.
-        recomputeVisibleRegions = true;
-    }
-
-    if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) ||
-        (mBufferInfo.mTransform != oldBufferInfo.mTransform) ||
-        (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) ||
-        (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) {
-        recomputeVisibleRegions = true;
-    }
-
-    if (oldBufferInfo.mBuffer != nullptr) {
-        uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
-        uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
-        if (bufWidth != oldBufferInfo.mBuffer->getWidth() ||
-            bufHeight != oldBufferInfo.mBuffer->getHeight()) {
-            recomputeVisibleRegions = true;
-        }
-    }
-
-    if (oldOpacity != isOpaque(s)) {
-        recomputeVisibleRegions = true;
-    }
-
-    return true;
-}
-
-bool BufferLayer::hasReadyFrame() const {
-    return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh();
-}
-
-uint32_t BufferLayer::getEffectiveScalingMode() const {
-    return mBufferInfo.mScaleMode;
-}
-
-bool BufferLayer::isProtected() const {
-    return (mBufferInfo.mBuffer != nullptr) &&
-            (mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
-}
-
-// As documented in libhardware header, formats in the range
-// 0x100 - 0x1FF are specific to the HAL implementation, and
-// are known to have no alpha channel
-// TODO: move definition for device-specific range into
-// hardware.h, instead of using hard-coded values here.
-#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
-
-bool BufferLayer::getOpacityForFormat(PixelFormat format) {
-    if (HARDWARE_IS_DEVICE_FORMAT(format)) {
-        return true;
-    }
-    switch (format) {
-        case PIXEL_FORMAT_RGBA_8888:
-        case PIXEL_FORMAT_BGRA_8888:
-        case PIXEL_FORMAT_RGBA_FP16:
-        case PIXEL_FORMAT_RGBA_1010102:
-        case PIXEL_FORMAT_R_8:
-            return false;
-    }
-    // in all other case, we have no blending (also for unknown formats)
-    return true;
-}
-
-bool BufferLayer::needsFiltering(const DisplayDevice* display) const {
-    const auto outputLayer = findOutputLayerForDisplay(display);
-    if (outputLayer == nullptr) {
-        return false;
-    }
-
-    // We need filtering if the sourceCrop rectangle size does not match the
-    // displayframe rectangle size (not a 1:1 render)
-    const auto& compositionState = outputLayer->getState();
-    const auto displayFrame = compositionState.displayFrame;
-    const auto sourceCrop = compositionState.sourceCrop;
-    return sourceCrop.getHeight() != displayFrame.getHeight() ||
-            sourceCrop.getWidth() != displayFrame.getWidth();
-}
-
-bool BufferLayer::needsFilteringForScreenshots(const DisplayDevice* display,
-                                               const ui::Transform& inverseParentTransform) const {
-    const auto outputLayer = findOutputLayerForDisplay(display);
-    if (outputLayer == nullptr) {
-        return false;
-    }
-
-    // We need filtering if the sourceCrop rectangle size does not match the
-    // viewport rectangle size (not a 1:1 render)
-    const auto& compositionState = outputLayer->getState();
-    const ui::Transform& displayTransform = display->getTransform();
-    const ui::Transform inverseTransform = inverseParentTransform * displayTransform.inverse();
-    // Undo the transformation of the displayFrame so that we're back into
-    // layer-stack space.
-    const Rect frame = inverseTransform.transform(compositionState.displayFrame);
-    const FloatRect sourceCrop = compositionState.sourceCrop;
-
-    int32_t frameHeight = frame.getHeight();
-    int32_t frameWidth = frame.getWidth();
-    // If the display transform had a rotational component then undo the
-    // rotation so that the orientation matches the source crop.
-    if (displayTransform.getOrientation() & ui::Transform::ROT_90) {
-        std::swap(frameHeight, frameWidth);
-    }
-    return sourceCrop.getHeight() != frameHeight || sourceCrop.getWidth() != frameWidth;
-}
-
-Rect BufferLayer::getBufferSize(const State& s) const {
-    // If we have a sideband stream, or we are scaling the buffer then return the layer size since
-    // we cannot determine the buffer size.
-    if ((s.sidebandStream != nullptr) ||
-        (getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE)) {
-        return Rect(getActiveWidth(s), getActiveHeight(s));
-    }
-
-    if (mBufferInfo.mBuffer == nullptr) {
-        return Rect::INVALID_RECT;
-    }
-
-    uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
-    uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
-
-    // Undo any transformations on the buffer and return the result.
-    if (mBufferInfo.mTransform & ui::Transform::ROT_90) {
-        std::swap(bufWidth, bufHeight);
-    }
-
-    if (getTransformToDisplayInverse()) {
-        uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
-        if (invTransform & ui::Transform::ROT_90) {
-            std::swap(bufWidth, bufHeight);
-        }
-    }
-
-    return Rect(bufWidth, bufHeight);
-}
-
-FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const {
-    const State& s(getDrawingState());
-
-    // If we have a sideband stream, or we are scaling the buffer then return the layer size since
-    // we cannot determine the buffer size.
-    if ((s.sidebandStream != nullptr) ||
-        (getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE)) {
-        return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s));
-    }
-
-    if (mBufferInfo.mBuffer == nullptr) {
-        return parentBounds;
-    }
-
-    uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
-    uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
-
-    // Undo any transformations on the buffer and return the result.
-    if (mBufferInfo.mTransform & ui::Transform::ROT_90) {
-        std::swap(bufWidth, bufHeight);
-    }
-
-    if (getTransformToDisplayInverse()) {
-        uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
-        if (invTransform & ui::Transform::ROT_90) {
-            std::swap(bufWidth, bufHeight);
-        }
-    }
-
-    return FloatRect(0, 0, bufWidth, bufHeight);
-}
-
-void BufferLayer::latchAndReleaseBuffer() {
-    if (hasReadyFrame()) {
-        bool ignored = false;
-        latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */);
-    }
-    releasePendingBuffer(systemTime());
-}
-
-PixelFormat BufferLayer::getPixelFormat() const {
-    return mBufferInfo.mPixelFormat;
-}
-
-bool BufferLayer::getTransformToDisplayInverse() const {
-    return mBufferInfo.mTransformToDisplayInverse;
-}
-
-Rect BufferLayer::getBufferCrop() const {
-    // this is the crop rectangle that applies to the buffer
-    // itself (as opposed to the window)
-    if (!mBufferInfo.mCrop.isEmpty()) {
-        // if the buffer crop is defined, we use that
-        return mBufferInfo.mCrop;
-    } else if (mBufferInfo.mBuffer != nullptr) {
-        // otherwise we use the whole buffer
-        return mBufferInfo.mBuffer->getBounds();
-    } else {
-        // if we don't have a buffer yet, we use an empty/invalid crop
-        return Rect();
-    }
-}
-
-uint32_t BufferLayer::getBufferTransform() const {
-    return mBufferInfo.mTransform;
-}
-
-ui::Dataspace BufferLayer::getDataSpace() const {
-    return mBufferInfo.mDataspace;
-}
-
-ui::Dataspace BufferLayer::translateDataspace(ui::Dataspace dataspace) {
-    ui::Dataspace updatedDataspace = dataspace;
-    // translate legacy dataspaces to modern dataspaces
-    switch (dataspace) {
-        case ui::Dataspace::SRGB:
-            updatedDataspace = ui::Dataspace::V0_SRGB;
-            break;
-        case ui::Dataspace::SRGB_LINEAR:
-            updatedDataspace = ui::Dataspace::V0_SRGB_LINEAR;
-            break;
-        case ui::Dataspace::JFIF:
-            updatedDataspace = ui::Dataspace::V0_JFIF;
-            break;
-        case ui::Dataspace::BT601_625:
-            updatedDataspace = ui::Dataspace::V0_BT601_625;
-            break;
-        case ui::Dataspace::BT601_525:
-            updatedDataspace = ui::Dataspace::V0_BT601_525;
-            break;
-        case ui::Dataspace::BT709:
-            updatedDataspace = ui::Dataspace::V0_BT709;
-            break;
-        default:
-            break;
-    }
-
-    return updatedDataspace;
-}
-
-sp<GraphicBuffer> BufferLayer::getBuffer() const {
-    return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr;
-}
-
-void BufferLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) {
-    GLConsumer::computeTransformMatrix(outMatrix,
-                                       mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer()
-                                                           : nullptr,
-                                       mBufferInfo.mCrop, mBufferInfo.mTransform, filteringEnabled);
-}
-
-void BufferLayer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {
-    Layer::setInitialValuesForClone(clonedFrom);
-
-    sp<BufferLayer> bufferClonedFrom = static_cast<BufferLayer*>(clonedFrom.get());
-    mPremultipliedAlpha = bufferClonedFrom->mPremultipliedAlpha;
-    mPotentialCursor = bufferClonedFrom->mPotentialCursor;
-    mProtectedByApp = bufferClonedFrom->mProtectedByApp;
-
-    updateCloneBufferInfo();
-}
-
-void BufferLayer::updateCloneBufferInfo() {
-    if (!isClone() || !isClonedFromAlive()) {
-        return;
-    }
-
-    sp<BufferLayer> clonedFrom = static_cast<BufferLayer*>(getClonedFrom().get());
-    mBufferInfo = clonedFrom->mBufferInfo;
-    mSidebandStream = clonedFrom->mSidebandStream;
-    surfaceDamageRegion = clonedFrom->surfaceDamageRegion;
-    mCurrentFrameNumber = clonedFrom->mCurrentFrameNumber.load();
-    mPreviousFrameNumber = clonedFrom->mPreviousFrameNumber;
-
-    // After buffer info is updated, the drawingState from the real layer needs to be copied into
-    // the cloned. This is because some properties of drawingState can change when latchBuffer is
-    // called. However, copying the drawingState would also overwrite the cloned layer's relatives
-    // and touchableRegionCrop. Therefore, temporarily store the relatives so they can be set in
-    // the cloned drawingState again.
-    wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf;
-    SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives;
-    wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop;
-    WindowInfo tmpInputInfo = mDrawingState.inputInfo;
-
-    cloneDrawingState(clonedFrom.get());
-
-    mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop;
-    mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf;
-    mDrawingState.zOrderRelatives = tmpZOrderRelatives;
-    mDrawingState.inputInfo = tmpInputInfo;
-}
-
-void BufferLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) {
-    mTransformHint = getFixedTransformHint();
-    if (mTransformHint == ui::Transform::ROT_INVALID) {
-        mTransformHint = displayTransformHint;
-    }
-}
-
-bool BufferLayer::bufferNeedsFiltering() const {
-    return isFixedSize();
-}
-
-const std::shared_ptr<renderengine::ExternalTexture>& BufferLayer::getExternalTexture() const {
-    return mBufferInfo.mBuffer;
-}
-
-} // namespace android
-
-#if defined(__gl_h_)
-#error "don't include gl/gl.h in this file"
-#endif
-
-#if defined(__gl2_h_)
-#error "don't include gl2/gl2.h in this file"
-#endif
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
deleted file mode 100644
index 2f3db74..0000000
--- a/services/surfaceflinger/BufferLayer.h
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <sys/types.h>
-#include <cstdint>
-#include <list>
-
-#include <android/gui/ISurfaceComposerClient.h>
-#include <gui/LayerState.h>
-#include <renderengine/Image.h>
-#include <renderengine/Mesh.h>
-#include <renderengine/Texture.h>
-#include <system/window.h> // For NATIVE_WINDOW_SCALING_MODE_FREEZE
-#include <ui/FrameStats.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/PixelFormat.h>
-#include <ui/Region.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <utils/Timers.h>
-
-#include "BufferLayerConsumer.h"
-#include "Client.h"
-#include "DisplayHardware/HWComposer.h"
-#include "FrameTimeline.h"
-#include "FrameTracker.h"
-#include "Layer.h"
-#include "LayerVector.h"
-#include "MonitoredProducer.h"
-#include "SurfaceFlinger.h"
-
-namespace android {
-
-class BufferLayer : public Layer {
-public:
-    explicit BufferLayer(const LayerCreationArgs& args);
-    virtual ~BufferLayer() override;
-
-    // Implements Layer.
-    sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override;
-    compositionengine::LayerFECompositionState* editCompositionState() override;
-
-    // If we have received a new buffer this frame, we will pass its surface
-    // damage down to hardware composer. Otherwise, we must send a region with
-    // one empty rect.
-    void useSurfaceDamage() override;
-    void useEmptyDamage() override;
-
-    bool isOpaque(const Layer::State& s) const override;
-    bool canReceiveInput() const override;
-
-    // isVisible - true if this layer is visible, false otherwise
-    bool isVisible() const override;
-
-    // isProtected - true if the layer may contain protected content in the
-    // GRALLOC_USAGE_PROTECTED sense.
-    bool isProtected() const override;
-
-    // isFixedSize - true if content has a fixed size
-    bool isFixedSize() const override;
-
-    bool usesSourceCrop() const override;
-
-    bool isHdrY410() const override;
-
-    void onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& glDoneFence,
-                           const std::shared_ptr<FenceTime>& presentFence,
-                           const CompositorTiming&) override;
-
-    // latchBuffer - called each time the screen is redrawn and returns whether
-    // the visible regions need to be recomputed (this is a fairly heavy
-    // operation, so this should be set only if needed). Typically this is used
-    // to figure out if the content or size of a surface has changed.
-    bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                     nsecs_t expectedPresentTime) override;
-    bool hasReadyFrame() const override;
-
-    // Returns the current scaling mode
-    uint32_t getEffectiveScalingMode() const override;
-
-    // Calls latchBuffer if the buffer has a frame queued and then releases the buffer.
-    // This is used if the buffer is just latched and releases to free up the buffer
-    // and will not be shown on screen.
-    // Should only be called on the main thread.
-    void latchAndReleaseBuffer() override;
-
-    bool getTransformToDisplayInverse() const override;
-
-    Rect getBufferCrop() const override;
-
-    uint32_t getBufferTransform() const override;
-
-    ui::Dataspace getDataSpace() const override;
-
-    sp<GraphicBuffer> getBuffer() const override;
-    const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const override;
-
-    ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; }
-
-    // Returns true if the transformed buffer size does not match the layer size and we need
-    // to apply filtering.
-    virtual bool bufferNeedsFiltering() const;
-
-protected:
-    struct BufferInfo {
-        nsecs_t mDesiredPresentTime;
-        std::shared_ptr<FenceTime> mFenceTime;
-        sp<Fence> mFence;
-        uint32_t mTransform{0};
-        ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN};
-        Rect mCrop;
-        uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
-        Region mSurfaceDamage;
-        HdrMetadata mHdrMetadata;
-        int mApi;
-        PixelFormat mPixelFormat{PIXEL_FORMAT_NONE};
-        bool mTransformToDisplayInverse{false};
-
-        std::shared_ptr<renderengine::ExternalTexture> mBuffer;
-        uint64_t mFrameNumber;
-        int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT};
-
-        bool mFrameLatencyNeeded{false};
-    };
-
-    BufferInfo mBufferInfo;
-    virtual void gatherBufferInfo() = 0;
-
-    std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
-            compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
-
-    /*
-     * compositionengine::LayerFE overrides
-     */
-    const compositionengine::LayerFECompositionState* getCompositionState() const override;
-    bool onPreComposition(nsecs_t) override;
-    void preparePerFrameCompositionState() override;
-
-    static bool getOpacityForFormat(PixelFormat format);
-
-    // from graphics API
-    const uint32_t mTextureName;
-    ui::Dataspace translateDataspace(ui::Dataspace dataspace);
-    void setInitialValuesForClone(const sp<Layer>& clonedFrom);
-    void updateCloneBufferInfo() override;
-    uint64_t mPreviousFrameNumber = 0;
-
-    void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
-
-    // Transform hint provided to the producer. This must be accessed holding
-    // the mStateLock.
-    ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
-
-    bool getAutoRefresh() const { return mDrawingState.autoRefresh; }
-    bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
-
-    // Returns true if the next buffer should be presented at the expected present time
-    bool shouldPresentNow(nsecs_t expectedPresentTime) const;
-
-    // Returns true if the next buffer should be presented at the expected present time,
-    // overridden by BufferStateLayer and BufferQueueLayer for implementation
-    // specific logic
-    virtual bool isBufferDue(nsecs_t /*expectedPresentTime*/) const = 0;
-
-    std::atomic<bool> mSidebandStreamChanged{false};
-
-private:
-    virtual bool fenceHasSignaled() const = 0;
-    virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0;
-
-    // Latch sideband stream and returns true if the dirty region should be updated.
-    virtual bool latchSidebandStream(bool& recomputeVisibleRegions) = 0;
-
-    virtual bool hasFrameUpdate() const = 0;
-
-    virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                                    nsecs_t expectedPresentTime) = 0;
-
-    virtual status_t updateActiveBuffer() = 0;
-    virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
-
-    // We generate InputWindowHandles for all non-cursor buffered layers regardless of whether they
-    // have an InputChannel. This is to enable the InputDispatcher to do PID based occlusion
-    // detection.
-    bool needsInputInfo() const override { return !mPotentialCursor; }
-
-    // Returns true if this layer requires filtering
-    bool needsFiltering(const DisplayDevice*) const override;
-    bool needsFilteringForScreenshots(const DisplayDevice*,
-                                      const ui::Transform& inverseParentTransform) const override;
-
-    // BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame
-    // and its parent layer is not bounded
-    Rect getBufferSize(const State& s) const override;
-
-    PixelFormat getPixelFormat() const;
-
-    // Computes the transform matrix using the setFilteringEnabled to determine whether the
-    // transform matrix should be computed for use with bilinear filtering.
-    void getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]);
-
-    std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
-
-    FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
-};
-
-} // namespace android
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
deleted file mode 100644
index 9ae45fc..0000000
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-#undef LOG_TAG
-#define LOG_TAG "BufferLayerConsumer"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-//#define LOG_NDEBUG 0
-
-#include "BufferLayerConsumer.h"
-#include "Layer.h"
-#include "Scheduler/VsyncController.h"
-
-#include <inttypes.h>
-
-#include <cutils/compiler.h>
-
-#include <hardware/hardware.h>
-
-#include <math/mat4.h>
-
-#include <gui/BufferItem.h>
-#include <gui/GLConsumer.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/SurfaceComposerClient.h>
-#include <private/gui/ComposerService.h>
-#include <renderengine/RenderEngine.h>
-#include <renderengine/impl/ExternalTexture.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <utils/Trace.h>
-
-namespace android {
-
-// Macros for including the BufferLayerConsumer name in log messages
-#define BLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define BLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
-//#define BLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define BLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define BLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
-
-static const mat4 mtxIdentity;
-
-BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq,
-                                         renderengine::RenderEngine& engine, uint32_t tex,
-                                         Layer* layer)
-      : ConsumerBase(bq, false),
-        mCurrentCrop(Rect::EMPTY_RECT),
-        mCurrentTransform(0),
-        mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
-        mCurrentFence(Fence::NO_FENCE),
-        mCurrentTimestamp(0),
-        mCurrentDataSpace(ui::Dataspace::UNKNOWN),
-        mCurrentFrameNumber(0),
-        mCurrentTransformToDisplayInverse(false),
-        mCurrentSurfaceDamage(),
-        mCurrentApi(0),
-        mDefaultWidth(1),
-        mDefaultHeight(1),
-        mFilteringEnabled(true),
-        mRE(engine),
-        mTexName(tex),
-        mLayer(layer),
-        mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) {
-    BLC_LOGV("BufferLayerConsumer");
-
-    memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
-
-    mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
-}
-
-status_t BufferLayerConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        BLC_LOGE("setDefaultBufferSize: BufferLayerConsumer is abandoned!");
-        return NO_INIT;
-    }
-    mDefaultWidth = w;
-    mDefaultHeight = h;
-    return mConsumer->setDefaultBufferSize(w, h);
-}
-
-void BufferLayerConsumer::setContentsChangedListener(const wp<ContentsChangedListener>& listener) {
-    setFrameAvailableListener(listener);
-    Mutex::Autolock lock(mMutex);
-    mContentsChangedListener = listener;
-}
-
-status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
-                                             bool* autoRefresh, bool* queuedBuffer,
-                                             uint64_t maxFrameNumber) {
-    ATRACE_CALL();
-    BLC_LOGV("updateTexImage");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        BLC_LOGE("updateTexImage: BufferLayerConsumer is abandoned!");
-        return NO_INIT;
-    }
-
-    BufferItem item;
-
-    // Acquire the next buffer.
-    // In asynchronous mode the list is guaranteed to be one buffer
-    // deep, while in synchronous mode we use the oldest buffer.
-    status_t err = acquireBufferLocked(&item, expectedPresentTime, maxFrameNumber);
-    if (err != NO_ERROR) {
-        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
-            err = NO_ERROR;
-        } else if (err == BufferQueue::PRESENT_LATER) {
-            // return the error, without logging
-        } else {
-            BLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err);
-        }
-        return err;
-    }
-
-    if (autoRefresh) {
-        *autoRefresh = item.mAutoRefresh;
-    }
-
-    if (queuedBuffer) {
-        *queuedBuffer = item.mQueuedBuffer;
-    }
-
-    // We call the rejecter here, in case the caller has a reason to
-    // not accept this buffer.  This is used by SurfaceFlinger to
-    // reject buffers which have the wrong size
-    int slot = item.mSlot;
-    if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) {
-        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
-        return BUFFER_REJECTED;
-    }
-
-    // Release the previous buffer.
-    err = updateAndReleaseLocked(item, &mPendingRelease);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    return err;
-}
-
-void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) {
-    if (!fence->isValid()) {
-        return;
-    }
-
-    auto slot = mPendingRelease.isPending ? mPendingRelease.currentTexture : mCurrentTexture;
-    if (slot == BufferQueue::INVALID_BUFFER_SLOT) {
-        return;
-    }
-
-    auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer
-                                            : mCurrentTextureBuffer->getBuffer();
-    auto err = addReleaseFence(slot, buffer, fence);
-    if (err != OK) {
-        BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err);
-    }
-}
-
-bool BufferLayerConsumer::releasePendingBuffer() {
-    if (!mPendingRelease.isPending) {
-        BLC_LOGV("Pending buffer already released");
-        return false;
-    }
-    BLC_LOGV("Releasing pending buffer");
-    Mutex::Autolock lock(mMutex);
-    status_t result =
-            releaseBufferLocked(mPendingRelease.currentTexture, mPendingRelease.graphicBuffer);
-    if (result < NO_ERROR) {
-        BLC_LOGE("releasePendingBuffer failed: %s (%d)", strerror(-result), result);
-    }
-    mPendingRelease = PendingRelease();
-    return true;
-}
-
-sp<Fence> BufferLayerConsumer::getPrevFinalReleaseFence() const {
-    Mutex::Autolock lock(mMutex);
-    return ConsumerBase::mPrevFinalReleaseFence;
-}
-
-status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
-                                                  uint64_t maxFrameNumber) {
-    status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    // If item->mGraphicBuffer is not null, this buffer has not been acquired
-    // before, so we need to clean up old references.
-    if (item->mGraphicBuffer != nullptr) {
-        std::lock_guard<std::mutex> lock(mImagesMutex);
-        if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->getBuffer() == nullptr ||
-            mImages[item->mSlot]->getBuffer()->getId() != item->mGraphicBuffer->getId()) {
-            mImages[item->mSlot] = std::make_shared<
-                    renderengine::impl::ExternalTexture>(item->mGraphicBuffer, mRE,
-                                                         renderengine::impl::ExternalTexture::
-                                                                 Usage::READABLE);
-        }
-    }
-
-    return NO_ERROR;
-}
-
-status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
-                                                     PendingRelease* pendingRelease) {
-    status_t err = NO_ERROR;
-
-    int slot = item.mSlot;
-
-    BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
-             (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->getBuffer() != nullptr)
-                     ? mCurrentTextureBuffer->getBuffer()->handle
-                     : 0,
-             slot, mSlots[slot].mGraphicBuffer->handle);
-
-    // Hang onto the pointer so that it isn't freed in the call to
-    // releaseBufferLocked() if we're in shared buffer mode and both buffers are
-    // the same.
-
-    std::shared_ptr<renderengine::ExternalTexture> nextTextureBuffer;
-    {
-        std::lock_guard<std::mutex> lock(mImagesMutex);
-        nextTextureBuffer = mImages[slot];
-    }
-
-    // release old buffer
-    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        if (pendingRelease == nullptr) {
-            status_t status =
-                    releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->getBuffer());
-            if (status < NO_ERROR) {
-                BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
-                         status);
-                err = status;
-                // keep going, with error raised [?]
-            }
-        } else {
-            pendingRelease->currentTexture = mCurrentTexture;
-            pendingRelease->graphicBuffer = mCurrentTextureBuffer->getBuffer();
-            pendingRelease->isPending = true;
-        }
-    }
-
-    // Update the BufferLayerConsumer state.
-    mCurrentTexture = slot;
-    mCurrentTextureBuffer = nextTextureBuffer;
-    mCurrentCrop = item.mCrop;
-    mCurrentTransform = item.mTransform;
-    mCurrentScalingMode = item.mScalingMode;
-    mCurrentTimestamp = item.mTimestamp;
-    mCurrentDataSpace = static_cast<ui::Dataspace>(item.mDataSpace);
-    mCurrentHdrMetadata = item.mHdrMetadata;
-    mCurrentFence = item.mFence;
-    mCurrentFenceTime = item.mFenceTime;
-    mCurrentFrameNumber = item.mFrameNumber;
-    mCurrentTransformToDisplayInverse = item.mTransformToDisplayInverse;
-    mCurrentSurfaceDamage = item.mSurfaceDamage;
-    mCurrentApi = item.mApi;
-
-    computeCurrentTransformMatrixLocked();
-
-    return err;
-}
-
-void BufferLayerConsumer::getTransformMatrix(float mtx[16]) {
-    Mutex::Autolock lock(mMutex);
-    memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
-}
-
-void BufferLayerConsumer::setFilteringEnabled(bool enabled) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        BLC_LOGE("setFilteringEnabled: BufferLayerConsumer is abandoned!");
-        return;
-    }
-    bool needsRecompute = mFilteringEnabled != enabled;
-    mFilteringEnabled = enabled;
-
-    if (needsRecompute && mCurrentTextureBuffer == nullptr) {
-        BLC_LOGD("setFilteringEnabled called with mCurrentTextureBuffer == nullptr");
-    }
-
-    if (needsRecompute && mCurrentTextureBuffer != nullptr) {
-        computeCurrentTransformMatrixLocked();
-    }
-}
-
-void BufferLayerConsumer::computeCurrentTransformMatrixLocked() {
-    BLC_LOGV("computeCurrentTransformMatrixLocked");
-    if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->getBuffer() == nullptr) {
-        BLC_LOGD("computeCurrentTransformMatrixLocked: "
-                 "mCurrentTextureBuffer is nullptr");
-    }
-    GLConsumer::computeTransformMatrix(mCurrentTransformMatrix,
-                                       mCurrentTextureBuffer == nullptr
-                                               ? nullptr
-                                               : mCurrentTextureBuffer->getBuffer(),
-                                       getCurrentCropLocked(), mCurrentTransform,
-                                       mFilteringEnabled);
-}
-
-nsecs_t BufferLayerConsumer::getTimestamp() {
-    BLC_LOGV("getTimestamp");
-    Mutex::Autolock lock(mMutex);
-    return mCurrentTimestamp;
-}
-
-ui::Dataspace BufferLayerConsumer::getCurrentDataSpace() {
-    BLC_LOGV("getCurrentDataSpace");
-    Mutex::Autolock lock(mMutex);
-    return mCurrentDataSpace;
-}
-
-const HdrMetadata& BufferLayerConsumer::getCurrentHdrMetadata() const {
-    BLC_LOGV("getCurrentHdrMetadata");
-    Mutex::Autolock lock(mMutex);
-    return mCurrentHdrMetadata;
-}
-
-uint64_t BufferLayerConsumer::getFrameNumber() {
-    BLC_LOGV("getFrameNumber");
-    Mutex::Autolock lock(mMutex);
-    return mCurrentFrameNumber;
-}
-
-bool BufferLayerConsumer::getTransformToDisplayInverse() const {
-    Mutex::Autolock lock(mMutex);
-    return mCurrentTransformToDisplayInverse;
-}
-
-const Region& BufferLayerConsumer::getSurfaceDamage() const {
-    return mCurrentSurfaceDamage;
-}
-
-void BufferLayerConsumer::mergeSurfaceDamage(const Region& damage) {
-    if (damage.bounds() == Rect::INVALID_RECT ||
-        mCurrentSurfaceDamage.bounds() == Rect::INVALID_RECT) {
-        mCurrentSurfaceDamage = Region::INVALID_REGION;
-    } else {
-        mCurrentSurfaceDamage |= damage;
-    }
-}
-
-int BufferLayerConsumer::getCurrentApi() const {
-    Mutex::Autolock lock(mMutex);
-    return mCurrentApi;
-}
-
-std::shared_ptr<renderengine::ExternalTexture> BufferLayerConsumer::getCurrentBuffer(
-        int* outSlot, sp<Fence>* outFence) const {
-    Mutex::Autolock lock(mMutex);
-
-    if (outSlot != nullptr) {
-        *outSlot = mCurrentTexture;
-    }
-
-    if (outFence != nullptr) {
-        *outFence = mCurrentFence;
-    }
-
-    return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer;
-}
-
-Rect BufferLayerConsumer::getCurrentCrop() const {
-    Mutex::Autolock lock(mMutex);
-    return getCurrentCropLocked();
-}
-
-Rect BufferLayerConsumer::getCurrentCropLocked() const {
-    uint32_t width = mDefaultWidth;
-    uint32_t height = mDefaultHeight;
-    // If the buffer comes with a rotated bit for 90 (or 270) degrees, switch width/height in order
-    // to scale and crop correctly.
-    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-        width = mDefaultHeight;
-        height = mDefaultWidth;
-    }
-
-    return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
-            ? GLConsumer::scaleDownCrop(mCurrentCrop, width, height)
-            : mCurrentCrop;
-}
-
-uint32_t BufferLayerConsumer::getCurrentTransform() const {
-    Mutex::Autolock lock(mMutex);
-    return mCurrentTransform;
-}
-
-uint32_t BufferLayerConsumer::getCurrentScalingMode() const {
-    Mutex::Autolock lock(mMutex);
-    return mCurrentScalingMode;
-}
-
-sp<Fence> BufferLayerConsumer::getCurrentFence() const {
-    Mutex::Autolock lock(mMutex);
-    return mCurrentFence;
-}
-
-std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const {
-    Mutex::Autolock lock(mMutex);
-    return mCurrentFenceTime;
-}
-
-void BufferLayerConsumer::freeBufferLocked(int slotIndex) {
-    BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
-    std::lock_guard<std::mutex> lock(mImagesMutex);
-    if (slotIndex == mCurrentTexture) {
-        mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
-    }
-    mImages[slotIndex] = nullptr;
-    ConsumerBase::freeBufferLocked(slotIndex);
-}
-
-void BufferLayerConsumer::onDisconnect() {
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        // Nothing to do if we're already abandoned.
-        return;
-    }
-
-    mLayer->onDisconnect();
-}
-
-void BufferLayerConsumer::onSidebandStreamChanged() {
-    [[maybe_unused]] FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
-    {
-        Mutex::Autolock lock(mFrameAvailableMutex);
-        unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get();
-    }
-    sp<ContentsChangedListener> listener;
-    { // scope for the lock
-        Mutex::Autolock lock(mMutex);
-        ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get());
-        listener = mContentsChangedListener.promote();
-    }
-
-    if (listener != nullptr) {
-        listener->onSidebandStreamChanged();
-    }
-}
-
-void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) {
-    if (item.mGraphicBuffer != nullptr && item.mSlot != BufferQueue::INVALID_BUFFER_SLOT) {
-        std::lock_guard<std::mutex> lock(mImagesMutex);
-        const std::shared_ptr<renderengine::ExternalTexture>& oldImage = mImages[item.mSlot];
-        if (oldImage == nullptr || oldImage->getBuffer() == nullptr ||
-            oldImage->getBuffer()->getId() != item.mGraphicBuffer->getId()) {
-            mImages[item.mSlot] = std::make_shared<
-                    renderengine::impl::ExternalTexture>(item.mGraphicBuffer, mRE,
-                                                         renderengine::impl::ExternalTexture::
-                                                                 Usage::READABLE);
-        }
-    }
-}
-
-void BufferLayerConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
-                                                   FrameEventHistoryDelta* outDelta) {
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        // Nothing to do if we're already abandoned.
-        return;
-    }
-
-    mLayer->addAndGetFrameTimestamps(newTimestamps, outDelta);
-}
-
-void BufferLayerConsumer::abandonLocked() {
-    BLC_LOGV("abandonLocked");
-    mCurrentTextureBuffer = nullptr;
-    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
-        std::lock_guard<std::mutex> lock(mImagesMutex);
-        mImages[i] = nullptr;
-    }
-    ConsumerBase::abandonLocked();
-}
-
-status_t BufferLayerConsumer::setConsumerUsageBits(uint64_t usage) {
-    return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
-}
-
-void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const {
-    result.appendFormat("%smTexName=%d mCurrentTexture=%d\n"
-                        "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
-                        prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
-                        mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
-                        mCurrentTransform);
-
-    ConsumerBase::dumpLocked(result, prefix);
-}
-}; // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
deleted file mode 100644
index 9ed80b4..0000000
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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_BUFFERLAYERCONSUMER_H
-#define ANDROID_BUFFERLAYERCONSUMER_H
-
-#include <android-base/thread_annotations.h>
-#include <gui/BufferQueueDefs.h>
-#include <gui/ConsumerBase.h>
-#include <gui/HdrMetadata.h>
-#include <renderengine/ExternalTexture.h>
-#include <ui/FenceTime.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/GraphicTypes.h>
-#include <ui/Region.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/threads.h>
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-class Layer;
-class String8;
-
-namespace renderengine {
-class RenderEngine;
-} // namespace renderengine
-
-/*
- * BufferLayerConsumer consumes buffers of graphics data from a BufferQueue,
- * and makes them available to RenderEngine as a texture.
- *
- * A typical usage pattern is to call updateTexImage() when a new frame is
- * desired.  If a new frame is available, the frame is latched.  If not, the
- * previous contents are retained.  The texture is attached and updated after
- * bindTextureImage() is called.
- *
- * All calls to updateTexImage must be made with RenderEngine being current.
- * The texture is attached to the TEXTURE_EXTERNAL texture target.
- */
-class BufferLayerConsumer : public ConsumerBase {
-public:
-    static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8;
-
-    class BufferRejecter {
-        friend class BufferLayerConsumer;
-        virtual bool reject(const sp<GraphicBuffer>& buf, const BufferItem& item) = 0;
-
-    protected:
-        virtual ~BufferRejecter() {}
-    };
-
-    struct ContentsChangedListener : public FrameAvailableListener {
-        virtual void onSidebandStreamChanged() = 0;
-    };
-
-    // BufferLayerConsumer constructs a new BufferLayerConsumer object.  The
-    // tex parameter indicates the name of the RenderEngine texture to which
-    // images are to be streamed.
-    BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, renderengine::RenderEngine& engine,
-                        uint32_t tex, Layer* layer);
-
-    // Sets the contents changed listener. This should be used instead of
-    // ConsumerBase::setFrameAvailableListener().
-    void setContentsChangedListener(const wp<ContentsChangedListener>& listener);
-
-    // updateTexImage acquires the most recently queued buffer, and sets the
-    // image contents of the target texture to it.
-    //
-    // This call may only be made while RenderEngine is current.
-    //
-    // This calls doFenceWait to ensure proper synchronization unless native
-    // fence is supported.
-    //
-    // Unlike the GLConsumer version, this version takes a functor that may be
-    // used to reject the newly acquired buffer.  It also does not bind the
-    // RenderEngine texture until bindTextureImage is called.
-    status_t updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
-                            bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber);
-
-    // setReleaseFence stores a fence that will signal when the current buffer
-    // is no longer being read. This fence will be returned to the producer
-    // when the current buffer is released by updateTexImage(). Multiple
-    // fences can be set for a given buffer; they will be merged into a single
-    // union fence.
-    void setReleaseFence(const sp<Fence>& fence);
-
-    bool releasePendingBuffer();
-
-    sp<Fence> getPrevFinalReleaseFence() const;
-
-    // See GLConsumer::getTransformMatrix.
-    void getTransformMatrix(float mtx[16]);
-
-    // getTimestamp retrieves the timestamp associated with the texture image
-    // set by the most recent call to updateTexImage.
-    //
-    // The timestamp is in nanoseconds, and is monotonically increasing. Its
-    // other semantics (zero point, etc) are source-dependent and should be
-    // documented by the source.
-    int64_t getTimestamp();
-
-    // getDataSpace retrieves the DataSpace associated with the texture image
-    // set by the most recent call to updateTexImage.
-    ui::Dataspace getCurrentDataSpace();
-
-    // getCurrentHdrMetadata retrieves the HDR metadata associated with the
-    // texture image set by the most recent call to updateTexImage.
-    const HdrMetadata& getCurrentHdrMetadata() const;
-
-    // getFrameNumber retrieves the frame number associated with the texture
-    // image set by the most recent call to updateTexImage.
-    //
-    // The frame number is an incrementing counter set to 0 at the creation of
-    // the BufferQueue associated with this consumer.
-    uint64_t getFrameNumber();
-
-    bool getTransformToDisplayInverse() const;
-
-    // must be called from SF main thread
-    const Region& getSurfaceDamage() const;
-
-    // Merge the given damage region into the current damage region value.
-    void mergeSurfaceDamage(const Region& damage);
-
-    // getCurrentApi retrieves the API which queues the current buffer.
-    int getCurrentApi() const;
-
-    // See GLConsumer::setDefaultBufferSize.
-    status_t setDefaultBufferSize(uint32_t width, uint32_t height);
-
-    // setFilteringEnabled sets whether the transform matrix should be computed
-    // for use with bilinear filtering.
-    void setFilteringEnabled(bool enabled);
-
-    // getCurrentBuffer returns the buffer associated with the current image.
-    // When outSlot is not nullptr, the current buffer slot index is also
-    // returned. Simiarly, when outFence is not nullptr, the current output
-    // fence is returned.
-    std::shared_ptr<renderengine::ExternalTexture> getCurrentBuffer(
-            int* outSlot = nullptr, sp<Fence>* outFence = nullptr) const;
-
-    // getCurrentCrop returns the cropping rectangle of the current buffer.
-    Rect getCurrentCrop() const;
-
-    // getCurrentTransform returns the transform of the current buffer.
-    uint32_t getCurrentTransform() const;
-
-    // getCurrentScalingMode returns the scaling mode of the current buffer.
-    uint32_t getCurrentScalingMode() const;
-
-    // getCurrentFence returns the fence indicating when the current buffer is
-    // ready to be read from.
-    sp<Fence> getCurrentFence() const;
-
-    // getCurrentFence returns the FenceTime indicating when the current
-    // buffer is ready to be read from.
-    std::shared_ptr<FenceTime> getCurrentFenceTime() const;
-
-    // setConsumerUsageBits overrides the ConsumerBase method to OR
-    // DEFAULT_USAGE_FLAGS to usage.
-    status_t setConsumerUsageBits(uint64_t usage);
-    void onBufferAvailable(const BufferItem& item) EXCLUDES(mImagesMutex);
-
-protected:
-    // abandonLocked overrides the ConsumerBase method to clear
-    // mCurrentTextureImage in addition to the ConsumerBase behavior.
-    virtual void abandonLocked() EXCLUDES(mImagesMutex);
-
-    // dumpLocked overrides the ConsumerBase method to dump BufferLayerConsumer-
-    // specific info in addition to the ConsumerBase behavior.
-    virtual void dumpLocked(String8& result, const char* prefix) const;
-
-    // See ConsumerBase::acquireBufferLocked
-    virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
-                                         uint64_t maxFrameNumber = 0) override
-            EXCLUDES(mImagesMutex);
-
-    bool canUseImageCrop(const Rect& crop) const;
-
-    struct PendingRelease {
-        PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer() {}
-
-        bool isPending;
-        int currentTexture;
-        sp<GraphicBuffer> graphicBuffer;
-    };
-
-    // This releases the buffer in the slot referenced by mCurrentTexture,
-    // then updates state to refer to the BufferItem, which must be a
-    // newly-acquired buffer. If pendingRelease is not null, the parameters
-    // which would have been passed to releaseBufferLocked upon the successful
-    // completion of the method will instead be returned to the caller, so that
-    // it may call releaseBufferLocked itself later.
-    status_t updateAndReleaseLocked(const BufferItem& item,
-                                    PendingRelease* pendingRelease = nullptr)
-            EXCLUDES(mImagesMutex);
-
-private:
-    // Utility class for managing GraphicBuffer references into renderengine
-    class Image {
-    public:
-        Image(const sp<GraphicBuffer>& graphicBuffer, renderengine::RenderEngine& engine);
-        virtual ~Image();
-        const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
-
-    private:
-        // mGraphicBuffer is the buffer that was used to create this image.
-        sp<GraphicBuffer> mGraphicBuffer;
-        // Back-reference into renderengine to initiate cleanup.
-        renderengine::RenderEngine& mRE;
-        DISALLOW_COPY_AND_ASSIGN(Image);
-    };
-
-    // freeBufferLocked frees up the given buffer slot. If the slot has been
-    // initialized this will release the reference to the GraphicBuffer in
-    // that slot.  Otherwise it has no effect.
-    //
-    // This method must be called with mMutex locked.
-    virtual void freeBufferLocked(int slotIndex) EXCLUDES(mImagesMutex);
-
-    // IConsumerListener interface
-    void onDisconnect() override;
-    void onSidebandStreamChanged() override;
-    void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
-                                  FrameEventHistoryDelta* outDelta) override;
-
-    // computeCurrentTransformMatrixLocked computes the transform matrix for the
-    // current texture.  It uses mCurrentTransform and the current GraphicBuffer
-    // to compute this matrix and stores it in mCurrentTransformMatrix.
-    // mCurrentTextureImage must not be nullptr.
-    void computeCurrentTransformMatrixLocked();
-
-    // getCurrentCropLocked returns the cropping rectangle of the current buffer.
-    Rect getCurrentCropLocked() const;
-
-    // The default consumer usage flags that BufferLayerConsumer always sets on its
-    // BufferQueue instance; these will be OR:d with any additional flags passed
-    // from the BufferLayerConsumer user. In particular, BufferLayerConsumer will always
-    // consume buffers as hardware textures.
-    static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
-
-    // mCurrentTextureBuffer is the buffer containing the current texture. It's
-    // possible that this buffer is not associated with any buffer slot, so we
-    // must track it separately in order to support the getCurrentBuffer method.
-    std::shared_ptr<renderengine::ExternalTexture> mCurrentTextureBuffer;
-
-    // mCurrentCrop is the crop rectangle that applies to the current texture.
-    // It gets set each time updateTexImage is called.
-    Rect mCurrentCrop;
-
-    // mCurrentTransform is the transform identifier for the current texture. It
-    // gets set each time updateTexImage is called.
-    uint32_t mCurrentTransform;
-
-    // mCurrentScalingMode is the scaling mode for the current texture. It gets
-    // set each time updateTexImage is called.
-    uint32_t mCurrentScalingMode;
-
-    // mCurrentFence is the fence received from BufferQueue in updateTexImage.
-    sp<Fence> mCurrentFence;
-
-    // The FenceTime wrapper around mCurrentFence.
-    std::shared_ptr<FenceTime> mCurrentFenceTime{FenceTime::NO_FENCE};
-
-    // mCurrentTransformMatrix is the transform matrix for the current texture.
-    // It gets computed by computeTransformMatrix each time updateTexImage is
-    // called.
-    float mCurrentTransformMatrix[16];
-
-    // mCurrentTimestamp is the timestamp for the current texture. It
-    // gets set each time updateTexImage is called.
-    int64_t mCurrentTimestamp;
-
-    // mCurrentDataSpace is the dataspace for the current texture. It
-    // gets set each time updateTexImage is called.
-    ui::Dataspace mCurrentDataSpace;
-
-    // mCurrentHdrMetadata is the HDR metadata for the current texture. It
-    // gets set each time updateTexImage is called.
-    HdrMetadata mCurrentHdrMetadata;
-
-    // mCurrentFrameNumber is the frame counter for the current texture.
-    // It gets set each time updateTexImage is called.
-    uint64_t mCurrentFrameNumber;
-
-    // Indicates this buffer must be transformed by the inverse transform of the screen
-    // it is displayed onto. This is applied after BufferLayerConsumer::mCurrentTransform.
-    // This must be set/read from SurfaceFlinger's main thread.
-    bool mCurrentTransformToDisplayInverse;
-
-    // The portion of this surface that has changed since the previous frame
-    Region mCurrentSurfaceDamage;
-
-    int mCurrentApi;
-
-    uint32_t mDefaultWidth, mDefaultHeight;
-
-    // mFilteringEnabled indicates whether the transform matrix is computed for
-    // use with bilinear filtering. It defaults to true and is changed by
-    // setFilteringEnabled().
-    bool mFilteringEnabled;
-
-    renderengine::RenderEngine& mRE;
-
-    // mTexName is the name of the RenderEngine texture to which streamed
-    // images will be bound when bindTexImage is called. It is set at
-    // construction time.
-    const uint32_t mTexName;
-
-    // The layer for this BufferLayerConsumer. Always check mAbandoned before accessing.
-    Layer* mLayer GUARDED_BY(mMutex);
-
-    wp<ContentsChangedListener> mContentsChangedListener;
-
-    // mCurrentTexture is the buffer slot index of the buffer that is currently
-    // bound to the RenderEngine texture. It is initialized to INVALID_BUFFER_SLOT,
-    // indicating that no buffer slot is currently bound to the texture. Note,
-    // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
-    // that no buffer is bound to the texture. A call to setBufferCount will
-    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
-    int mCurrentTexture;
-
-    // Shadow buffer cache for cleaning up renderengine references.
-    std::shared_ptr<renderengine::ExternalTexture>
-            mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex);
-
-    // Separate mutex guarding the shadow buffer cache.
-    // mImagesMutex can be manipulated with binder threads (e.g. onBuffersAllocated)
-    // which is contentious enough that we can't just use mMutex.
-    mutable std::mutex mImagesMutex;
-
-    // A release that is pending on the receipt of a new release fence from
-    // presentDisplay
-    PendingRelease mPendingRelease;
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_BUFFERLAYERCONSUMER_H
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
deleted file mode 100644
index 926aa1d..0000000
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ /dev/null
@@ -1,591 +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.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-#undef LOG_TAG
-#define LOG_TAG "BufferQueueLayer"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include "BufferQueueLayer.h"
-
-#include <compositionengine/LayerFECompositionState.h>
-#include <gui/BufferQueueConsumer.h>
-#include <system/window.h>
-
-#include "LayerRejecter.h"
-#include "SurfaceInterceptor.h"
-
-#include "FrameTracer/FrameTracer.h"
-#include "Scheduler/LayerHistory.h"
-#include "TimeStats/TimeStats.h"
-
-namespace android {
-using PresentState = frametimeline::SurfaceFrame::PresentState;
-
-BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {}
-
-BufferQueueLayer::~BufferQueueLayer() {
-    mContentsChangedListener->abandon();
-    mConsumer->abandon();
-}
-
-// -----------------------------------------------------------------------
-// Interface implementation for Layer
-// -----------------------------------------------------------------------
-
-void BufferQueueLayer::onLayerDisplayed(
-        std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) {
-    sp<Fence> releaseFence = new Fence(dup(futureRenderEngineResult.get().drawFence));
-    mConsumer->setReleaseFence(releaseFence);
-
-    // Prevent tracing the same release multiple times.
-    if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
-        mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
-                                           std::make_shared<FenceTime>(releaseFence),
-                                           FrameTracer::FrameEvent::RELEASE_FENCE);
-        mPreviousReleasedFrameNumber = mPreviousFrameNumber;
-    }
-}
-
-void BufferQueueLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) {
-    BufferLayer::setTransformHint(displayTransformHint);
-    mConsumer->setTransformHint(mTransformHint);
-}
-
-void BufferQueueLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
-    if (!mConsumer->releasePendingBuffer()) {
-        return;
-    }
-
-    auto releaseFenceTime = std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
-    mReleaseTimeline.updateSignalTimes();
-    mReleaseTimeline.push(releaseFenceTime);
-
-    Mutex::Autolock lock(mFrameEventHistoryMutex);
-    if (mPreviousFrameNumber != 0) {
-        mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
-                                      std::move(releaseFenceTime));
-    }
-}
-
-void BufferQueueLayer::setDefaultBufferSize(uint32_t w, uint32_t h) {
-    mConsumer->setDefaultBufferSize(w, h);
-}
-
-int32_t BufferQueueLayer::getQueuedFrameCount() const {
-    return mQueuedFrames;
-}
-
-bool BufferQueueLayer::isBufferDue(nsecs_t expectedPresentTime) const {
-    Mutex::Autolock lock(mQueueItemLock);
-
-    const int64_t addedTime = mQueueItems[0].item.mTimestamp;
-
-    // Ignore timestamps more than a second in the future
-    const bool isPlausible = addedTime < (expectedPresentTime + s2ns(1));
-    ALOGW_IF(!isPlausible,
-             "[%s] Timestamp %" PRId64 " seems implausible "
-             "relative to expectedPresent %" PRId64,
-             getDebugName(), addedTime, expectedPresentTime);
-
-    if (!isPlausible) {
-        mFlinger->mTimeStats->incrementBadDesiredPresent(getSequence());
-    }
-
-    const bool isDue = addedTime < expectedPresentTime;
-    return isDue || !isPlausible;
-}
-
-// -----------------------------------------------------------------------
-// Interface implementation for BufferLayer
-// -----------------------------------------------------------------------
-
-bool BufferQueueLayer::fenceHasSignaled() const {
-    Mutex::Autolock lock(mQueueItemLock);
-
-    if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
-        return true;
-    }
-
-    if (!hasFrameUpdate()) {
-        return true;
-    }
-
-    if (mQueueItems[0].item.mIsDroppable) {
-        // Even though this buffer's fence may not have signaled yet, it could
-        // be replaced by another buffer before it has a chance to, which means
-        // that it's possible to get into a situation where a buffer is never
-        // able to be latched. To avoid this, grab this buffer anyway.
-        return true;
-    }
-    const bool fenceSignaled =
-            mQueueItems[0].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
-    if (!fenceSignaled) {
-        mFlinger->mTimeStats->incrementLatchSkipped(getSequence(),
-                                                    TimeStats::LatchSkipReason::LateAcquire);
-    }
-
-    return fenceSignaled;
-}
-
-bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const {
-    Mutex::Autolock lock(mQueueItemLock);
-
-    if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
-        return true;
-    }
-
-    return mQueueItems[0].item.mTimestamp <= expectedPresentTime;
-}
-
-bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
-    // We need to update the sideband stream if the layer has both a buffer and a sideband stream.
-    editCompositionState()->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get();
-
-    bool sidebandStreamChanged = true;
-    if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
-        // mSidebandStreamChanged was changed to false
-        mSidebandStream = mConsumer->getSidebandStream();
-        auto* layerCompositionState = editCompositionState();
-        layerCompositionState->sidebandStream = mSidebandStream;
-        if (layerCompositionState->sidebandStream != nullptr) {
-            setTransactionFlags(eTransactionNeeded);
-            mFlinger->setTransactionFlags(eTraversalNeeded);
-        }
-        recomputeVisibleRegions = true;
-
-        return true;
-    }
-    return false;
-}
-
-bool BufferQueueLayer::hasFrameUpdate() const {
-    return mQueuedFrames > 0;
-}
-
-status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                                          nsecs_t expectedPresentTime) {
-    // This boolean is used to make sure that SurfaceFlinger's shadow copy
-    // of the buffer queue isn't modified when the buffer queue is returning
-    // BufferItem's that weren't actually queued. This can happen in shared
-    // buffer mode.
-    bool queuedBuffer = false;
-    const int32_t layerId = getSequence();
-    LayerRejecter r(mDrawingState, getDrawingState(), recomputeVisibleRegions,
-                    getProducerStickyTransform() != 0, mName,
-                    getTransformToDisplayInverse());
-
-    if (isRemovedFromCurrentState()) {
-        expectedPresentTime = 0;
-    }
-
-    // updateTexImage() below might drop the some buffers at the head of the queue if there is a
-    // buffer behind them which is timely to be presented. However this buffer may not be signaled
-    // yet. The code below makes sure that this wouldn't happen by setting maxFrameNumber to the
-    // last buffer that was signaled.
-    uint64_t lastSignaledFrameNumber = mLastFrameNumberReceived;
-    {
-        Mutex::Autolock lock(mQueueItemLock);
-        for (size_t i = 0; i < mQueueItems.size(); i++) {
-            bool fenceSignaled =
-                    mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
-            if (!fenceSignaled) {
-                break;
-            }
-            lastSignaledFrameNumber = mQueueItems[i].item.mFrameNumber;
-        }
-    }
-    const uint64_t maxFrameNumberToAcquire =
-            std::min(mLastFrameNumberReceived.load(), lastSignaledFrameNumber);
-
-    bool autoRefresh;
-    status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &autoRefresh,
-                                                      &queuedBuffer, maxFrameNumberToAcquire);
-    mDrawingState.autoRefresh = autoRefresh;
-    if (updateResult == BufferQueue::PRESENT_LATER) {
-        // Producer doesn't want buffer to be displayed yet.  Signal a
-        // layer update so we check again at the next opportunity.
-        mFlinger->onLayerUpdate();
-        return BAD_VALUE;
-    } else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) {
-        // If the buffer has been rejected, remove it from the shadow queue
-        // and return early
-        if (queuedBuffer) {
-            Mutex::Autolock lock(mQueueItemLock);
-            if (mQueuedFrames > 0) {
-                mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
-                mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
-                if (mQueueItems[0].surfaceFrame) {
-                    addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame);
-                }
-                mQueueItems.erase(mQueueItems.begin());
-                mQueuedFrames--;
-            }
-        }
-        return BAD_VALUE;
-    } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
-        // This can occur if something goes wrong when trying to create the
-        // EGLImage for this buffer. If this happens, the buffer has already
-        // been released, so we need to clean up the queue and bug out
-        // early.
-        if (queuedBuffer) {
-            Mutex::Autolock lock(mQueueItemLock);
-            for (auto& [item, surfaceFrame] : mQueueItems) {
-                if (surfaceFrame) {
-                    addSurfaceFrameDroppedForBuffer(surfaceFrame);
-                }
-            }
-            mQueueItems.clear();
-            mQueuedFrames = 0;
-            mFlinger->mTimeStats->onDestroy(layerId);
-            mFlinger->mFrameTracer->onDestroy(layerId);
-        }
-
-        // Once we have hit this state, the shadow queue may no longer
-        // correctly reflect the incoming BufferQueue's contents, so even if
-        // updateTexImage starts working, the only safe course of action is
-        // to continue to ignore updates.
-        mUpdateTexImageFailed = true;
-
-        return BAD_VALUE;
-    }
-
-    bool more_frames_pending = false;
-    if (queuedBuffer) {
-        // Autolock scope
-        auto currentFrameNumber = mConsumer->getFrameNumber();
-
-        Mutex::Autolock lock(mQueueItemLock);
-
-        // Remove any stale buffers that have been dropped during
-        // updateTexImage
-        while (mQueuedFrames > 0 && mQueueItems[0].item.mFrameNumber != currentFrameNumber) {
-            mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
-            mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
-            if (mQueueItems[0].surfaceFrame) {
-                addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame);
-            }
-            mQueueItems.erase(mQueueItems.begin());
-            mQueuedFrames--;
-        }
-
-        uint64_t bufferID = mQueueItems[0].item.mGraphicBuffer->getId();
-        mFlinger->mTimeStats->setLatchTime(layerId, currentFrameNumber, latchTime);
-        mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, currentFrameNumber, latchTime,
-                                               FrameTracer::FrameEvent::LATCH);
-
-        if (mQueueItems[0].surfaceFrame) {
-            addSurfaceFramePresentedForBuffer(mQueueItems[0].surfaceFrame,
-                                              mQueueItems[0].item.mFenceTime->getSignalTime(),
-                                              latchTime);
-        }
-        mQueueItems.erase(mQueueItems.begin());
-        more_frames_pending = (mQueuedFrames.fetch_sub(1) > 1);
-    }
-
-    // Decrement the queued-frames count.  Signal another event if we
-    // have more frames pending.
-    if ((queuedBuffer && more_frames_pending) || mDrawingState.autoRefresh) {
-        mFlinger->onLayerUpdate();
-    }
-
-    return NO_ERROR;
-}
-
-status_t BufferQueueLayer::updateActiveBuffer() {
-    // update the active buffer
-    mPreviousBufferId = getCurrentBufferId();
-    mBufferInfo.mBuffer =
-            mConsumer->getCurrentBuffer(&mBufferInfo.mBufferSlot, &mBufferInfo.mFence);
-
-    if (mBufferInfo.mBuffer == nullptr) {
-        // this can only happen if the very first buffer was rejected.
-        return BAD_VALUE;
-    }
-    return NO_ERROR;
-}
-
-status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) {
-    mPreviousFrameNumber = mCurrentFrameNumber;
-    mCurrentFrameNumber = mConsumer->getFrameNumber();
-
-    {
-        Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
-    }
-    return NO_ERROR;
-}
-
-void BufferQueueLayer::setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) {
-    mFrameTimelineInfo = frameTimelineInfo;
-}
-
-// -----------------------------------------------------------------------
-// Interface implementation for BufferLayerConsumer::ContentsChangedListener
-// -----------------------------------------------------------------------
-
-void BufferQueueLayer::onFrameDequeued(const uint64_t bufferId) {
-    const int32_t layerId = getSequence();
-    mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
-    mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER,
-                                           systemTime(), FrameTracer::FrameEvent::DEQUEUE);
-}
-
-void BufferQueueLayer::onFrameDetached(const uint64_t bufferId) {
-    const int32_t layerId = getSequence();
-    mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
-    mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER,
-                                           systemTime(), FrameTracer::FrameEvent::DETACH);
-}
-
-void BufferQueueLayer::onFrameCancelled(const uint64_t bufferId) {
-    const int32_t layerId = getSequence();
-    mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER,
-                                           systemTime(), FrameTracer::FrameEvent::CANCEL);
-}
-
-void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
-    const int32_t layerId = getSequence();
-    const uint64_t bufferId = item.mGraphicBuffer->getId();
-    mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, item.mFrameNumber, systemTime(),
-                                           FrameTracer::FrameEvent::QUEUE);
-    mFlinger->mFrameTracer->traceFence(layerId, bufferId, item.mFrameNumber,
-                                       std::make_shared<FenceTime>(item.mFence),
-                                       FrameTracer::FrameEvent::ACQUIRE_FENCE);
-
-    ATRACE_CALL();
-    // Add this buffer from our internal queue tracker
-    { // Autolock scope
-        const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp;
-
-        using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType;
-        mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer);
-
-        Mutex::Autolock lock(mQueueItemLock);
-        // Reset the frame number tracker when we receive the first buffer after
-        // a frame number reset
-        if (item.mFrameNumber == 1) {
-            mLastFrameNumberReceived = 0;
-        }
-
-        // Ensure that callbacks are handled in order
-        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
-            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
-            if (result != NO_ERROR) {
-                ALOGE("[%s] Timed out waiting on callback", getDebugName());
-                break;
-            }
-        }
-
-        auto surfaceFrame = createSurfaceFrameForBuffer(mFrameTimelineInfo, systemTime(), mName);
-
-        mQueueItems.push_back({item, surfaceFrame});
-        mQueuedFrames++;
-
-        // Wake up any pending callbacks
-        mLastFrameNumberReceived = item.mFrameNumber;
-        mQueueItemCondition.broadcast();
-    }
-
-    mFlinger->mInterceptor->saveBufferUpdate(layerId, item.mGraphicBuffer->getWidth(),
-                                             item.mGraphicBuffer->getHeight(), item.mFrameNumber);
-
-    mFlinger->onLayerUpdate();
-    mConsumer->onBufferAvailable(item);
-}
-
-void BufferQueueLayer::onFrameReplaced(const BufferItem& item) {
-    ATRACE_CALL();
-    { // Autolock scope
-        Mutex::Autolock lock(mQueueItemLock);
-
-        // Ensure that callbacks are handled in order
-        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
-            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
-            if (result != NO_ERROR) {
-                ALOGE("[%s] Timed out waiting on callback", getDebugName());
-                break;
-            }
-        }
-
-        if (!hasFrameUpdate()) {
-            ALOGE("Can't replace a frame on an empty queue");
-            return;
-        }
-
-        auto surfaceFrame = createSurfaceFrameForBuffer(mFrameTimelineInfo, systemTime(), mName);
-        mQueueItems[mQueueItems.size() - 1].item = item;
-        mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame);
-
-        // Wake up any pending callbacks
-        mLastFrameNumberReceived = item.mFrameNumber;
-        mQueueItemCondition.broadcast();
-    }
-
-    const int32_t layerId = getSequence();
-    const uint64_t bufferId = item.mGraphicBuffer->getId();
-    mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, item.mFrameNumber, systemTime(),
-                                           FrameTracer::FrameEvent::QUEUE);
-    mFlinger->mFrameTracer->traceFence(layerId, bufferId, item.mFrameNumber,
-                                       std::make_shared<FenceTime>(item.mFence),
-                                       FrameTracer::FrameEvent::ACQUIRE_FENCE);
-    mConsumer->onBufferAvailable(item);
-}
-
-void BufferQueueLayer::onSidebandStreamChanged() {
-    bool sidebandStreamChanged = false;
-    if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, true)) {
-        // mSidebandStreamChanged was changed to true
-        mFlinger->onLayerUpdate();
-    }
-}
-
-// -----------------------------------------------------------------------
-
-void BufferQueueLayer::onFirstRef() {
-    BufferLayer::onFirstRef();
-
-    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
-    sp<IGraphicBufferProducer> producer;
-    sp<IGraphicBufferConsumer> consumer;
-    mFlinger->getFactory().createBufferQueue(&producer, &consumer, true);
-    mProducer = mFlinger->getFactory().createMonitoredProducer(producer, mFlinger, this);
-    mConsumer =
-            mFlinger->getFactory().createBufferLayerConsumer(consumer, mFlinger->getRenderEngine(),
-                                                             mTextureName, this);
-    mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
-
-    mContentsChangedListener = new ContentsChangedListener(this);
-    mConsumer->setContentsChangedListener(mContentsChangedListener);
-    mConsumer->setName(String8(mName.data(), mName.size()));
-
-    mProducer->setMaxDequeuedBufferCount(2);
-}
-
-status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) {
-    // never allow a surface larger than what our underlying GL implementation
-    // can handle.
-    if (mFlinger->exceedsMaxRenderTargetSize(w, h)) {
-        ALOGE("dimensions too large %" PRIu32 " x %" PRIu32, w, h);
-        return BAD_VALUE;
-    }
-
-    setDefaultBufferSize(w, h);
-    mConsumer->setDefaultBufferFormat(format);
-    mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
-
-    return NO_ERROR;
-}
-
-sp<IGraphicBufferProducer> BufferQueueLayer::getProducer() const {
-    return mProducer;
-}
-
-uint32_t BufferQueueLayer::getProducerStickyTransform() const {
-    int producerStickyTransform = 0;
-    int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform);
-    if (ret != OK) {
-        ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__,
-              strerror(-ret), ret);
-        return 0;
-    }
-    return static_cast<uint32_t>(producerStickyTransform);
-}
-
-void BufferQueueLayer::gatherBufferInfo() {
-    BufferLayer::gatherBufferInfo();
-
-    mBufferInfo.mDesiredPresentTime = mConsumer->getTimestamp();
-    mBufferInfo.mFenceTime = mConsumer->getCurrentFenceTime();
-    mBufferInfo.mFence = mConsumer->getCurrentFence();
-    mBufferInfo.mTransform = mConsumer->getCurrentTransform();
-    mBufferInfo.mDataspace = translateDataspace(mConsumer->getCurrentDataSpace());
-    mBufferInfo.mCrop = mConsumer->getCurrentCrop();
-    mBufferInfo.mScaleMode = mConsumer->getCurrentScalingMode();
-    mBufferInfo.mSurfaceDamage = mConsumer->getSurfaceDamage();
-    mBufferInfo.mHdrMetadata = mConsumer->getCurrentHdrMetadata();
-    mBufferInfo.mApi = mConsumer->getCurrentApi();
-    mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse();
-}
-
-sp<Layer> BufferQueueLayer::createClone() {
-    LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata());
-    args.textureName = mTextureName;
-    sp<BufferQueueLayer> layer = mFlinger->getFactory().createBufferQueueLayer(args);
-    layer->setInitialValuesForClone(this);
-
-    return layer;
-}
-
-// -----------------------------------------------------------------------
-// Interface implementation for BufferLayerConsumer::ContentsChangedListener
-// -----------------------------------------------------------------------
-
-void BufferQueueLayer::ContentsChangedListener::onFrameAvailable(const BufferItem& item) {
-    Mutex::Autolock lock(mMutex);
-    if (mBufferQueueLayer != nullptr) {
-        mBufferQueueLayer->onFrameAvailable(item);
-    }
-}
-
-void BufferQueueLayer::ContentsChangedListener::onFrameReplaced(const BufferItem& item) {
-    Mutex::Autolock lock(mMutex);
-    if (mBufferQueueLayer != nullptr) {
-        mBufferQueueLayer->onFrameReplaced(item);
-    }
-}
-
-void BufferQueueLayer::ContentsChangedListener::onSidebandStreamChanged() {
-    Mutex::Autolock lock(mMutex);
-    if (mBufferQueueLayer != nullptr) {
-        mBufferQueueLayer->onSidebandStreamChanged();
-    }
-}
-
-void BufferQueueLayer::ContentsChangedListener::onFrameDequeued(const uint64_t bufferId) {
-    Mutex::Autolock lock(mMutex);
-    if (mBufferQueueLayer != nullptr) {
-        mBufferQueueLayer->onFrameDequeued(bufferId);
-    }
-}
-
-void BufferQueueLayer::ContentsChangedListener::onFrameDetached(const uint64_t bufferId) {
-    Mutex::Autolock lock(mMutex);
-    if (mBufferQueueLayer != nullptr) {
-        mBufferQueueLayer->onFrameDetached(bufferId);
-    }
-}
-
-void BufferQueueLayer::ContentsChangedListener::onFrameCancelled(const uint64_t bufferId) {
-    Mutex::Autolock lock(mMutex);
-    if (mBufferQueueLayer != nullptr) {
-        mBufferQueueLayer->onFrameCancelled(bufferId);
-    }
-}
-
-void BufferQueueLayer::ContentsChangedListener::abandon() {
-    Mutex::Autolock lock(mMutex);
-    mBufferQueueLayer = nullptr;
-}
-
-// -----------------------------------------------------------------------
-
-} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
deleted file mode 100644
index c6e0727..0000000
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "BufferLayer.h"
-
-#include <utils/String8.h>
-
-namespace android {
-
-namespace frametimeline {
-class SurfaceFrame;
-}
-
-/*
- * A new BufferQueue and a new BufferLayerConsumer are created when the
- * BufferLayer is first referenced.
- *
- * This also implements onFrameAvailable(), which notifies SurfaceFlinger
- * that new data has arrived.
- */
-class BufferQueueLayer : public BufferLayer {
-public:
-    // Only call while mStateLock is held
-    explicit BufferQueueLayer(const LayerCreationArgs&);
-    ~BufferQueueLayer() override;
-
-    // Implements Layer.
-    const char* getType() const override { return "BufferQueueLayer"; }
-
-    void onLayerDisplayed(
-            std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
-
-    // If a buffer was replaced this frame, release the former buffer
-    void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
-
-    void setDefaultBufferSize(uint32_t w, uint32_t h) override;
-
-    int32_t getQueuedFrameCount() const override;
-
-    // Returns true if the next buffer should be presented at the expected present time
-    bool isBufferDue(nsecs_t expectedPresentTime) const override;
-
-    // Implements BufferLayer.
-    bool fenceHasSignaled() const override;
-    bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
-
-    status_t setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format);
-    sp<IGraphicBufferProducer> getProducer() const;
-
-    void setSizeForTest(uint32_t w, uint32_t h) {
-        mDrawingState.active_legacy.w = w;
-        mDrawingState.active_legacy.h = h;
-    }
-
-protected:
-    void gatherBufferInfo() override;
-
-    // -----------------------------------------------------------------------
-    // Interface implementation for BufferLayerConsumer::ContentsChangedListener
-    // -----------------------------------------------------------------------
-    class ContentsChangedListener : public BufferLayerConsumer::ContentsChangedListener {
-    public:
-        ContentsChangedListener(BufferQueueLayer* bufferQueueLayer)
-              : mBufferQueueLayer(bufferQueueLayer) {}
-        void abandon();
-
-    protected:
-        void onFrameAvailable(const BufferItem& item) override;
-        void onFrameReplaced(const BufferItem& item) override;
-        void onSidebandStreamChanged() override;
-        void onFrameDequeued(const uint64_t bufferId) override;
-        void onFrameDetached(const uint64_t bufferId) override;
-        void onFrameCancelled(const uint64_t bufferId) override;
-
-    private:
-        BufferQueueLayer* mBufferQueueLayer = nullptr;
-        Mutex mMutex;
-    };
-
-private:
-
-    bool latchSidebandStream(bool& recomputeVisibleRegions) override;
-    void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
-
-    bool hasFrameUpdate() const override;
-
-    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                            nsecs_t expectedPresentTime) override;
-
-    status_t updateActiveBuffer() override;
-    status_t updateFrameNumber(nsecs_t latchTime) override;
-    void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) override;
-
-    sp<Layer> createClone() override;
-
-    void onFirstRef() override;
-
-    void onFrameAvailable(const BufferItem& item);
-    void onFrameReplaced(const BufferItem& item);
-    void onSidebandStreamChanged();
-    void onFrameDequeued(const uint64_t bufferId);
-    void onFrameDetached(const uint64_t bufferId);
-    void onFrameCancelled(const uint64_t bufferId);
-
-    // Temporary - Used only for LEGACY camera mode.
-    uint32_t getProducerStickyTransform() const;
-
-    sp<BufferLayerConsumer> mConsumer;
-    sp<IGraphicBufferProducer> mProducer;
-
-    bool mUpdateTexImageFailed{false};
-
-    uint64_t mPreviousBufferId = 0;
-    uint64_t mPreviousReleasedFrameNumber = 0;
-
-    // Local copy of the queued contents of the incoming BufferQueue
-    mutable Mutex mQueueItemLock;
-    Condition mQueueItemCondition;
-
-    struct BufferData {
-        BufferData(BufferItem item, std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame)
-              : item(item), surfaceFrame(surfaceFrame) {}
-        BufferItem item;
-        std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame;
-    };
-    std::vector<BufferData> mQueueItems;
-    std::atomic<uint64_t> mLastFrameNumberReceived{0};
-
-    // thread-safe
-    std::atomic<int32_t> mQueuedFrames{0};
-
-    sp<ContentsChangedListener> mContentsChangedListener;
-
-    // The last vsync info received on this layer. This will be used when we get
-    // a buffer to correlate the buffer with the vsync id. Can only be accessed
-    // with the SF state lock held.
-    FrameTimelineInfo mFrameTimelineInfo;
-};
-
-} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index c5d7a60..51a5445 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -24,35 +24,122 @@
 #include <limits>
 
 #include <FrameTimeline/FrameTimeline.h>
-#include <compositionengine/LayerFECompositionState.h>
+#include <compositionengine/CompositionEngine.h>
 #include <gui/BufferQueue.h>
 #include <private/gui/SyncFeatures.h>
 #include <renderengine/Image.h>
 #include "TunnelModeEnabledReporter.h"
 
+#include <gui/TraceUtils.h>
 #include "EffectLayer.h"
 #include "FrameTracer/FrameTracer.h"
 #include "TimeStats/TimeStats.h"
 
+#define EARLY_RELEASE_ENABLED false
+
+#include <compositionengine/LayerFECompositionState.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <cutils/compiler.h>
+#include <cutils/native_handle.h>
+#include <cutils/properties.h>
+#include <gui/BufferItem.h>
+#include <gui/BufferQueue.h>
+#include <gui/GLConsumer.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/Surface.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/DebugUtils.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/NativeHandle.h>
+#include <utils/StopWatch.h>
+#include <utils/Trace.h>
+
+#include <cmath>
+#include <cstdlib>
+#include <mutex>
+#include <sstream>
+
+#include "Colorizer.h"
+#include "DisplayDevice.h"
+#include "FrameTracer/FrameTracer.h"
+#include "TimeStats/TimeStats.h"
+
 namespace android {
 
 using PresentState = frametimeline::SurfaceFrame::PresentState;
+using gui::WindowInfo;
 namespace {
-void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
-                               const sp<GraphicBuffer>& buffer, uint64_t framenumber,
-                               const sp<Fence>& releaseFence,
-                               uint32_t currentMaxAcquiredBufferCount) {
-    if (!listener) {
-        return;
+static constexpr float defaultMaxLuminance = 1000.0;
+
+constexpr mat4 inverseOrientation(uint32_t transform) {
+    const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
+    const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
+    const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
+    mat4 tr;
+
+    if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+        tr = tr * rot90;
     }
-    listener->onReleaseBuffer({buffer->getId(), framenumber},
-                              releaseFence ? releaseFence : Fence::NO_FENCE,
-                              currentMaxAcquiredBufferCount);
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+        tr = tr * flipH;
+    }
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+        tr = tr * flipV;
+    }
+    return inverse(tr);
+}
+
+bool assignTransform(ui::Transform* dst, ui::Transform& from) {
+    if (*dst == from) {
+        return false;
+    }
+    *dst = from;
+    return true;
+}
+
+TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) {
+    using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility;
+    using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness;
+    const auto frameRateCompatibility = [frameRate] {
+        switch (frameRate.type) {
+            case Layer::FrameRateCompatibility::Default:
+                return FrameRateCompatibility::Default;
+            case Layer::FrameRateCompatibility::ExactOrMultiple:
+                return FrameRateCompatibility::ExactOrMultiple;
+            default:
+                return FrameRateCompatibility::Undefined;
+        }
+    }();
+
+    const auto seamlessness = [frameRate] {
+        switch (frameRate.seamlessness) {
+            case scheduler::Seamlessness::OnlySeamless:
+                return Seamlessness::ShouldBeSeamless;
+            case scheduler::Seamlessness::SeamedAndSeamless:
+                return Seamlessness::NotRequired;
+            default:
+                return Seamlessness::Undefined;
+        }
+    }();
+
+    return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(),
+                                       .frameRateCompatibility = frameRateCompatibility,
+                                       .seamlessness = seamlessness};
 }
 } // namespace
 
 BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args)
-      : BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) {
+      : Layer(args),
+        mTextureName(args.textureName),
+        mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()},
+        mHwcSlotGenerator(sp<HwcSlotGenerator>::make()) {
+    ALOGV("Creating Layer %s", getDebugName());
+
+    mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
+    mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow;
+    mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp;
     mDrawingState.dataspace = ui::Dataspace::V0_SRGB;
 }
 
@@ -68,22 +155,45 @@
                                   mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
                                           mOwnerUid));
     }
+    if (!isClone()) {
+        // The original layer and the clone layer share the same texture. Therefore, only one of
+        // the layers, in this case the original layer, needs to handle the deletion. The original
+        // layer and the clone should be removed at the same time so there shouldn't be any issue
+        // with the clone layer trying to use the deleted texture.
+        mFlinger->deleteTextureAsync(mTextureName);
+    }
+    const int32_t layerId = getSequence();
+    mFlinger->mTimeStats->onDestroy(layerId);
+    mFlinger->mFrameTracer->onDestroy(layerId);
+}
+
+void BufferStateLayer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
+                                                 const sp<GraphicBuffer>& buffer,
+                                                 uint64_t framenumber,
+                                                 const sp<Fence>& releaseFence,
+                                                 uint32_t currentMaxAcquiredBufferCount) {
+    if (!listener) {
+        return;
+    }
+    ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber);
+    listener->onReleaseBuffer({buffer->getId(), framenumber},
+                              releaseFence ? releaseFence : Fence::NO_FENCE,
+                              currentMaxAcquiredBufferCount);
 }
 
 // -----------------------------------------------------------------------
 // Interface implementation for Layer
 // -----------------------------------------------------------------------
-void BufferStateLayer::onLayerDisplayed(
-        std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) {
+void BufferStateLayer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) {
     // If we are displayed on multiple displays in a single composition cycle then we would
     // need to do careful tracking to enable the use of the mLastClientCompositionFence.
     //  For example we can only use it if all the displays are client comp, and we need
     //  to merge all the client comp fences. We could do this, but for now we just
     // disable the optimization when a layer is composed on multiple displays.
-    if (mAlreadyDisplayedThisCompose) {
+    if (mClearClientCompositionFenceOnLayerDisplayed) {
         mLastClientCompositionFence = nullptr;
     } else {
-        mAlreadyDisplayedThisCompose = true;
+        mClearClientCompositionFenceOnLayerDisplayed = true;
     }
 
     // The previous release fence notifies the client that SurfaceFlinger is done with the previous
@@ -118,7 +228,7 @@
 
     if (ch != nullptr) {
         ch->previousReleaseCallbackId = mPreviousReleaseCallbackId;
-        ch->previousReleaseFences.emplace_back(futureRenderEngineResult);
+        ch->previousReleaseFences.emplace_back(std::move(futureFenceResult));
         ch->name = mName;
     }
 }
@@ -144,6 +254,8 @@
         handle->dequeueReadyTime = dequeueReadyTime;
         handle->currentMaxAcquiredBufferCount =
                 mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid);
+        ATRACE_FORMAT_INSTANT("releasePendingBuffer %s - %" PRIu64, getDebugName(),
+                              handle->previousReleaseCallbackId.framenumber);
     }
 
     for (auto& handle : mDrawingState.callbackHandles) {
@@ -179,23 +291,6 @@
     }
 
     mDrawingState.callbackHandles = {};
-
-    std::shared_ptr<FenceTime> releaseFenceTime = std::make_shared<FenceTime>(releaseFence);
-    {
-        Mutex::Autolock lock(mFrameEventHistoryMutex);
-        if (mPreviousFrameNumber != 0) {
-            mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
-                                          std::move(releaseFenceTime));
-        }
-    }
-}
-
-void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
-                                                 const CompositorTiming& compositorTiming) {
-    for (const auto& handle : mDrawingState.callbackHandles) {
-        handle->gpuCompositionDoneFence = glDoneFence;
-        handle->compositorTiming = compositorTiming;
-    }
 }
 
 bool BufferStateLayer::willPresentCurrentTransaction() const {
@@ -258,14 +353,6 @@
     return true;
 }
 
-static bool assignTransform(ui::Transform* dst, ui::Transform& from) {
-    if (*dst == from) {
-        return false;
-    }
-    *dst = from;
-    return true;
-}
-
 // Translate destination frame into scale and position. If a destination frame is not set, use the
 // provided scale and position
 bool BufferStateLayer::updateGeometry() {
@@ -347,19 +434,6 @@
     return true;
 }
 
-bool BufferStateLayer::addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
-                                     nsecs_t desiredPresentTime) {
-    Mutex::Autolock lock(mFrameEventHistoryMutex);
-    mAcquireTimeline.updateSignalTimes();
-    std::shared_ptr<FenceTime> acquireFenceTime =
-            std::make_shared<FenceTime>((acquireFence ? acquireFence : Fence::NO_FENCE));
-    NewFrameEventsEntry newTimestamps = {mDrawingState.frameNumber, postedTime, desiredPresentTime,
-                                         acquireFenceTime};
-    mFrameEventHistory.setProducerWantsEvents();
-    mFrameEventHistory.addQueue(newTimestamps);
-    return true;
-}
-
 bool BufferStateLayer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer,
                                  const BufferData& bufferData, nsecs_t postTime,
                                  nsecs_t desiredPresentTime, bool isAutoTimestamp,
@@ -396,7 +470,7 @@
               addSurfaceFrameDroppedForBuffer(mDrawingState.bufferSurfaceFrameTX);
               mDrawingState.bufferSurfaceFrameTX.reset();
             }
-        } else if (mLastClientCompositionFence != nullptr) {
+        } else if (EARLY_RELEASE_ENABLED && mLastClientCompositionFence != nullptr) {
             callReleaseBufferCallback(mDrawingState.releaseBufferListener,
                                       mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
                                       mLastClientCompositionFence,
@@ -446,8 +520,6 @@
     using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType;
     mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer);
 
-    addFrameEvent(mDrawingState.acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime);
-
     setFrameTimelineVsyncForBufferTransaction(info, postTime);
 
     if (dequeueTime && *dequeueTime != 0) {
@@ -592,10 +664,6 @@
 }
 
 // -----------------------------------------------------------------------
-
-// -----------------------------------------------------------------------
-// Interface implementation for BufferLayer
-// -----------------------------------------------------------------------
 bool BufferStateLayer::fenceHasSignaled() const {
     if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
         return true;
@@ -611,19 +679,11 @@
     return fenceSignaled;
 }
 
-bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const {
-    if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
-        return true;
-    }
-
-    return mDrawingState.isAutoTimestamp || mDrawingState.desiredPresentTime <= expectedPresentTime;
-}
-
 bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) {
     for (const auto& handle : mDrawingState.callbackHandles) {
         handle->refreshStartTime = refreshStartTime;
     }
-    return BufferLayer::onPreComposition(refreshStartTime);
+    return hasReadyFrame();
 }
 
 void BufferStateLayer::setAutoRefresh(bool autoRefresh) {
@@ -655,8 +715,7 @@
     return (mDrawingStateModified || mDrawingState.modified) && (c.buffer != nullptr || c.bgColorLayer != nullptr);
 }
 
-status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
-                                          nsecs_t /*expectedPresentTime*/) {
+void BufferStateLayer::updateTexImage(nsecs_t latchTime) {
     const State& s(getDrawingState());
 
     if (!s.buffer) {
@@ -665,7 +724,7 @@
                 handle->latchTime = latchTime;
             }
         }
-        return NO_ERROR;
+        return;
     }
 
     for (auto& handle : mDrawingState.callbackHandles) {
@@ -704,137 +763,36 @@
     mDrawingState.callbackHandles = remainingHandles;
 
     mDrawingStateModified = false;
-
-    return NO_ERROR;
 }
 
-status_t BufferStateLayer::updateActiveBuffer() {
-    const State& s(getDrawingState());
-
-    if (s.buffer == nullptr) {
-        return BAD_VALUE;
-    }
-
-    if (!mBufferInfo.mBuffer || !s.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) {
+void BufferStateLayer::gatherBufferInfo() {
+    if (!mBufferInfo.mBuffer || !mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) {
         decrementPendingBufferCount();
     }
 
     mPreviousReleaseCallbackId = {getCurrentBufferId(), mBufferInfo.mFrameNumber};
-    mBufferInfo.mBuffer = s.buffer;
-    mBufferInfo.mFence = s.acquireFence;
-    mBufferInfo.mFrameNumber = s.frameNumber;
-
-    return NO_ERROR;
-}
-
-status_t BufferStateLayer::updateFrameNumber(nsecs_t latchTime) {
-    // TODO(marissaw): support frame history events
-    mPreviousFrameNumber = mCurrentFrameNumber;
-    mCurrentFrameNumber = mDrawingState.frameNumber;
-    {
-        Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
-    }
-    return NO_ERROR;
-}
-
-void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) {
-    std::lock_guard lock(mMutex);
-    if (!clientCacheId.isValid()) {
-        ALOGE("invalid process, failed to erase buffer");
-        return;
-    }
-    eraseBufferLocked(clientCacheId);
-}
-
-int BufferStateLayer::HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    auto itr = mCachedBuffers.find(clientCacheId);
-    if (itr == mCachedBuffers.end()) {
-        return addCachedBuffer(clientCacheId);
-    }
-    auto& [hwcCacheSlot, counter] = itr->second;
-    counter = mCounter++;
-    return hwcCacheSlot;
-}
-
-int BufferStateLayer::HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId)
-        REQUIRES(mMutex) {
-    if (!clientCacheId.isValid()) {
-        ALOGE("invalid process, returning invalid slot");
-        return BufferQueue::INVALID_BUFFER_SLOT;
-    }
-
-    ClientCache::getInstance().registerErasedRecipient(clientCacheId, wp<ErasedRecipient>(this));
-
-    int hwcCacheSlot = getFreeHwcCacheSlot();
-    mCachedBuffers[clientCacheId] = {hwcCacheSlot, mCounter++};
-    return hwcCacheSlot;
-}
-
-int BufferStateLayer::HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) {
-    if (mFreeHwcCacheSlots.empty()) {
-        evictLeastRecentlyUsed();
-    }
-
-    int hwcCacheSlot = mFreeHwcCacheSlots.top();
-    mFreeHwcCacheSlots.pop();
-    return hwcCacheSlot;
-}
-
-void BufferStateLayer::HwcSlotGenerator::evictLeastRecentlyUsed() REQUIRES(mMutex) {
-    uint64_t minCounter = UINT_MAX;
-    client_cache_t minClientCacheId = {};
-    for (const auto& [clientCacheId, slotCounter] : mCachedBuffers) {
-        const auto& [hwcCacheSlot, counter] = slotCounter;
-        if (counter < minCounter) {
-            minCounter = counter;
-            minClientCacheId = clientCacheId;
-        }
-    }
-    eraseBufferLocked(minClientCacheId);
-
-    ClientCache::getInstance().unregisterErasedRecipient(minClientCacheId, this);
-}
-
-void BufferStateLayer::HwcSlotGenerator::eraseBufferLocked(const client_cache_t& clientCacheId)
-        REQUIRES(mMutex) {
-    auto itr = mCachedBuffers.find(clientCacheId);
-    if (itr == mCachedBuffers.end()) {
-        return;
-    }
-    auto& [hwcCacheSlot, counter] = itr->second;
-
-    // TODO send to hwc cache and resources
-
-    mFreeHwcCacheSlots.push(hwcCacheSlot);
-    mCachedBuffers.erase(clientCacheId);
-}
-
-void BufferStateLayer::gatherBufferInfo() {
-    BufferLayer::gatherBufferInfo();
-
-    const State& s(getDrawingState());
-    mBufferInfo.mDesiredPresentTime = s.desiredPresentTime;
-    mBufferInfo.mFenceTime = std::make_shared<FenceTime>(s.acquireFence);
-    mBufferInfo.mFence = s.acquireFence;
-    mBufferInfo.mTransform = s.bufferTransform;
+    mBufferInfo.mBuffer = mDrawingState.buffer;
+    mBufferInfo.mFence = mDrawingState.acquireFence;
+    mBufferInfo.mFrameNumber = mDrawingState.frameNumber;
+    mBufferInfo.mPixelFormat =
+            !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat();
+    mBufferInfo.mFrameLatencyNeeded = true;
+    mBufferInfo.mDesiredPresentTime = mDrawingState.desiredPresentTime;
+    mBufferInfo.mFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence);
+    mBufferInfo.mFence = mDrawingState.acquireFence;
+    mBufferInfo.mTransform = mDrawingState.bufferTransform;
     auto lastDataspace = mBufferInfo.mDataspace;
-    mBufferInfo.mDataspace = translateDataspace(s.dataspace);
+    mBufferInfo.mDataspace = translateDataspace(mDrawingState.dataspace);
     if (lastDataspace != mBufferInfo.mDataspace) {
         mFlinger->mSomeDataspaceChanged = true;
     }
-    mBufferInfo.mCrop = computeBufferCrop(s);
+    mBufferInfo.mCrop = computeBufferCrop(mDrawingState);
     mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
-    mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion;
-    mBufferInfo.mHdrMetadata = s.hdrMetadata;
-    mBufferInfo.mApi = s.api;
-    mBufferInfo.mTransformToDisplayInverse = s.transformToDisplayInverse;
-    mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId);
-}
-
-uint32_t BufferStateLayer::getEffectiveScalingMode() const {
-   return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
+    mBufferInfo.mSurfaceDamage = mDrawingState.surfaceDamageRegion;
+    mBufferInfo.mHdrMetadata = mDrawingState.hdrMetadata;
+    mBufferInfo.mApi = mDrawingState.api;
+    mBufferInfo.mTransformToDisplayInverse = mDrawingState.transformToDisplayInverse;
+    mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(mDrawingState.clientCacheId);
 }
 
 Rect BufferStateLayer::computeBufferCrop(const State& s) {
@@ -854,7 +812,7 @@
     args.textureName = mTextureName;
     sp<BufferStateLayer> layer = mFlinger->getFactory().createBufferStateLayer(args);
     layer->mHwcSlotGenerator = mHwcSlotGenerator;
-    layer->setInitialValuesForClone(this);
+    layer->setInitialValuesForClone(sp<Layer>::fromExisting(this));
     return layer;
 }
 
@@ -880,7 +838,15 @@
     }
 
     const Rect layerSize{getBounds()};
-    return layerSize.width() != bufferWidth || layerSize.height() != bufferHeight;
+    int32_t layerWidth = layerSize.getWidth();
+    int32_t layerHeight = layerSize.getHeight();
+
+    // Align the layer orientation with the buffer before comparism
+    if (mTransformHint & ui::Transform::ROT_90) {
+        std::swap(layerWidth, layerHeight);
+    }
+
+    return layerWidth != bufferWidth || layerHeight != bufferHeight;
 }
 
 void BufferStateLayer::decrementPendingBufferCount() {
@@ -1109,4 +1075,553 @@
     return true;
 }
 
+void BufferStateLayer::useSurfaceDamage() {
+    if (mFlinger->mForceFullDamage) {
+        surfaceDamageRegion = Region::INVALID_REGION;
+    } else {
+        surfaceDamageRegion = mBufferInfo.mSurfaceDamage;
+    }
+}
+
+void BufferStateLayer::useEmptyDamage() {
+    surfaceDamageRegion.clear();
+}
+
+bool BufferStateLayer::isOpaque(const Layer::State& s) const {
+    // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
+    // layer's opaque flag.
+    if ((mSidebandStream == nullptr) && (mBufferInfo.mBuffer == nullptr)) {
+        return false;
+    }
+
+    // if the layer has the opaque flag, then we're always opaque,
+    // otherwise we use the current buffer's format.
+    return ((s.flags & layer_state_t::eLayerOpaque) != 0) || getOpacityForFormat(getPixelFormat());
+}
+
+bool BufferStateLayer::canReceiveInput() const {
+    return !isHiddenByPolicy() && (mBufferInfo.mBuffer == nullptr || getAlpha() > 0.0f);
+}
+
+bool BufferStateLayer::isVisible() const {
+    return !isHiddenByPolicy() && getAlpha() > 0.0f &&
+            (mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr);
+}
+
+std::optional<compositionengine::LayerFE::LayerSettings> BufferStateLayer::prepareClientComposition(
+        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+    ATRACE_CALL();
+
+    std::optional<compositionengine::LayerFE::LayerSettings> result =
+            Layer::prepareClientComposition(targetSettings);
+    if (!result) {
+        return result;
+    }
+
+    if (CC_UNLIKELY(mBufferInfo.mBuffer == 0) && mSidebandStream != nullptr) {
+        // For surfaceview of tv sideband, there is no activeBuffer
+        // in bufferqueue, we need return LayerSettings.
+        return result;
+    }
+    const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
+            ((isSecure() || isProtected()) && !targetSettings.isSecure);
+    const bool bufferCanBeUsedAsHwTexture =
+            mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE;
+    compositionengine::LayerFE::LayerSettings& layer = *result;
+    if (blackOutLayer || !bufferCanBeUsedAsHwTexture) {
+        ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable",
+                 mName.c_str());
+        prepareClearClientComposition(layer, true /* blackout */);
+        return layer;
+    }
+
+    const State& s(getDrawingState());
+    layer.source.buffer.buffer = mBufferInfo.mBuffer;
+    layer.source.buffer.isOpaque = isOpaque(s);
+    layer.source.buffer.fence = mBufferInfo.mFence;
+    layer.source.buffer.textureName = mTextureName;
+    layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
+    layer.source.buffer.isY410BT2020 = isHdrY410();
+    bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086;
+    bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3;
+    float maxLuminance = 0.f;
+    if (hasSmpte2086 && hasCta861_3) {
+        maxLuminance = std::min(mBufferInfo.mHdrMetadata.smpte2086.maxLuminance,
+                                mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel);
+    } else if (hasSmpte2086) {
+        maxLuminance = mBufferInfo.mHdrMetadata.smpte2086.maxLuminance;
+    } else if (hasCta861_3) {
+        maxLuminance = mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel;
+    } else {
+        switch (layer.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) {
+            case HAL_DATASPACE_TRANSFER_ST2084:
+            case HAL_DATASPACE_TRANSFER_HLG:
+                // Behavior-match previous releases for HDR content
+                maxLuminance = defaultMaxLuminance;
+                break;
+        }
+    }
+    layer.source.buffer.maxLuminanceNits = maxLuminance;
+    layer.frameNumber = mCurrentFrameNumber;
+    layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
+
+    const bool useFiltering =
+            targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering();
+
+    // Query the texture matrix given our current filtering mode.
+    float textureMatrix[16];
+    getDrawingTransformMatrix(useFiltering, textureMatrix);
+
+    if (getTransformToDisplayInverse()) {
+        /*
+         * the code below applies the primary display's inverse transform to
+         * the texture transform
+         */
+        uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
+        mat4 tr = inverseOrientation(transform);
+
+        /**
+         * TODO(b/36727915): This is basically a hack.
+         *
+         * Ensure that regardless of the parent transformation,
+         * this buffer is always transformed from native display
+         * orientation to display orientation. For example, in the case
+         * of a camera where the buffer remains in native orientation,
+         * we want the pixels to always be upright.
+         */
+        sp<Layer> p = mDrawingParent.promote();
+        if (p != nullptr) {
+            const auto parentTransform = p->getTransform();
+            tr = tr * inverseOrientation(parentTransform.getOrientation());
+        }
+
+        // and finally apply it to the original texture matrix
+        const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
+        memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
+    }
+
+    const Rect win{getBounds()};
+    float bufferWidth = getBufferSize(s).getWidth();
+    float bufferHeight = getBufferSize(s).getHeight();
+
+    // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has
+    // been set and there is no parent layer bounds. In that case, the scale is meaningless so
+    // ignore them.
+    if (!getBufferSize(s).isValid()) {
+        bufferWidth = float(win.right) - float(win.left);
+        bufferHeight = float(win.bottom) - float(win.top);
+    }
+
+    const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
+    const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
+    const float translateY = float(win.top) / bufferHeight;
+    const float translateX = float(win.left) / bufferWidth;
+
+    // Flip y-coordinates because GLConsumer expects OpenGL convention.
+    mat4 tr = mat4::translate(vec4(.5f, .5f, 0.f, 1.f)) * mat4::scale(vec4(1.f, -1.f, 1.f, 1.f)) *
+            mat4::translate(vec4(-.5f, -.5f, 0.f, 1.f)) *
+            mat4::translate(vec4(translateX, translateY, 0.f, 1.f)) *
+            mat4::scale(vec4(scaleWidth, scaleHeight, 1.0f, 1.0f));
+
+    layer.source.buffer.useTextureFiltering = useFiltering;
+    layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr;
+
+    return layer;
+}
+
+bool BufferStateLayer::isHdrY410() const {
+    // pixel format is HDR Y410 masquerading as RGBA_1010102
+    return (mBufferInfo.mDataspace == ui::Dataspace::BT2020_ITU_PQ &&
+            mBufferInfo.mApi == NATIVE_WINDOW_API_MEDIA &&
+            mBufferInfo.mPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102);
+}
+
+sp<compositionengine::LayerFE> BufferStateLayer::getCompositionEngineLayerFE() const {
+    return asLayerFE();
+}
+
+compositionengine::LayerFECompositionState* BufferStateLayer::editCompositionState() {
+    return mCompositionState.get();
+}
+
+const compositionengine::LayerFECompositionState* BufferStateLayer::getCompositionState() const {
+    return mCompositionState.get();
+}
+
+void BufferStateLayer::preparePerFrameCompositionState() {
+    Layer::preparePerFrameCompositionState();
+
+    // Sideband layers
+    auto* compositionState = editCompositionState();
+    if (compositionState->sidebandStream.get() && !compositionState->sidebandStreamHasFrame) {
+        compositionState->compositionType =
+                aidl::android::hardware::graphics::composer3::Composition::SIDEBAND;
+        return;
+    } else if ((mDrawingState.flags & layer_state_t::eLayerIsDisplayDecoration) != 0) {
+        compositionState->compositionType =
+                aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
+    } else {
+        // Normal buffer layers
+        compositionState->hdrMetadata = mBufferInfo.mHdrMetadata;
+        compositionState->compositionType = mPotentialCursor
+                ? aidl::android::hardware::graphics::composer3::Composition::CURSOR
+                : aidl::android::hardware::graphics::composer3::Composition::DEVICE;
+    }
+
+    compositionState->buffer = getBuffer();
+    compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT)
+            ? 0
+            : mBufferInfo.mBufferSlot;
+    compositionState->acquireFence = mBufferInfo.mFence;
+    compositionState->frameNumber = mBufferInfo.mFrameNumber;
+    compositionState->sidebandStreamHasFrame = false;
+}
+
+void BufferStateLayer::onPostComposition(const DisplayDevice* display,
+                                         const std::shared_ptr<FenceTime>& glDoneFence,
+                                         const std::shared_ptr<FenceTime>& presentFence,
+                                         const CompositorTiming& compositorTiming) {
+    // mFrameLatencyNeeded is true when a new frame was latched for the
+    // composition.
+    if (!mBufferInfo.mFrameLatencyNeeded) return;
+
+    for (const auto& handle : mDrawingState.callbackHandles) {
+        handle->gpuCompositionDoneFence = glDoneFence;
+        handle->compositorTiming = compositorTiming;
+    }
+
+    // Update mFrameTracker.
+    nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime;
+    mFrameTracker.setDesiredPresentTime(desiredPresentTime);
+
+    const int32_t layerId = getSequence();
+    mFlinger->mTimeStats->setDesiredTime(layerId, mCurrentFrameNumber, desiredPresentTime);
+
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    if (outputLayer && outputLayer->requiresClientComposition()) {
+        nsecs_t clientCompositionTimestamp = outputLayer->getState().clientCompositionTimestamp;
+        mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber,
+                                               clientCompositionTimestamp,
+                                               FrameTracer::FrameEvent::FALLBACK_COMPOSITION);
+        // Update the SurfaceFrames in the drawing state
+        if (mDrawingState.bufferSurfaceFrameTX) {
+            mDrawingState.bufferSurfaceFrameTX->setGpuComposition();
+        }
+        for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) {
+            surfaceFrame->setGpuComposition();
+        }
+    }
+
+    std::shared_ptr<FenceTime> frameReadyFence = mBufferInfo.mFenceTime;
+    if (frameReadyFence->isValid()) {
+        mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
+    } else {
+        // There was no fence for this frame, so assume that it was ready
+        // to be presented at the desired present time.
+        mFrameTracker.setFrameReadyTime(desiredPresentTime);
+    }
+
+    if (display) {
+        const Fps refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
+        const std::optional<Fps> renderRate =
+                mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
+
+        const auto vote = frameRateToSetFrameRateVotePayload(mDrawingState.frameRate);
+        const auto gameMode = getGameMode();
+
+        if (presentFence->isValid()) {
+            mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence,
+                                                  refreshRate, renderRate, vote, gameMode);
+            mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber,
+                                               presentFence,
+                                               FrameTracer::FrameEvent::PRESENT_FENCE);
+            mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
+        } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId());
+                   displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
+            // The HWC doesn't support present fences, so use the refresh
+            // timestamp instead.
+            const nsecs_t actualPresentTime = display->getRefreshTimestamp();
+            mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime,
+                                                 refreshRate, renderRate, vote, gameMode);
+            mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(),
+                                                   mCurrentFrameNumber, actualPresentTime,
+                                                   FrameTracer::FrameEvent::PRESENT_FENCE);
+            mFrameTracker.setActualPresentTime(actualPresentTime);
+        }
+    }
+
+    mFrameTracker.advanceFrame();
+    mBufferInfo.mFrameLatencyNeeded = false;
+}
+
+bool BufferStateLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+    ATRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(),
+                          getDrawingState().frameNumber);
+
+    bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
+
+    if (refreshRequired) {
+        return refreshRequired;
+    }
+
+    // If the head buffer's acquire fence hasn't signaled yet, return and
+    // try again later
+    if (!fenceHasSignaled()) {
+        ATRACE_NAME("!fenceHasSignaled()");
+        mFlinger->onLayerUpdate();
+        return false;
+    }
+
+    updateTexImage(latchTime);
+    if (mDrawingState.buffer == nullptr) {
+        return false;
+    }
+
+    // Capture the old state of the layer for comparisons later
+    BufferInfo oldBufferInfo = mBufferInfo;
+    const bool oldOpacity = isOpaque(mDrawingState);
+    mPreviousFrameNumber = mCurrentFrameNumber;
+    mCurrentFrameNumber = mDrawingState.frameNumber;
+    gatherBufferInfo();
+
+    if (oldBufferInfo.mBuffer == nullptr) {
+        // the first time we receive a buffer, we need to trigger a
+        // geometry invalidation.
+        recomputeVisibleRegions = true;
+    }
+
+    if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) ||
+        (mBufferInfo.mTransform != oldBufferInfo.mTransform) ||
+        (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) ||
+        (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) {
+        recomputeVisibleRegions = true;
+    }
+
+    if (oldBufferInfo.mBuffer != nullptr) {
+        uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
+        uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
+        if (bufWidth != oldBufferInfo.mBuffer->getWidth() ||
+            bufHeight != oldBufferInfo.mBuffer->getHeight()) {
+            recomputeVisibleRegions = true;
+        }
+    }
+
+    if (oldOpacity != isOpaque(mDrawingState)) {
+        recomputeVisibleRegions = true;
+    }
+
+    return true;
+}
+
+bool BufferStateLayer::hasReadyFrame() const {
+    return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh();
+}
+
+bool BufferStateLayer::isProtected() const {
+    return (mBufferInfo.mBuffer != nullptr) &&
+            (mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+}
+
+// As documented in libhardware header, formats in the range
+// 0x100 - 0x1FF are specific to the HAL implementation, and
+// are known to have no alpha channel
+// TODO: move definition for device-specific range into
+// hardware.h, instead of using hard-coded values here.
+#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
+
+bool BufferStateLayer::getOpacityForFormat(PixelFormat format) {
+    if (HARDWARE_IS_DEVICE_FORMAT(format)) {
+        return true;
+    }
+    switch (format) {
+        case PIXEL_FORMAT_RGBA_8888:
+        case PIXEL_FORMAT_BGRA_8888:
+        case PIXEL_FORMAT_RGBA_FP16:
+        case PIXEL_FORMAT_RGBA_1010102:
+        case PIXEL_FORMAT_R_8:
+            return false;
+    }
+    // in all other case, we have no blending (also for unknown formats)
+    return true;
+}
+
+bool BufferStateLayer::needsFiltering(const DisplayDevice* display) const {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    if (outputLayer == nullptr) {
+        return false;
+    }
+
+    // We need filtering if the sourceCrop rectangle size does not match the
+    // displayframe rectangle size (not a 1:1 render)
+    const auto& compositionState = outputLayer->getState();
+    const auto displayFrame = compositionState.displayFrame;
+    const auto sourceCrop = compositionState.sourceCrop;
+    return sourceCrop.getHeight() != displayFrame.getHeight() ||
+            sourceCrop.getWidth() != displayFrame.getWidth();
+}
+
+bool BufferStateLayer::needsFilteringForScreenshots(
+        const DisplayDevice* display, const ui::Transform& inverseParentTransform) const {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    if (outputLayer == nullptr) {
+        return false;
+    }
+
+    // We need filtering if the sourceCrop rectangle size does not match the
+    // viewport rectangle size (not a 1:1 render)
+    const auto& compositionState = outputLayer->getState();
+    const ui::Transform& displayTransform = display->getTransform();
+    const ui::Transform inverseTransform = inverseParentTransform * displayTransform.inverse();
+    // Undo the transformation of the displayFrame so that we're back into
+    // layer-stack space.
+    const Rect frame = inverseTransform.transform(compositionState.displayFrame);
+    const FloatRect sourceCrop = compositionState.sourceCrop;
+
+    int32_t frameHeight = frame.getHeight();
+    int32_t frameWidth = frame.getWidth();
+    // If the display transform had a rotational component then undo the
+    // rotation so that the orientation matches the source crop.
+    if (displayTransform.getOrientation() & ui::Transform::ROT_90) {
+        std::swap(frameHeight, frameWidth);
+    }
+    return sourceCrop.getHeight() != frameHeight || sourceCrop.getWidth() != frameWidth;
+}
+
+void BufferStateLayer::latchAndReleaseBuffer() {
+    if (hasReadyFrame()) {
+        bool ignored = false;
+        latchBuffer(ignored, systemTime());
+    }
+    releasePendingBuffer(systemTime());
+}
+
+PixelFormat BufferStateLayer::getPixelFormat() const {
+    return mBufferInfo.mPixelFormat;
+}
+
+bool BufferStateLayer::getTransformToDisplayInverse() const {
+    return mBufferInfo.mTransformToDisplayInverse;
+}
+
+Rect BufferStateLayer::getBufferCrop() const {
+    // this is the crop rectangle that applies to the buffer
+    // itself (as opposed to the window)
+    if (!mBufferInfo.mCrop.isEmpty()) {
+        // if the buffer crop is defined, we use that
+        return mBufferInfo.mCrop;
+    } else if (mBufferInfo.mBuffer != nullptr) {
+        // otherwise we use the whole buffer
+        return mBufferInfo.mBuffer->getBounds();
+    } else {
+        // if we don't have a buffer yet, we use an empty/invalid crop
+        return Rect();
+    }
+}
+
+uint32_t BufferStateLayer::getBufferTransform() const {
+    return mBufferInfo.mTransform;
+}
+
+ui::Dataspace BufferStateLayer::getDataSpace() const {
+    return mBufferInfo.mDataspace;
+}
+
+ui::Dataspace BufferStateLayer::translateDataspace(ui::Dataspace dataspace) {
+    ui::Dataspace updatedDataspace = dataspace;
+    // translate legacy dataspaces to modern dataspaces
+    switch (dataspace) {
+        case ui::Dataspace::SRGB:
+            updatedDataspace = ui::Dataspace::V0_SRGB;
+            break;
+        case ui::Dataspace::SRGB_LINEAR:
+            updatedDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+            break;
+        case ui::Dataspace::JFIF:
+            updatedDataspace = ui::Dataspace::V0_JFIF;
+            break;
+        case ui::Dataspace::BT601_625:
+            updatedDataspace = ui::Dataspace::V0_BT601_625;
+            break;
+        case ui::Dataspace::BT601_525:
+            updatedDataspace = ui::Dataspace::V0_BT601_525;
+            break;
+        case ui::Dataspace::BT709:
+            updatedDataspace = ui::Dataspace::V0_BT709;
+            break;
+        default:
+            break;
+    }
+
+    return updatedDataspace;
+}
+
+sp<GraphicBuffer> BufferStateLayer::getBuffer() const {
+    return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr;
+}
+
+void BufferStateLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) {
+    sp<GraphicBuffer> buffer = getBuffer();
+    if (!buffer) {
+        ALOGE("Buffer should not be null!");
+        return;
+    }
+    GLConsumer::computeTransformMatrix(outMatrix, buffer->getWidth(), buffer->getHeight(),
+                                       buffer->getPixelFormat(), mBufferInfo.mCrop,
+                                       mBufferInfo.mTransform, filteringEnabled);
+}
+
+void BufferStateLayer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {
+    Layer::setInitialValuesForClone(clonedFrom);
+
+    sp<BufferStateLayer> bufferClonedFrom =
+            sp<BufferStateLayer>::fromExisting(static_cast<BufferStateLayer*>(clonedFrom.get()));
+    mPremultipliedAlpha = bufferClonedFrom->mPremultipliedAlpha;
+    mPotentialCursor = bufferClonedFrom->mPotentialCursor;
+    mProtectedByApp = bufferClonedFrom->mProtectedByApp;
+
+    updateCloneBufferInfo();
+}
+
+void BufferStateLayer::updateCloneBufferInfo() {
+    if (!isClone() || !isClonedFromAlive()) {
+        return;
+    }
+
+    sp<BufferStateLayer> clonedFrom = sp<BufferStateLayer>::fromExisting(
+            static_cast<BufferStateLayer*>(getClonedFrom().get()));
+    mBufferInfo = clonedFrom->mBufferInfo;
+    mSidebandStream = clonedFrom->mSidebandStream;
+    surfaceDamageRegion = clonedFrom->surfaceDamageRegion;
+    mCurrentFrameNumber = clonedFrom->mCurrentFrameNumber.load();
+    mPreviousFrameNumber = clonedFrom->mPreviousFrameNumber;
+
+    // After buffer info is updated, the drawingState from the real layer needs to be copied into
+    // the cloned. This is because some properties of drawingState can change when latchBuffer is
+    // called. However, copying the drawingState would also overwrite the cloned layer's relatives
+    // and touchableRegionCrop. Therefore, temporarily store the relatives so they can be set in
+    // the cloned drawingState again.
+    wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf;
+    SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives;
+    wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop;
+    WindowInfo tmpInputInfo = mDrawingState.inputInfo;
+
+    cloneDrawingState(clonedFrom.get());
+
+    mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop;
+    mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf;
+    mDrawingState.zOrderRelatives = tmpZOrderRelatives;
+    mDrawingState.inputInfo = tmpInputInfo;
+}
+
+void BufferStateLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) {
+    mTransformHint = getFixedTransformHint();
+    if (mTransformHint == ui::Transform::ROT_INVALID) {
+        mTransformHint = displayTransformHint;
+    }
+}
+
+const std::shared_ptr<renderengine::ExternalTexture>& BufferStateLayer::getExternalTexture() const {
+    return mBufferInfo.mBuffer;
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 8a696f1..8bad3d2 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -16,39 +16,106 @@
 
 #pragma once
 
-#include "BufferLayer.h"
-#include "Layer.h"
-
-#include <renderengine/Image.h>
-#include <renderengine/RenderEngine.h>
-#include <system/window.h>
-#include <utils/String8.h>
-
+#include <sys/types.h>
+#include <cstdint>
+#include <list>
 #include <stack>
 
+#include <android/gui/ISurfaceComposerClient.h>
+#include <gui/LayerState.h>
+#include <renderengine/Image.h>
+#include <renderengine/Mesh.h>
+#include <renderengine/RenderEngine.h>
+#include <renderengine/Texture.h>
+#include <system/window.h> // For NATIVE_WINDOW_SCALING_MODE_FREEZE
+#include <ui/FrameStats.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
+#include <ui/Region.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
+
+#include "Client.h"
+#include "DisplayHardware/HWComposer.h"
+#include "FrameTimeline.h"
+#include "FrameTracker.h"
+#include "HwcSlotGenerator.h"
+#include "Layer.h"
+#include "LayerVector.h"
+#include "SurfaceFlinger.h"
+
 namespace android {
 
 class SlotGenerationTest;
 
-class BufferStateLayer : public BufferLayer {
+class BufferStateLayer : public Layer {
 public:
     explicit BufferStateLayer(const LayerCreationArgs&);
 
     ~BufferStateLayer() override;
 
     // Implements Layer.
+    sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override;
+    compositionengine::LayerFECompositionState* editCompositionState() override;
+
+    // If we have received a new buffer this frame, we will pass its surface
+    // damage down to hardware composer. Otherwise, we must send a region with
+    // one empty rect.
+    void useSurfaceDamage() override;
+    void useEmptyDamage() override;
+
+    bool isOpaque(const Layer::State& s) const override;
+    bool canReceiveInput() const override;
+
+    // isVisible - true if this layer is visible, false otherwise
+    bool isVisible() const override;
+
+    // isProtected - true if the layer may contain protected content in the
+    // GRALLOC_USAGE_PROTECTED sense.
+    bool isProtected() const override;
+
+    bool usesSourceCrop() const override { return true; }
+
+    bool isHdrY410() const override;
+
+    void onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& glDoneFence,
+                           const std::shared_ptr<FenceTime>& presentFence,
+                           const CompositorTiming&) override;
+
+    // latchBuffer - called each time the screen is redrawn and returns whether
+    // the visible regions need to be recomputed (this is a fairly heavy
+    // operation, so this should be set only if needed). Typically this is used
+    // to figure out if the content or size of a surface has changed.
+    bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+    bool hasReadyFrame() const override;
+
+    // Calls latchBuffer if the buffer has a frame queued and then releases the buffer.
+    // This is used if the buffer is just latched and releases to free up the buffer
+    // and will not be shown on screen.
+    // Should only be called on the main thread.
+    void latchAndReleaseBuffer() override;
+
+    bool getTransformToDisplayInverse() const override;
+
+    Rect getBufferCrop() const override;
+
+    uint32_t getBufferTransform() const override;
+
+    ui::Dataspace getDataSpace() const override;
+
+    sp<GraphicBuffer> getBuffer() const override;
+    const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const override;
+
+    ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; }
+
+    // Implements Layer.
     const char* getType() const override { return "BufferStateLayer"; }
 
-    void onLayerDisplayed(
-            std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
+    void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override;
 
     void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
 
-    void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
-                                   const CompositorTiming& compositorTiming) override;
-
-    bool isBufferDue(nsecs_t /*expectedPresentTime*/) const override { return true; }
-
     Region getActiveTransparentRegion(const Layer::State& s) const override {
         return s.transparentRegionHint;
     }
@@ -67,8 +134,6 @@
     bool setApi(int32_t api) override;
     bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
     bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
-    bool addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
-                       nsecs_t requestedPresentTime) override;
     bool setPosition(float /*x*/, float /*y*/) override;
     bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/);
 
@@ -76,6 +141,8 @@
     bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; }
     bool setTransparentRegionHint(const Region& transparent) override;
 
+    // BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame
+    // and its parent layer is not bounded
     Rect getBufferSize(const State& s) const override;
     FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
     void setAutoRefresh(bool autoRefresh) override;
@@ -84,48 +151,106 @@
     bool setDestinationFrame(const Rect& destinationFrame) override;
     bool updateGeometry() override;
 
-    // -----------------------------------------------------------------------
-
-    // -----------------------------------------------------------------------
-    // Interface implementation for BufferLayer
-    // -----------------------------------------------------------------------
-    bool fenceHasSignaled() const override;
-    bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
-    bool onPreComposition(nsecs_t refreshStartTime) override;
-    uint32_t getEffectiveScalingMode() const override;
+    bool fenceHasSignaled() const;
+    bool onPreComposition(nsecs_t) override;
 
     // See mPendingBufferTransactions
     void decrementPendingBufferCount();
     std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; }
     std::string getPendingBufferCounterName() override { return mBlastTransactionName; }
 
-    bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const override { return true; }
-
 protected:
-    void gatherBufferInfo() override;
+    void gatherBufferInfo();
     void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame);
     ui::Transform getInputTransform() const override;
     Rect getInputBounds() const override;
 
+    struct BufferInfo {
+        nsecs_t mDesiredPresentTime;
+        std::shared_ptr<FenceTime> mFenceTime;
+        sp<Fence> mFence;
+        uint32_t mTransform{0};
+        ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN};
+        Rect mCrop;
+        uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
+        Region mSurfaceDamage;
+        HdrMetadata mHdrMetadata;
+        int mApi;
+        PixelFormat mPixelFormat{PIXEL_FORMAT_NONE};
+        bool mTransformToDisplayInverse{false};
+
+        std::shared_ptr<renderengine::ExternalTexture> mBuffer;
+        uint64_t mFrameNumber;
+        int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT};
+
+        bool mFrameLatencyNeeded{false};
+    };
+
+    BufferInfo mBufferInfo;
+
+    std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
+            compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
+
+    /*
+     * compositionengine::LayerFE overrides
+     */
+    const compositionengine::LayerFECompositionState* getCompositionState() const override;
+    void preparePerFrameCompositionState() override;
+
+    static bool getOpacityForFormat(PixelFormat format);
+
+    // from graphics API
+    const uint32_t mTextureName;
+    ui::Dataspace translateDataspace(ui::Dataspace dataspace);
+    void setInitialValuesForClone(const sp<Layer>& clonedFrom);
+    void updateCloneBufferInfo() override;
+    uint64_t mPreviousFrameNumber = 0;
+
+    void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
+
+    // Transform hint provided to the producer. This must be accessed holding
+    // the mStateLock.
+    ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
+
+    bool getAutoRefresh() const { return mDrawingState.autoRefresh; }
+    bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
+
+    std::atomic<bool> mSidebandStreamChanged{false};
+
 private:
     friend class SlotGenerationTest;
     friend class TransactionFrameTracerTest;
     friend class TransactionSurfaceFrameTest;
 
+    // We generate InputWindowHandles for all non-cursor buffered layers regardless of whether they
+    // have an InputChannel. This is to enable the InputDispatcher to do PID based occlusion
+    // detection.
+    bool needsInputInfo() const override { return !mPotentialCursor; }
+
+    // Returns true if this layer requires filtering
+    bool needsFiltering(const DisplayDevice*) const override;
+    bool needsFilteringForScreenshots(const DisplayDevice*,
+                                      const ui::Transform& inverseParentTransform) const override;
+
+    PixelFormat getPixelFormat() const;
+
+    // Computes the transform matrix using the setFilteringEnabled to determine whether the
+    // transform matrix should be computed for use with bilinear filtering.
+    void getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]);
+
+    std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
+
     inline void tracePendingBufferCount(int32_t pendingBuffers);
 
     bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
                                  nsecs_t requestedPresentTime);
 
-    bool latchSidebandStream(bool& recomputeVisibleRegions) override;
+    // Latch sideband stream and returns true if the dirty region should be updated.
+    bool latchSidebandStream(bool& recomputeVisibleRegions);
 
-    bool hasFrameUpdate() const override;
+    bool hasFrameUpdate() const;
 
-    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                            nsecs_t expectedPresentTime) override;
-
-    status_t updateActiveBuffer() override;
-    status_t updateFrameNumber(nsecs_t latchTime) override;
+    void updateTexImage(nsecs_t latchTime);
 
     sp<Layer> createClone() override;
 
@@ -134,10 +259,17 @@
 
     bool willPresentCurrentTransaction() const;
 
-    bool bufferNeedsFiltering() const override;
+    // Returns true if the transformed buffer size does not match the layer size and we need
+    // to apply filtering.
+    bool bufferNeedsFiltering() const;
 
     bool simpleBufferUpdate(const layer_state_t& s) const override;
 
+    void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
+                                   const sp<GraphicBuffer>& buffer, uint64_t framenumber,
+                                   const sp<Fence>& releaseFence,
+                                   uint32_t currentMaxAcquiredBufferCount);
+
     ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID;
     uint64_t mPreviousReleasedFrameNumber = 0;
 
@@ -169,45 +301,6 @@
     // not specify a destination frame.
     ui::Transform mRequestedTransform;
 
-    // TODO(marissaw): support sticky transform for LEGACY camera mode
-
-    class HwcSlotGenerator : public ClientCache::ErasedRecipient {
-    public:
-        HwcSlotGenerator() {
-            for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
-                mFreeHwcCacheSlots.push(i);
-            }
-        }
-
-        void bufferErased(const client_cache_t& clientCacheId);
-
-        int getHwcCacheSlot(const client_cache_t& clientCacheId);
-
-    private:
-        friend class SlotGenerationTest;
-        int addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex);
-        int getFreeHwcCacheSlot() REQUIRES(mMutex);
-        void evictLeastRecentlyUsed() REQUIRES(mMutex);
-        void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex);
-
-        struct CachedBufferHash {
-            std::size_t operator()(const client_cache_t& clientCacheId) const {
-                return std::hash<uint64_t>{}(clientCacheId.id);
-            }
-        };
-
-        std::mutex mMutex;
-
-        std::unordered_map<client_cache_t, std::pair<int /*HwcCacheSlot*/, uint64_t /*counter*/>,
-                           CachedBufferHash>
-                mCachedBuffers GUARDED_BY(mMutex);
-        std::stack<int /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex);
-
-        // The cache increments this counter value when a slot is updated or used.
-        // Used to track the least recently-used buffer
-        uint64_t mCounter = 0;
-    };
-
     sp<HwcSlotGenerator> mHwcSlotGenerator;
 };
 
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index b27055d..3685bb4 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -83,8 +83,8 @@
     sp<IBinder> handle;
     int32_t layerId;
     uint32_t transformHint;
-    LayerCreationArgs args(mFlinger.get(), this, name.c_str(), static_cast<uint32_t>(flags),
-                           std::move(metadata));
+    LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), name.c_str(),
+                           static_cast<uint32_t>(flags), std::move(metadata));
     const status_t status =
             mFlinger->createLayer(args, &handle, parent, &layerId, nullptr, &transformHint);
     if (status == NO_ERROR) {
@@ -137,7 +137,8 @@
                                      gui::MirrorSurfaceResult* outResult) {
     sp<IBinder> handle;
     int32_t layerId;
-    LayerCreationArgs args(mFlinger.get(), this, "MirrorRoot", 0 /* flags */, gui::LayerMetadata());
+    LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), "MirrorRoot",
+                           0 /* flags */, gui::LayerMetadata());
     status_t status = mFlinger->mirrorLayer(args, mirrorFromHandle, &handle, &layerId);
     if (status == NO_ERROR) {
         outResult->handle = handle;
@@ -146,5 +147,20 @@
     return binderStatusFromStatusT(status);
 }
 
+binder::Status Client::mirrorDisplay(int64_t displayId, gui::MirrorSurfaceResult* outResult) {
+    sp<IBinder> handle;
+    int32_t layerId;
+    LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this),
+                           "MirrorRoot-" + std::to_string(displayId), 0 /* flags */,
+                           gui::LayerMetadata());
+    std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId));
+    status_t status = mFlinger->mirrorDisplay(*id, args, &handle, &layerId);
+    if (status == NO_ERROR) {
+        outResult->handle = handle;
+        outResult->layerId = layerId;
+    }
+    return binderStatusFromStatusT(status);
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 4720d5c..4e59dfd 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -59,6 +59,8 @@
     binder::Status mirrorSurface(const sp<IBinder>& mirrorFromHandle,
                                  gui::MirrorSurfaceResult* outResult) override;
 
+    binder::Status mirrorDisplay(int64_t displayId, gui::MirrorSurfaceResult* outResult) override;
+
     // constant
     sp<SurfaceFlinger> mFlinger;
 
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
index 3c7b9d9..cf932a8 100644
--- a/services/surfaceflinger/ClientCache.cpp
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -30,7 +30,7 @@
 
 ANDROID_SINGLETON_STATIC_INSTANCE(ClientCache);
 
-ClientCache::ClientCache() : mDeathRecipient(new CacheDeathRecipient) {}
+ClientCache::ClientCache() : mDeathRecipient(sp<CacheDeathRecipient>::make()) {}
 
 bool ClientCache::getBuffer(const client_cache_t& cacheId,
                             ClientCacheBuffer** outClientCacheBuffer) {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
index f201751..f861fc9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -32,6 +32,11 @@
 using Layers = std::vector<sp<compositionengine::LayerFE>>;
 using Outputs = std::vector<std::shared_ptr<compositionengine::Output>>;
 
+struct BorderRenderInfo {
+    float width = 0;
+    half4 color;
+    std::vector<int32_t> layerIds;
+};
 /**
  * A parameter object for refreshing a set of outputs
  */
@@ -90,6 +95,8 @@
 
     // If set, a frame has been scheduled for that time.
     std::optional<std::chrono::steady_clock::time_point> scheduledFrameTime;
+
+    std::vector<BorderRenderInfo> borderInfoList;
 };
 
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h
new file mode 100644
index 0000000..0ce263b
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/expected.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+// TODO(b/232535621): Pull this file to <ui/FenceResult.h> so that RenderEngine::drawLayers returns
+// FenceResult rather than RenderEngineResult.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#include <renderengine/RenderEngine.h>
+#pragma clang diagnostic pop
+
+namespace android {
+
+class Fence;
+
+using FenceResult = base::expected<sp<Fence>, status_t>;
+
+// TODO(b/232535621): Prevent base::unexpected(NO_ERROR) from being a valid FenceResult.
+inline status_t fenceStatus(const FenceResult& fenceResult) {
+    return fenceResult.ok() ? NO_ERROR : fenceResult.error();
+}
+
+inline FenceResult toFenceResult(renderengine::RenderEngineResult&& result) {
+    if (auto [status, fence] = std::move(result); fence.ok()) {
+        return sp<Fence>::make(std::move(fence));
+    } else {
+        return base::unexpected(status);
+    }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index e77e155..ec610c1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -16,22 +16,23 @@
 
 #pragma once
 
-#include <future>
 #include <optional>
 #include <ostream>
 #include <unordered_set>
 
+#include <compositionengine/FenceResult.h>
+
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wconversion"
 #pragma clang diagnostic ignored "-Wextra"
 
 #include <renderengine/LayerSettings.h>
-#include <renderengine/RenderEngine.h>
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
 
+#include <ftl/future.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 
@@ -156,7 +157,7 @@
             ClientCompositionTargetSettings&) = 0;
 
     // Called after the layer is displayed to update the presentation fence
-    virtual void onLayerDisplayed(std::shared_future<renderengine::RenderEngineResult>) = 0;
+    virtual void onLayerDisplayed(ftl::SharedFuture<FenceResult>) = 0;
 
     // Gets some kind of identifier for the layer for debug purposes.
     virtual const char* getDebugName() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 5846e67..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>
@@ -267,6 +268,9 @@
     // Enables predicting composition strategy to run client composition earlier
     virtual void setPredictCompositionStrategy(bool) = 0;
 
+    // Enables overriding the 170M trasnfer function as sRGB
+    virtual void setTreat170mAsSrgb(bool) = 0;
+
 protected:
     virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
     virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
@@ -308,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/ProjectionSpace.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
index a63145a..49013e0 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
@@ -120,16 +120,16 @@
 
 } // namespace compositionengine
 
-inline std::string to_string(const android::compositionengine::ProjectionSpace& space) {
-    return android::base::
-            StringPrintf("ProjectionSpace(bounds = %s, content = %s, orientation = %s)",
-                         to_string(space.getBoundsAsRect()).c_str(),
-                         to_string(space.getContent()).c_str(), toCString(space.getOrientation()));
+inline std::string to_string(const compositionengine::ProjectionSpace& space) {
+    return base::StringPrintf("ProjectionSpace{bounds=%s, content=%s, orientation=%s}",
+                              to_string(space.getBoundsAsRect()).c_str(),
+                              to_string(space.getContent()).c_str(),
+                              toCString(space.getOrientation()));
 }
 
 // Defining PrintTo helps with Google Tests.
-inline void PrintTo(const android::compositionengine::ProjectionSpace& space, ::std::ostream* os) {
+inline void PrintTo(const compositionengine::ProjectionSpace& space, std::ostream* os) {
     *os << to_string(space);
 }
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index 9ee779c..5854674 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -91,16 +91,9 @@
     // Called after the HWC calls are made to present the display
     virtual void onPresentDisplayCompleted() = 0;
 
-    // Called after the surface has been rendering to signal the surface should
-    // be made ready for displaying
-    virtual void flip() = 0;
-
     // Debugging - Dumps the state of the RenderSurface to a string
     virtual void dump(std::string& result) const = 0;
 
-    // Debugging - gets the page flip count for the RenderSurface
-    virtual std::uint32_t getPageFlipCount() const = 0;
-
     // Returns true if the render surface supports client composition prediction.
     virtual bool supportsCompositionStrategyPrediction() const = 0;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 61a0e6a..fa7bc5d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -89,6 +89,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 0feb9f7..fc8dd8b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -108,6 +108,7 @@
     void cacheClientCompositionRequests(uint32_t) override;
     bool canPredictCompositionStrategy(const CompositionRefreshArgs&) override;
     void setPredictCompositionStrategy(bool) override;
+    void setTreat170mAsSrgb(bool) override;
 
     // Testing
     const ReleasedLayers& getReleasedLayersForTest() const;
@@ -139,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.
@@ -151,6 +154,7 @@
 
 private:
     void dirtyEntireOutput();
+    void updateCompositionStateForBorder(const compositionengine::CompositionRefreshArgs&);
     compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const;
     void finishPrepareFrame();
     ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 5fa0d67..c291652 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -33,6 +33,7 @@
 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
 
 #include <compositionengine/ProjectionSpace.h>
+#include <renderengine/BorderRenderInfo.h>
 #include <ui/LayerStack.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -155,11 +156,20 @@
         SUCCESS = 1,
         // Composition strategy prediction failed for this frame.
         FAIL = 2,
+
+        ftl_last = FAIL
     };
 
     CompositionStrategyPredictionState strategyPrediction =
             CompositionStrategyPredictionState::DISABLED;
 
+    bool treat170mAsSrgb = false;
+
+    std::vector<renderengine::BorderRenderInfo> borderInfoList;
+
+    uint64_t lastOutputLayerHash = 0;
+    uint64_t outputLayerHash = 0;
+
     // Debugging
     void dump(std::string& result) const;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index d64d676..ecd432f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -60,7 +60,7 @@
     std::vector<LayerFE::LayerSettings> getOverrideCompositionList() const override;
 
     void dump(std::string&) const override;
-    virtual FloatRect calculateOutputSourceCrop() const;
+    virtual FloatRect calculateOutputSourceCrop(uint32_t internalDisplayRotationFlags) const;
     virtual Rect calculateOutputDisplayFrame() const;
     virtual uint32_t calculateOutputRelativeBufferTransform(
             uint32_t internalDisplayRotationFlags) const;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index e4cb113..1c14a43 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -62,15 +62,12 @@
             base::unique_fd* bufferFence) override;
     void queueBuffer(base::unique_fd readyFence) override;
     void onPresentDisplayCompleted() override;
-    void flip() override;
     bool supportsCompositionStrategyPrediction() const override;
 
     // Debugging
     void dump(std::string& result) const override;
-    std::uint32_t getPageFlipCount() const override;
 
     // Testing
-    void setPageFlipCountForTest(std::uint32_t);
     void setSizeForTest(const ui::Size&);
     std::shared_ptr<renderengine::ExternalTexture>& mutableTextureForTest();
     base::unique_fd& mutableBufferReadyForTest();
@@ -89,7 +86,6 @@
     ui::Size mSize;
     const size_t mMaxTextureCacheSize;
     bool mProtected{false};
-    std::uint32_t mPageFlipCount{0};
 };
 
 std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 2e7a377..2bfd3cf 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -147,9 +147,9 @@
 
     bool hasProtectedLayers() const;
 
-private:
-    CachedSet() = default;
+    bool hasSolidColorLayers() const;
 
+private:
     const NonBufferHash mFingerprint;
     std::chrono::steady_clock::time_point mLastUpdate = std::chrono::steady_clock::now();
     std::vector<Layer> mLayers;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index 29d3366..5aec7c2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -248,6 +248,12 @@
     bool isProtected() const {
         return getOutputLayer()->getLayerFE().getCompositionState()->hasProtectedContent;
     }
+
+    bool hasSolidColorCompositionType() const {
+        return getOutputLayer()->getLayerFE().getCompositionState()->compositionType ==
+                aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR;
+    }
+
     float getFps() const { return getOutputLayer()->getLayerFE().getCompositionState()->fps; }
 
     void dump(std::string& result) const;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index ee0c53d..1c5c10f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -49,7 +49,7 @@
                  std::vector<compositionengine::LayerFE::LayerSettings>(
                          compositionengine::LayerFE::ClientCompositionTargetSettings&));
 
-    MOCK_METHOD1(onLayerDisplayed, void(std::shared_future<renderengine::RenderEngineResult>));
+    MOCK_METHOD(void, onLayerDisplayed, (ftl::SharedFuture<FenceResult>), (override));
 
     MOCK_CONST_METHOD0(getDebugName, const char*());
     MOCK_CONST_METHOD0(getSequence, int32_t());
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index fa86076..2a04949 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -132,6 +132,9 @@
     MOCK_METHOD1(cacheClientCompositionRequests, void(uint32_t));
     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/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index e12aebb..af8d4bc 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -42,9 +42,7 @@
     MOCK_METHOD1(dequeueBuffer, std::shared_ptr<renderengine::ExternalTexture>(base::unique_fd*));
     MOCK_METHOD1(queueBuffer, void(base::unique_fd));
     MOCK_METHOD0(onPresentDisplayCompleted, void());
-    MOCK_METHOD0(flip, void());
     MOCK_CONST_METHOD1(dump, void(std::string& result));
-    MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t());
     MOCK_CONST_METHOD0(supportsCompositionStrategyPrediction, bool());
 };
 
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index f545886..09adaed 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -131,15 +131,11 @@
 }
 
 void Display::dump(std::string& out) const {
-    using android::base::StringAppendF;
+    const char* const type = isVirtual() ? "virtual" : "physical";
+    base::StringAppendF(&out, "Display %s (%s, \"%s\")", to_string(mId).c_str(), type,
+                        getName().c_str());
 
-    StringAppendF(&out, "   Composition Display State: [\"%s\"]", getName().c_str());
-
-    out.append("\n   ");
-    dumpVal(out, "isVirtual", isVirtual());
-    dumpVal(out, "DisplayId", to_string(mId));
-    out.append("\n");
-
+    out.append("\n   Composition Display State:\n");
     Output::dumpBase(out);
 }
 
@@ -200,7 +196,7 @@
                             });
 
         if (hasQueuedFrames) {
-            releasedLayers.emplace_back(layerFE);
+            releasedLayers.emplace_back(wp<LayerFE>::fromExisting(layerFE));
         }
     }
 
@@ -247,11 +243,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);
@@ -261,6 +260,11 @@
         return false;
     }
 
+    if (isPowerHintSessionEnabled()) {
+        mPowerAdvisor->setHwcValidateTiming(mId, startTime, systemTime());
+        mPowerAdvisor->setRequiresClientComposition(mId, requiresClientComposition);
+    }
+
     return true;
 }
 
@@ -360,9 +364,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
@@ -388,6 +407,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:
@@ -400,6 +427,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/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
index 01c368d..290c710 100644
--- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
@@ -89,7 +89,6 @@
 
 void dumpVal(std::string& out, const char* name, const ui::Transform& transform) {
     transform.dump(out, name);
-    out.append(" ");
 }
 
 void dumpVal(std::string& out, const char* name, const mat4& tr) {
@@ -99,7 +98,7 @@
                   "[%0.3f,%0.3f,%0.3f,%0.3f]"
                   "[%0.3f,%0.3f,%0.3f,%0.3f]"
                   "[%0.3f,%0.3f,%0.3f,%0.3f]"
-                  "[%0.3f,%0.3f,%0.3f,%0.3f]]",
+                  "[%0.3f,%0.3f,%0.3f,%0.3f]] ",
                   name,
                   tr[0][0], tr[1][0], tr[2][0], tr[3][0],
                   tr[0][1], tr[1][1], tr[2][1], tr[3][1],
@@ -109,9 +108,9 @@
 }
 
 void dumpVal(std::string& out, const char* name, const StretchEffect& effect) {
-    StringAppendF(&out, "%s={ width =%f, height = %f, vec=(%f, %f), max=(%f, %f) } ", name,
-                  effect.width, effect.height,
-                  effect.vectorX, effect.vectorY, effect.maxAmountX, effect.maxAmountY);
+    StringAppendF(&out, "%s={width=%f, height=%f, vec=(%f, %f), max=(%f, %f)} ", name, effect.width,
+                  effect.height, effect.vectorX, effect.vectorY, effect.maxAmountX,
+                  effect.maxAmountY);
 }
 
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 004e071..8ebc5b1 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -294,17 +294,15 @@
 }
 
 void Output::dump(std::string& out) const {
-    using android::base::StringAppendF;
-
-    StringAppendF(&out, "   Composition Output State: [\"%s\"]", mName.c_str());
-
-    out.append("\n   ");
+    base::StringAppendF(&out, "Output \"%s\"", mName.c_str());
+    out.append("\n   Composition Output State:\n");
 
     dumpBase(out);
 }
 
 void Output::dumpBase(std::string& out) const {
     dumpState(out);
+    out += '\n';
 
     if (mDisplayColorProfile) {
         mDisplayColorProfile->dump(out);
@@ -312,13 +310,15 @@
         out.append("    No display color profile!\n");
     }
 
+    out += '\n';
+
     if (mRenderSurface) {
         mRenderSurface->dump(out);
     } else {
         out.append("    No render surface!\n");
     }
 
-    android::base::StringAppendF(&out, "\n   %zu Layers\n", getOutputLayerCount());
+    base::StringAppendF(&out, "\n   %zu Layers\n", getOutputLayerCount());
     for (const auto* outputLayer : getOutputLayersOrderedByZ()) {
         if (!outputLayer) {
             continue;
@@ -329,7 +329,7 @@
 
 void Output::dumpPlannerInfo(const Vector<String16>& args, std::string& out) const {
     if (!mPlanner) {
-        base::StringAppendF(&out, "Planner is disabled\n");
+        out.append("Planner is disabled\n");
         return;
     }
     base::StringAppendF(&out, "Planner info for display [%s]\n", mName.c_str());
@@ -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.
@@ -733,6 +754,44 @@
             forceClientComposition = false;
         }
     }
+
+    updateCompositionStateForBorder(refreshArgs);
+}
+
+void Output::updateCompositionStateForBorder(
+        const compositionengine::CompositionRefreshArgs& refreshArgs) {
+    std::unordered_map<int32_t, const Region*> layerVisibleRegionMap;
+    // Store a map of layerId to their computed visible region.
+    for (auto* layer : getOutputLayersOrderedByZ()) {
+        int layerId = (layer->getLayerFE()).getSequence();
+        layerVisibleRegionMap[layerId] = &((layer->getState()).visibleRegion);
+    }
+    OutputCompositionState& outputCompositionState = editState();
+    outputCompositionState.borderInfoList.clear();
+    bool clientComposeTopLayer = false;
+    for (const auto& borderInfo : refreshArgs.borderInfoList) {
+        renderengine::BorderRenderInfo info;
+        for (const auto& id : borderInfo.layerIds) {
+            info.combinedRegion.orSelf(*(layerVisibleRegionMap[id]));
+        }
+
+        if (!info.combinedRegion.isEmpty()) {
+            info.width = borderInfo.width;
+            info.color = borderInfo.color;
+            outputCompositionState.borderInfoList.emplace_back(std::move(info));
+            clientComposeTopLayer = true;
+        }
+    }
+
+    // In this situation we must client compose the top layer instead of using hwc
+    // because we want to draw the border above all else.
+    // This could potentially cause a bit of a performance regression if the top
+    // layer would have been rendered using hwc originally.
+    // TODO(b/227656283): Measure system's performance before enabling the border feature
+    if (clientComposeTopLayer) {
+        auto topLayer = getOutputLayerOrderedByZByIndex(getOutputLayerCount() - 1);
+        (topLayer->editState()).forceClientComposition = true;
+    }
 }
 
 void Output::planComposition() {
@@ -763,6 +822,7 @@
     bool includeGeometry = refreshArgs.updatingGeometryThisFrame;
     uint32_t z = 0;
     bool overrideZ = false;
+    uint64_t outputLayerHash = 0;
     for (auto* layer : getOutputLayersOrderedByZ()) {
         if (layer == peekThroughLayer) {
             // No longer needed, although it should not show up again, so
@@ -789,6 +849,10 @@
                     constexpr bool isPeekingThrough = true;
                     peekThroughLayer->writeStateToHWC(includeGeometry, false, z++, overrideZ,
                                                       isPeekingThrough);
+                    outputLayerHash ^= android::hashCombine(
+                            reinterpret_cast<uint64_t>(&peekThroughLayer->getLayerFE()),
+                            z, includeGeometry, overrideZ, isPeekingThrough,
+                            peekThroughLayer->requiresClientComposition());
                 }
 
                 previousOverride = overrideInfo.buffer->getBuffer();
@@ -797,7 +861,14 @@
 
         constexpr bool isPeekingThrough = false;
         layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough);
+        if (!skipLayer) {
+            outputLayerHash ^= android::hashCombine(
+                    reinterpret_cast<uint64_t>(&layer->getLayerFE()),
+                    z, includeGeometry, overrideZ, isPeekingThrough,
+                    layer->requiresClientComposition());
+        }
     }
+    editState().outputLayerHash = outputLayerHash;
 }
 
 compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const {
@@ -1087,6 +1158,11 @@
         return;
     }
 
+    if (isPowerHintSessionEnabled()) {
+        // get fence end time to know when gpu is complete in display
+        setHintSessionGpuFence(
+                std::make_unique<FenceTime>(sp<Fence>::make(dup(optReadyFence->get()))));
+    }
     // swap buffers (presentation)
     mRenderSurface->queueBuffer(std::move(*optReadyFence));
 }
@@ -1183,6 +1259,13 @@
 
     // Compute the global color transform matrix.
     clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
+    for (auto& info : outputState.borderInfoList) {
+        renderengine::BorderRenderInfo borderInfo;
+        borderInfo.width = info.width;
+        borderInfo.color = info.color;
+        borderInfo.combinedRegion = info.combinedRegion;
+        clientCompositionDisplay.borderInfoList.emplace_back(std::move(borderInfo));
+    }
     clientCompositionDisplay.deviceHandlesColorTransform =
             outputState.usesDeviceComposition || getSkipColorTransform();
 
@@ -1206,7 +1289,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,
@@ -1245,34 +1329,31 @@
     // probably to encapsulate the output buffer into a structure that dispatches resource cleanup
     // over to RenderEngine, in which case this flag can be removed from the drawLayers interface.
     const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay;
-    auto [status, drawFence] =
-            renderEngine
-                    .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, tex,
-                                useFramebufferCache, std::move(fd))
-                    .get();
 
-    if (status != NO_ERROR && mClientCompositionRequestCache) {
+    auto fenceResult =
+            toFenceResult(renderEngine
+                                  .drawLayers(clientCompositionDisplay, clientRenderEngineLayers,
+                                              tex, useFramebufferCache, std::move(fd))
+                                  .get());
+
+    if (mClientCompositionRequestCache && fenceStatus(fenceResult) != NO_ERROR) {
         // If rendering was not successful, remove the request from the cache.
         mClientCompositionRequestCache->remove(tex->getBuffer()->getId());
     }
 
-    auto& timeStats = getCompositionEngine().getTimeStats();
-    if (drawFence.get() < 0) {
-        timeStats.recordRenderEngineDuration(renderEngineStart, systemTime());
+    const auto fence = std::move(fenceResult).value_or(Fence::NO_FENCE);
+
+    if (auto& timeStats = getCompositionEngine().getTimeStats(); fence->isValid()) {
+        timeStats.recordRenderEngineDuration(renderEngineStart, std::make_shared<FenceTime>(fence));
     } else {
-        timeStats.recordRenderEngineDuration(renderEngineStart,
-                                             std::make_shared<FenceTime>(
-                                                     new Fence(dup(drawFence.get()))));
+        timeStats.recordRenderEngineDuration(renderEngineStart, systemTime());
     }
 
-    if (clientCompositionLayersFE.size() > 0) {
-        sp<Fence> clientCompFence = new Fence(dup(drawFence.get()));
-        for (auto clientComposedLayer : clientCompositionLayersFE) {
-            clientComposedLayer->setWasClientComposed(clientCompFence);
-        }
+    for (auto* clientComposedLayer : clientCompositionLayersFE) {
+        clientComposedLayer->setWasClientComposed(fence);
     }
 
-    return std::move(drawFence);
+    return base::unique_fd(fence->dup());
 }
 
 std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests(
@@ -1291,6 +1372,7 @@
         const auto& layerState = layer->getState();
         const auto* layerFEState = layer->getLayerFE().getCompositionState();
         auto& layerFE = layer->getLayerFE();
+        layerFE.setWasClientComposed(nullptr);
 
         const Region clip(viewportRegion.intersect(layerState.visibleRegion));
         ALOGV("Layer: %s", layerFE.getDebugName());
@@ -1356,7 +1438,10 @@
                 }
             }
 
-            outLayerFEs.push_back(&layerFE);
+            if (clientComposition) {
+                outLayerFEs.push_back(&layerFE);
+            }
+
             clientCompositionLayers.insert(clientCompositionLayers.end(),
                                            std::make_move_iterator(results.begin()),
                                            std::make_move_iterator(results.end()));
@@ -1390,6 +1475,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__);
@@ -1400,7 +1493,6 @@
 
     auto& outputState = editState();
     outputState.dirtyRegion.clear();
-    mRenderSurface->flip();
 
     auto frame = presentAndGetFrameFences();
 
@@ -1429,19 +1521,15 @@
                     Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
         }
         layer->getLayerFE().onLayerDisplayed(
-                ftl::yield<renderengine::RenderEngineResult>(
-                        {NO_ERROR, base::unique_fd(releaseFence->dup())})
-                        .share());
+                ftl::yield<FenceResult>(std::move(releaseFence)).share());
     }
 
     // We've got a list of layers needing fences, that are disjoint with
     // OutputLayersOrderedByZ.  The best we can do is to
     // supply them with the present fence.
     for (auto& weakLayer : mReleasedLayers) {
-        if (auto layer = weakLayer.promote(); layer != nullptr) {
-            layer->onLayerDisplayed(ftl::yield<renderengine::RenderEngineResult>(
-                                            {NO_ERROR, base::unique_fd(frame.presentFence->dup())})
-                                            .share());
+        if (const auto layer = weakLayer.promote()) {
+            layer->onLayerDisplayed(ftl::yield<FenceResult>(frame.presentFence).share());
         }
     }
 
@@ -1488,7 +1576,15 @@
     }
 }
 
+void Output::setTreat170mAsSrgb(bool enable) {
+    editState().treat170mAsSrgb = enable;
+}
+
 bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) {
+    uint64_t lastOutputLayerHash = getState().lastOutputLayerHash;
+    uint64_t outputLayerHash = getState().outputLayerHash;
+    editState().lastOutputLayerHash = outputLayerHash;
+
     if (!getState().isEnabled || !mHwComposerAsyncWorker) {
         ALOGV("canPredictCompositionStrategy disabled");
         return false;
@@ -1509,6 +1605,11 @@
         return false;
     }
 
+    if (lastOutputLayerHash != outputLayerHash) {
+        ALOGV("canPredictCompositionStrategy output layers changed");
+        return false;
+    }
+
     // If no layer uses clientComposition, then don't predict composition strategy
     // because we have less work to do in parallel.
     if (!anyLayersRequireClientComposition()) {
@@ -1516,12 +1617,7 @@
         return false;
     }
 
-    if (!refreshArgs.updatingOutputGeometryThisFrame) {
-        return true;
-    }
-
-    ALOGV("canPredictCompositionStrategy updatingOutputGeometryThisFrame");
-    return false;
+    return true;
 }
 
 bool Output::anyLayersRequireClientComposition() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 7188281..c512a1e 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -14,40 +14,30 @@
  * limitations under the License.
  */
 
+#include <ftl/enum.h>
+
 #include <compositionengine/impl/DumpHelpers.h>
 #include <compositionengine/impl/OutputCompositionState.h>
 
 namespace android::compositionengine::impl {
-using CompositionStrategyPredictionState =
-        OutputCompositionState::CompositionStrategyPredictionState;
-
-std::string toString(CompositionStrategyPredictionState state) {
-    switch (state) {
-        case CompositionStrategyPredictionState::DISABLED:
-            return "Disabled";
-        case CompositionStrategyPredictionState::SUCCESS:
-            return "Success";
-        case CompositionStrategyPredictionState::FAIL:
-            return "Fail";
-    }
-}
 
 void OutputCompositionState::dump(std::string& out) const {
     out.append("   ");
     dumpVal(out, "isEnabled", isEnabled);
     dumpVal(out, "isSecure", isSecure);
-
-    dumpVal(out, "usesClientComposition", usesClientComposition);
     dumpVal(out, "usesDeviceComposition", usesDeviceComposition);
+
+    out.append("\n   ");
+    dumpVal(out, "usesClientComposition", usesClientComposition);
     dumpVal(out, "flipClientTarget", flipClientTarget);
     dumpVal(out, "reusedClientComposition", reusedClientComposition);
-    dumpVal(out, "layerFilter", layerFilter);
 
     out.append("\n   ");
-
+    dumpVal(out, "layerFilter", layerFilter);
+    out.append("\n   ");
     dumpVal(out, "transform", transform);
 
-    out.append("\n   ");
+    out.append("   "); // ui::Transform::dump appends EOL.
     dumpVal(out, "layerStackSpace", to_string(layerStackSpace));
     out.append("\n   ");
     dumpVal(out, "framebufferSpace", to_string(framebufferSpace));
@@ -59,18 +49,30 @@
     dumpVal(out, "needsFiltering", needsFiltering);
 
     out.append("\n   ");
-
     dumpVal(out, "colorMode", toString(colorMode), colorMode);
     dumpVal(out, "renderIntent", toString(renderIntent), renderIntent);
     dumpVal(out, "dataspace", toString(dataspace), dataspace);
+    dumpVal(out, "targetDataspace", toString(targetDataspace), targetDataspace);
+
+    out.append("\n   ");
     dumpVal(out, "colorTransformMatrix", colorTransformMatrix);
-    dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace);
+
+    out.append("\n   ");
     dumpVal(out, "displayBrightnessNits", displayBrightnessNits);
     dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits);
     dumpVal(out, "clientTargetBrightness", clientTargetBrightness);
     dumpVal(out, "displayBrightness", displayBrightness);
-    dumpVal(out, "compositionStrategyPredictionState", toString(strategyPrediction));
+    out.append("\n   ");
+    dumpVal(out, "compositionStrategyPredictionState", ftl::enum_string(strategyPrediction));
+    out.append("\n   ");
 
+    out.append("\n   ");
+    dumpVal(out, "treate170mAsSrgb", treat170mAsSrgb);
+
+    out.append("\n");
+    for (const auto& borderRenderInfo : borderInfoList) {
+        dumpVal(out, "borderRegion", borderRenderInfo.combinedRegion);
+    }
     out.append("\n");
 }
 
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 3289d55..1bb9d0eb 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -106,9 +106,8 @@
     return activeCrop;
 }
 
-FloatRect OutputLayer::calculateOutputSourceCrop() const {
+FloatRect OutputLayer::calculateOutputSourceCrop(uint32_t internalDisplayRotationFlags) const {
     const auto& layerState = *getLayerFE().getCompositionState();
-    const auto& outputState = getOutput().getState();
 
     if (!layerState.geomUsesSourceCrop) {
         return {};
@@ -140,8 +139,7 @@
          * the code below applies the primary display's inverse transform to the
          * buffer
          */
-        uint32_t invTransformOrient =
-                ui::Transform::toRotationFlags(outputState.displaySpace.getOrientation());
+        uint32_t invTransformOrient = internalDisplayRotationFlags;
         // calculate the inverse transform
         if (invTransformOrient & HAL_TRANSFORM_ROT_90) {
             invTransformOrient ^= HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H;
@@ -304,7 +302,7 @@
         state.forceClientComposition = false;
 
         state.displayFrame = calculateOutputDisplayFrame();
-        state.sourceCrop = calculateOutputSourceCrop();
+        state.sourceCrop = calculateOutputSourceCrop(internalDisplayRotationFlags);
         state.bufferTransform = static_cast<Hwc2::Transform>(
                 calculateOutputRelativeBufferTransform(internalDisplayRotationFlags));
 
@@ -322,6 +320,17 @@
             ? outputState.targetDataspace
             : layerFEState->dataspace;
 
+    // Override the dataspace transfer from 170M to sRGB if the device configuration requests this.
+    // We do this here instead of in buffer info so that dumpsys can still report layers that are
+    // using the 170M transfer. Also we only do this if the colorspace is not agnostic for the
+    // layer, in case the color profile uses a 170M transfer function.
+    if (outputState.treat170mAsSrgb && !layerFEState->isColorspaceAgnostic &&
+        (state.dataspace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_SMPTE_170M) {
+        state.dataspace = static_cast<ui::Dataspace>(
+                (state.dataspace & HAL_DATASPACE_STANDARD_MASK) |
+                (state.dataspace & HAL_DATASPACE_RANGE_MASK) | HAL_DATASPACE_TRANSFER_SRGB);
+    }
+
     // For hdr content, treat the white point as the display brightness - HDR content should not be
     // boosted or dimmed.
     // If the layer explicitly requests to disable dimming, then don't dim either.
@@ -368,6 +377,7 @@
     auto requestedCompositionType = outputIndependentState->compositionType;
 
     if (requestedCompositionType == Composition::SOLID_COLOR && state.overrideInfo.buffer) {
+        // this should never happen, as SOLID_COLOR is skipped from caching, b/230073351
         requestedCompositionType = Composition::DEVICE;
     }
 
@@ -407,7 +417,12 @@
 
     if (outputDependentState.overrideInfo.buffer != nullptr) {
         displayFrame = outputDependentState.overrideInfo.displayFrame;
-        sourceCrop = displayFrame.toFloatRect();
+        sourceCrop =
+                FloatRect(0.f, 0.f,
+                          static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
+                                                     ->getWidth()),
+                          static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
+                                                     ->getHeight()));
     }
 
     ALOGV("Writing display frame [%d, %d, %d, %d]", displayFrame.left, displayFrame.top,
@@ -781,7 +796,7 @@
     // framebuffer space of the override buffer to layer space.
     const ProjectionSpace& layerSpace = getOutput().getState().layerStackSpace;
     const ui::Transform transform = getState().overrideInfo.displaySpace.getTransform(layerSpace);
-    const Rect boundaries = transform.transform(getState().overrideInfo.displaySpace.getContent());
+    const Rect boundaries = transform.transform(getState().overrideInfo.displayFrame);
 
     LayerFE::LayerSettings settings;
     settings.geometry = renderengine::Geometry{
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 5a3af7b..0fe55db 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -251,10 +251,6 @@
     mDisplaySurface->onFrameCommitted();
 }
 
-void RenderSurface::flip() {
-    mPageFlipCount++;
-}
-
 void RenderSurface::dump(std::string& out) const {
     using android::base::StringAppendF;
 
@@ -265,7 +261,6 @@
     dumpVal(out, "size", mSize);
     StringAppendF(&out, "ANativeWindow=%p (format %d) ", mNativeWindow.get(),
                   ANativeWindow_getFormat(mNativeWindow.get()));
-    dumpVal(out, "flips", mPageFlipCount);
     out.append("\n");
 
     String8 surfaceDump;
@@ -273,14 +268,6 @@
     out.append(surfaceDump);
 }
 
-std::uint32_t RenderSurface::getPageFlipCount() const {
-    return mPageFlipCount;
-}
-
-void RenderSurface::setPageFlipCountForTest(std::uint32_t count) {
-    mPageFlipCount = count;
-}
-
 void RenderSurface::setSizeForTest(const ui::Size& size) {
     mSize = size;
 }
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index aaca4fe..641b806 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -271,13 +271,16 @@
         bufferFence.reset(texture->getReadyFence()->dup());
     }
 
-    auto [status, drawFence] = renderEngine
-                                       .drawLayers(displaySettings, layerSettings, texture->get(),
-                                                   false, std::move(bufferFence))
-                                       .get();
+    constexpr bool kUseFramebufferCache = false;
 
-    if (status == NO_ERROR) {
-        mDrawFence = new Fence(drawFence.release());
+    auto fenceResult =
+            toFenceResult(renderEngine
+                                  .drawLayers(displaySettings, layerSettings, texture->get(),
+                                              kUseFramebufferCache, std::move(bufferFence))
+                                  .get());
+
+    if (fenceStatus(fenceResult) == NO_ERROR) {
+        mDrawFence = std::move(fenceResult).value_or(Fence::NO_FENCE);
         mOutputSpace = outputState.framebufferSpace;
         mTexture = texture;
         mTexture->setReadyFence(mDrawFence);
@@ -385,6 +388,12 @@
                        [](const Layer& layer) { return layer.getState()->isProtected(); });
 }
 
+bool CachedSet::hasSolidColorLayers() const {
+    return std::any_of(mLayers.cbegin(), mLayers.cend(), [](const Layer& layer) {
+        return layer.getState()->hasSolidColorCompositionType();
+    });
+}
+
 void CachedSet::dump(std::string& result) const {
     const auto now = std::chrono::steady_clock::now();
 
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 8d26747..1062b70 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -316,7 +316,7 @@
                         state.overrideInfo = {
                                 .buffer = mNewCachedSet->getBuffer(),
                                 .acquireFence = mNewCachedSet->getDrawFence(),
-                                .displayFrame = mNewCachedSet->getBounds(),
+                                .displayFrame = mNewCachedSet->getTextureBounds(),
                                 .dataspace = mNewCachedSet->getOutputDataspace(),
                                 .displaySpace = mNewCachedSet->getOutputSpace(),
                                 .damageRegion = Region::INVALID_REGION,
@@ -356,7 +356,7 @@
                 state.overrideInfo = {
                         .buffer = currentLayerIter->getBuffer(),
                         .acquireFence = currentLayerIter->getDrawFence(),
-                        .displayFrame = currentLayerIter->getBounds(),
+                        .displayFrame = currentLayerIter->getTextureBounds(),
                         .dataspace = currentLayerIter->getOutputDataspace(),
                         .displaySpace = currentLayerIter->getOutputSpace(),
                         .damageRegion = Region(),
@@ -401,19 +401,6 @@
     return true;
 }
 
-namespace {
-bool isDisplayDecoration(const CachedSet& cachedSet) {
-    return cachedSet.getLayerCount() == 1 &&
-            cachedSet.getFirstLayer()
-                    .getState()
-                    ->getOutputLayer()
-                    ->getLayerFE()
-                    .getCompositionState()
-                    ->compositionType ==
-            aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
-}
-} // namespace
-
 std::vector<Flattener::Run> Flattener::findCandidateRuns(time_point now) const {
     ATRACE_CALL();
     std::vector<Run> runs;
@@ -437,7 +424,7 @@
         }
 
         if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) &&
-            !currentSet->hasUnsupportedDataspace() && !isDisplayDecoration(*currentSet)) {
+            !currentSet->hasUnsupportedDataspace()) {
             if (isPartOfRun) {
                 builder.increment();
             } else {
@@ -511,6 +498,13 @@
         }
     }
 
+    for (const CachedSet& layer : mLayers) {
+        if (layer.hasSolidColorLayers()) {
+            ATRACE_NAME("layer->hasSolidColorLayers()");
+            return;
+        }
+    }
+
     std::vector<Run> runs = findCandidateRuns(now);
 
     std::optional<Run> bestRun = findBestRun(runs);
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 0e5a7b6..51ca213 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() {
@@ -193,7 +194,7 @@
     StrictMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor;
     StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
     StrictMock<mock::CompositionEngine> mCompositionEngine;
-    sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
+    sp<mock::NativeWindow> mNativeWindow = sp<StrictMock<mock::NativeWindow>>::make();
 };
 
 struct PartialMockDisplayTestCommon : public DisplayTestCommon {
@@ -523,7 +524,7 @@
     auto args = getDisplayCreationArgsForGpuVirtualDisplay();
     std::shared_ptr<impl::Display> gpuDisplay = impl::createDisplay(mCompositionEngine, args);
 
-    sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>();
+    sp<mock::LayerFE> layerXLayerFE = sp<StrictMock<mock::LayerFE>>::make();
 
     {
         Output::ReleasedLayers releasedLayers;
@@ -541,7 +542,7 @@
 }
 
 TEST_F(DisplaySetReleasedLayersTest, doesNothingIfNoLayersWithQueuedFrames) {
-    sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>();
+    sp<mock::LayerFE> layerXLayerFE = sp<StrictMock<mock::LayerFE>>::make();
 
     {
         Output::ReleasedLayers releasedLayers;
@@ -557,7 +558,7 @@
 }
 
 TEST_F(DisplaySetReleasedLayersTest, setReleasedLayers) {
-    sp<mock::LayerFE> unknownLayer = new StrictMock<mock::LayerFE>();
+    sp<mock::LayerFE> unknownLayer = sp<StrictMock<mock::LayerFE>>::make();
 
     CompositionRefreshArgs refreshArgs;
     refreshArgs.layersWithQueuedFrames.push_back(mLayer1.layerFE);
@@ -896,9 +897,9 @@
 }
 
 TEST_F(DisplayPresentAndGetFrameFencesTest, returnsPresentAndLayerFences) {
-    sp<Fence> presentFence = new Fence();
-    sp<Fence> layer1Fence = new Fence();
-    sp<Fence> layer2Fence = new Fence();
+    sp<Fence> presentFence = sp<Fence>::make();
+    sp<Fence> layer1Fence = sp<Fence>::make();
+    sp<Fence> layer2Fence = sp<Fence>::make();
 
     EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(HalDisplayId(DEFAULT_DISPLAY_ID), _, _))
             .Times(1);
@@ -1017,8 +1018,8 @@
     NiceMock<android::mock::HWComposer> mHwComposer;
     NiceMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor;
     NiceMock<mock::CompositionEngine> mCompositionEngine;
-    sp<mock::NativeWindow> mNativeWindow = new NiceMock<mock::NativeWindow>();
-    sp<mock::DisplaySurface> mDisplaySurface = new NiceMock<mock::DisplaySurface>();
+    sp<mock::NativeWindow> mNativeWindow = sp<NiceMock<mock::NativeWindow>>::make();
+    sp<mock::DisplaySurface> mDisplaySurface = sp<NiceMock<mock::DisplaySurface>>::make();
     std::shared_ptr<Display> mDisplay;
     impl::RenderSurface* mRenderSurface;
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
index 00eafb1..7197780 100644
--- a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
@@ -66,8 +66,10 @@
     }
 
     impl::HwcBufferCache mCache;
-    sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
-    sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+    sp<GraphicBuffer> mBuffer1 =
+            sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
+    sp<GraphicBuffer> mBuffer2 =
+            sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
 };
 
 TEST_F(HwcBufferCacheTest, cacheWorksForSlotZero) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index ff2aa15..d7704a8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -84,9 +84,9 @@
     MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t));
     MOCK_METHOD4(getDisplayedContentSample,
                  status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*));
-    MOCK_METHOD4(setDisplayBrightness,
-                 std::future<status_t>(PhysicalDisplayId, float, float,
-                                       const Hwc2::Composer::DisplayBrightnessOptions&));
+    MOCK_METHOD(ftl::Future<status_t>, setDisplayBrightness,
+                (PhysicalDisplayId, float, float, const Hwc2::Composer::DisplayBrightnessOptions&),
+                (override));
     MOCK_METHOD2(getDisplayBrightnessSupport, status_t(PhysicalDisplayId, bool*));
 
     MOCK_METHOD2(onHotplug,
@@ -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/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index ceee48c..0f7dce8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -169,7 +169,7 @@
     FloatRect calculateOutputSourceCrop() {
         mLayerFEState.geomInverseLayerTransform = mLayerFEState.geomLayerTransform.inverse();
 
-        return mOutputLayer.calculateOutputSourceCrop();
+        return mOutputLayer.calculateOutputSourceCrop(ui::Transform::RotationFlags::ROT_0);
     }
 };
 
@@ -533,7 +533,7 @@
                                                     sp<compositionengine::LayerFE> layerFE)
           : mOutput(output), mLayerFE(layerFE) {}
     // Mock everything called by updateCompositionState to simplify testing it.
-    MOCK_CONST_METHOD0(calculateOutputSourceCrop, FloatRect());
+    MOCK_CONST_METHOD1(calculateOutputSourceCrop, FloatRect(uint32_t));
     MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect());
     MOCK_CONST_METHOD1(calculateOutputRelativeBufferTransform, uint32_t(uint32_t));
 
@@ -563,7 +563,8 @@
     ~OutputLayerUpdateCompositionStateTest() = default;
 
     void setupGeometryChildCallValues(ui::Transform::RotationFlags internalDisplayRotationFlags) {
-        EXPECT_CALL(mOutputLayer, calculateOutputSourceCrop()).WillOnce(Return(kSourceCrop));
+        EXPECT_CALL(mOutputLayer, calculateOutputSourceCrop(internalDisplayRotationFlags))
+                .WillOnce(Return(kSourceCrop));
         EXPECT_CALL(mOutputLayer, calculateOutputDisplayFrame()).WillOnce(Return(kDisplayFrame));
         EXPECT_CALL(mOutputLayer,
                     calculateOutputRelativeBufferTransform(internalDisplayRotationFlags))
@@ -657,6 +658,23 @@
     EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace);
 }
 
+TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceWith170mReplacement) {
+    mLayerFEState.dataspace = ui::Dataspace::TRANSFER_SMPTE_170M;
+    mOutputState.targetDataspace = ui::Dataspace::V0_SCRGB;
+    mOutputState.treat170mAsSrgb = false;
+    mLayerFEState.isColorspaceAgnostic = false;
+
+    mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
+
+    EXPECT_EQ(ui::Dataspace::TRANSFER_SMPTE_170M, mOutputLayer.getState().dataspace);
+
+    // Rewrite SMPTE 170M as sRGB
+    mOutputState.treat170mAsSrgb = true;
+    mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
+
+    EXPECT_EQ(ui::Dataspace::TRANSFER_SRGB, mOutputLayer.getState().dataspace);
+}
+
 TEST_F(OutputLayerUpdateCompositionStateTest, setsWhitePointNitsAndDimmingRatioCorrectly) {
     mOutputState.sdrWhitePointNits = 200.f;
     mOutputState.displayBrightnessNits = 800.f;
@@ -922,7 +940,7 @@
                                                    84.f / 255.f};
 const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
 const Rect OutputLayerWriteStateToHWCTest::kOverrideDisplayFrame{1002, 1003, 1004, 20044};
-const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{1002, 1003, 1004, 20044};
+const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{0.f, 0.f, 4.f, 5.f};
 const Region OutputLayerWriteStateToHWCTest::kOutputSpaceVisibleRegion{
         Rect{1005, 1006, 1007, 1008}};
 const Region OutputLayerWriteStateToHWCTest::kOverrideVisibleRegion{Rect{1006, 1007, 1008, 1009}};
@@ -937,11 +955,11 @@
         reinterpret_cast<native_handle_t*>(1031);
 const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer;
 const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kOverrideBuffer =
-        new GraphicBuffer(4, 5, PIXEL_FORMAT_RGBA_8888,
-                          AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
-                                  AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
+        sp<GraphicBuffer>::make(4, 5, PIXEL_FORMAT_RGBA_8888,
+                                AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
+                                        AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
 const sp<Fence> OutputLayerWriteStateToHWCTest::kFence;
-const sp<Fence> OutputLayerWriteStateToHWCTest::kOverrideFence = new Fence();
+const sp<Fence> OutputLayerWriteStateToHWCTest::kOverrideFence = sp<Fence>::make();
 const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key =
         "com.example.metadata.1";
 const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Value{{1, 2, 3}};
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 42c8b37..ad0fb9d 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -248,6 +248,20 @@
 }
 
 /*
+ * Output::setTreat170mAsSrgb()
+ */
+
+TEST_F(OutputTest, setTreat170mAsSrgb) {
+    EXPECT_FALSE(mOutput->getState().treat170mAsSrgb);
+
+    mOutput->setTreat170mAsSrgb(true);
+    EXPECT_TRUE(mOutput->getState().treat170mAsSrgb);
+
+    mOutput->setTreat170mAsSrgb(false);
+    EXPECT_FALSE(mOutput->getState().treat170mAsSrgb);
+}
+
+/*
  * Output::setLayerCachingEnabled()
  */
 
@@ -279,7 +293,7 @@
     InjectedLayer layer;
     layer.outputLayerState.overrideInfo.buffer = std::make_shared<
             renderengine::impl::
-                    ExternalTexture>(new GraphicBuffer(), renderEngine,
+                    ExternalTexture>(sp<GraphicBuffer>::make(), renderEngine,
                                      renderengine::impl::ExternalTexture::Usage::READABLE |
                                              renderengine::impl::ExternalTexture::Usage::WRITEABLE);
     injectOutputLayer(layer);
@@ -836,14 +850,20 @@
     EXPECT_CALL(*layer1.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
     EXPECT_CALL(*layer2.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
     EXPECT_CALL(*layer3.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
 
     injectOutputLayer(layer1);
     injectOutputLayer(layer2);
@@ -870,14 +890,20 @@
     EXPECT_CALL(*layer1.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
     EXPECT_CALL(*layer2.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
     EXPECT_CALL(*layer3.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
 
     injectOutputLayer(layer1);
     injectOutputLayer(layer2);
@@ -903,14 +929,20 @@
     EXPECT_CALL(*layer1.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
     EXPECT_CALL(*layer2.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
     EXPECT_CALL(*layer3.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
 
     injectOutputLayer(layer1);
     injectOutputLayer(layer2);
@@ -936,6 +968,8 @@
     InSequence seq;
     EXPECT_CALL(*layer0.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
     EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
+        EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+                .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
     EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
 
@@ -943,6 +977,9 @@
     EXPECT_CALL(*layer0.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer0.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
+
 
     // After calling planComposition (which clears overrideInfo), this test sets
     // layer3 to be the peekThroughLayer for layer1 and layer2. As a result, it
@@ -952,12 +989,18 @@
                 writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ true, /*isPeekingThrough*/
                                 true));
+    EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer1.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ true, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer2.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, z++,
                                 /*zIsOverridden*/ true, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
 
     injectOutputLayer(layer0);
     injectOutputLayer(layer1);
@@ -974,7 +1017,7 @@
 
     std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared<
             renderengine::impl::
-                    ExternalTexture>(new GraphicBuffer(), renderEngine,
+                    ExternalTexture>(sp<GraphicBuffer>::make(), renderEngine,
                                      renderengine::impl::ExternalTexture::Usage::READABLE |
                                              renderengine::impl::ExternalTexture::Usage::WRITEABLE);
     layer1.outputLayerState.overrideInfo.buffer = buffer;
@@ -1462,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;
@@ -1485,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));
@@ -1954,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()
  */
@@ -3143,7 +3227,6 @@
     // setup below are satisfied in the specific order.
     InSequence seq;
 
-    EXPECT_CALL(*mRenderSurface, flip());
     EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences));
     EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
 
@@ -3157,16 +3240,15 @@
     mOutput.mState.isEnabled = true;
 
     // Create three unique fence instances
-    sp<Fence> layer1Fence = new Fence();
-    sp<Fence> layer2Fence = new Fence();
-    sp<Fence> layer3Fence = new Fence();
+    sp<Fence> layer1Fence = sp<Fence>::make();
+    sp<Fence> layer2Fence = sp<Fence>::make();
+    sp<Fence> layer3Fence = sp<Fence>::make();
 
     Output::FrameFences frameFences;
     frameFences.layerFences.emplace(&mLayer1.hwc2Layer, layer1Fence);
     frameFences.layerFences.emplace(&mLayer2.hwc2Layer, layer2Fence);
     frameFences.layerFences.emplace(&mLayer3.hwc2Layer, layer3Fence);
 
-    EXPECT_CALL(*mRenderSurface, flip());
     EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences));
     EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
 
@@ -3174,23 +3256,17 @@
     // are passed. This happens to work with the current implementation, but
     // would not survive certain calls like Fence::merge() which would return a
     // new instance.
-    base::unique_fd layer1FD(layer1Fence->dup());
-    base::unique_fd layer2FD(layer2Fence->dup());
-    base::unique_fd layer3FD(layer3Fence->dup());
     EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_))
-            .WillOnce([&layer1FD](std::shared_future<renderengine::RenderEngineResult>
-                                          futureRenderEngineResult) {
-                EXPECT_EQ(layer1FD, futureRenderEngineResult.get().drawFence);
+            .WillOnce([&layer1Fence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+                EXPECT_EQ(FenceResult(layer1Fence), futureFenceResult.get());
             });
     EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_))
-            .WillOnce([&layer2FD](std::shared_future<renderengine::RenderEngineResult>
-                                          futureRenderEngineResult) {
-                EXPECT_EQ(layer2FD, futureRenderEngineResult.get().drawFence);
+            .WillOnce([&layer2Fence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+                EXPECT_EQ(FenceResult(layer2Fence), futureFenceResult.get());
             });
     EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_))
-            .WillOnce([&layer3FD](std::shared_future<renderengine::RenderEngineResult>
-                                          futureRenderEngineResult) {
-                EXPECT_EQ(layer3FD, futureRenderEngineResult.get().drawFence);
+            .WillOnce([&layer3Fence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+                EXPECT_EQ(FenceResult(layer3Fence), futureFenceResult.get());
             });
 
     mOutput.postFramebuffer();
@@ -3200,17 +3276,12 @@
     mOutput.mState.isEnabled = true;
     mOutput.mState.usesClientComposition = true;
 
-    sp<Fence> clientTargetAcquireFence = new Fence();
-    sp<Fence> layer1Fence = new Fence();
-    sp<Fence> layer2Fence = new Fence();
-    sp<Fence> layer3Fence = new Fence();
     Output::FrameFences frameFences;
-    frameFences.clientTargetAcquireFence = clientTargetAcquireFence;
-    frameFences.layerFences.emplace(&mLayer1.hwc2Layer, layer1Fence);
-    frameFences.layerFences.emplace(&mLayer2.hwc2Layer, layer2Fence);
-    frameFences.layerFences.emplace(&mLayer3.hwc2Layer, layer3Fence);
+    frameFences.clientTargetAcquireFence = sp<Fence>::make();
+    frameFences.layerFences.emplace(&mLayer1.hwc2Layer, sp<Fence>::make());
+    frameFences.layerFences.emplace(&mLayer2.hwc2Layer, sp<Fence>::make());
+    frameFences.layerFences.emplace(&mLayer3.hwc2Layer, sp<Fence>::make());
 
-    EXPECT_CALL(*mRenderSurface, flip());
     EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences));
     EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
 
@@ -3242,30 +3313,25 @@
     mOutput.setReleasedLayers(std::move(layers));
 
     // Set up a fake present fence
-    sp<Fence> presentFence = new Fence();
+    sp<Fence> presentFence = sp<Fence>::make();
     Output::FrameFences frameFences;
     frameFences.presentFence = presentFence;
 
-    EXPECT_CALL(*mRenderSurface, flip());
     EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences));
     EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
 
     // Each released layer should be given the presentFence.
-    base::unique_fd layerFD(presentFence.get()->dup());
     EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_))
-            .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
-                                         futureRenderEngineResult) {
-                EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+            .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+                EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
             });
     EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_))
-            .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
-                                         futureRenderEngineResult) {
-                EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+            .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+                EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
             });
     EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_))
-            .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
-                                         futureRenderEngineResult) {
-                EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+            .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+                EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
             });
 
     mOutput.postFramebuffer();
@@ -3290,6 +3356,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() {
@@ -3354,7 +3423,6 @@
     static constexpr float kDefaultMaxLuminance = 0.9f;
     static constexpr float kDefaultAvgLuminance = 0.7f;
     static constexpr float kDefaultMinLuminance = 0.1f;
-    static constexpr float kUnknownLuminance = -1.f;
     static constexpr float kDisplayLuminance = 400.f;
     static constexpr float kClientTargetLuminanceNits = 200.f;
     static constexpr float kClientTargetBrightness = 0.5f;
@@ -3377,7 +3445,7 @@
     StrictMock<OutputPartialMock> mOutput;
     std::shared_ptr<renderengine::ExternalTexture> mOutputBuffer = std::make_shared<
             renderengine::impl::
-                    ExternalTexture>(new GraphicBuffer(), mRenderEngine,
+                    ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine,
                                      renderengine::impl::ExternalTexture::Usage::READABLE |
                                              renderengine::impl::ExternalTexture::Usage::WRITEABLE);
 
@@ -3615,7 +3683,7 @@
 
     const auto otherOutputBuffer = std::make_shared<
             renderengine::impl::
-                    ExternalTexture>(new GraphicBuffer(), mRenderEngine,
+                    ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine,
                                      renderengine::impl::ExternalTexture::Usage::READABLE |
                                              renderengine::impl::ExternalTexture::Usage::WRITEABLE);
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
@@ -3752,7 +3820,7 @@
 TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedComposition) {
     verify().ifMixedCompositionIs(true)
             .andIfUsesHdr(true)
-            .withDisplayBrightnessNits(kUnknownLuminance)
+            .withDisplayBrightnessNits(kDisplayLuminance)
             .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
             .withRenderIntent(
                     aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3761,7 +3829,7 @@
                     {.physicalDisplay = kDefaultOutputDestinationClip,
                      .clip = kDefaultOutputViewport,
                      .maxLuminance = kDefaultMaxLuminance,
-                     .currentLuminanceNits = kDefaultMaxLuminance,
+                     .currentLuminanceNits = kDisplayLuminance,
                      .outputDataspace = kDefaultOutputDataspace,
                      .colorTransform = kDefaultColorTransformMat,
                      .deviceHandlesColorTransform = true,
@@ -3806,7 +3874,7 @@
        forHdrMixedCompositionWithDimmingStage) {
     verify().ifMixedCompositionIs(true)
             .andIfUsesHdr(true)
-            .withDisplayBrightnessNits(kUnknownLuminance)
+            .withDisplayBrightnessNits(kDisplayLuminance)
             .withDimmingStage(
                     aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF)
             .withRenderIntent(
@@ -3816,7 +3884,7 @@
                     {.physicalDisplay = kDefaultOutputDestinationClip,
                      .clip = kDefaultOutputViewport,
                      .maxLuminance = kDefaultMaxLuminance,
-                     .currentLuminanceNits = kDefaultMaxLuminance,
+                     .currentLuminanceNits = kDisplayLuminance,
                      .outputDataspace = kDefaultOutputDataspace,
                      .colorTransform = kDefaultColorTransformMat,
                      .deviceHandlesColorTransform = true,
@@ -3834,7 +3902,7 @@
        forHdrMixedCompositionWithRenderIntent) {
     verify().ifMixedCompositionIs(true)
             .andIfUsesHdr(true)
-            .withDisplayBrightnessNits(kUnknownLuminance)
+            .withDisplayBrightnessNits(kDisplayLuminance)
             .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
             .withRenderIntent(aidl::android::hardware::graphics::composer3::RenderIntent::ENHANCE)
             .andIfSkipColorTransform(false)
@@ -3842,7 +3910,7 @@
                     {.physicalDisplay = kDefaultOutputDestinationClip,
                      .clip = kDefaultOutputViewport,
                      .maxLuminance = kDefaultMaxLuminance,
-                     .currentLuminanceNits = kDefaultMaxLuminance,
+                     .currentLuminanceNits = kDisplayLuminance,
                      .outputDataspace = kDefaultOutputDataspace,
                      .colorTransform = kDefaultColorTransformMat,
                      .deviceHandlesColorTransform = true,
@@ -3859,7 +3927,7 @@
 TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComposition) {
     verify().ifMixedCompositionIs(true)
             .andIfUsesHdr(false)
-            .withDisplayBrightnessNits(kUnknownLuminance)
+            .withDisplayBrightnessNits(kDisplayLuminance)
             .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
             .withRenderIntent(
                     aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3868,7 +3936,7 @@
                     {.physicalDisplay = kDefaultOutputDestinationClip,
                      .clip = kDefaultOutputViewport,
                      .maxLuminance = kDefaultMaxLuminance,
-                     .currentLuminanceNits = kDefaultMaxLuminance,
+                     .currentLuminanceNits = kDisplayLuminance,
                      .outputDataspace = kDefaultOutputDataspace,
                      .colorTransform = kDefaultColorTransformMat,
                      .deviceHandlesColorTransform = true,
@@ -3885,7 +3953,7 @@
 TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientComposition) {
     verify().ifMixedCompositionIs(false)
             .andIfUsesHdr(true)
-            .withDisplayBrightnessNits(kUnknownLuminance)
+            .withDisplayBrightnessNits(kDisplayLuminance)
             .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
             .withRenderIntent(
                     aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3894,7 +3962,7 @@
                     {.physicalDisplay = kDefaultOutputDestinationClip,
                      .clip = kDefaultOutputViewport,
                      .maxLuminance = kDefaultMaxLuminance,
-                     .currentLuminanceNits = kDefaultMaxLuminance,
+                     .currentLuminanceNits = kDisplayLuminance,
                      .outputDataspace = kDefaultOutputDataspace,
                      .colorTransform = kDefaultColorTransformMat,
                      .deviceHandlesColorTransform = false,
@@ -3911,7 +3979,7 @@
 TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrOnlyClientComposition) {
     verify().ifMixedCompositionIs(false)
             .andIfUsesHdr(false)
-            .withDisplayBrightnessNits(kUnknownLuminance)
+            .withDisplayBrightnessNits(kDisplayLuminance)
             .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
             .withRenderIntent(
                     aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3920,7 +3988,7 @@
                     {.physicalDisplay = kDefaultOutputDestinationClip,
                      .clip = kDefaultOutputViewport,
                      .maxLuminance = kDefaultMaxLuminance,
-                     .currentLuminanceNits = kDefaultMaxLuminance,
+                     .currentLuminanceNits = kDisplayLuminance,
                      .outputDataspace = kDefaultOutputDataspace,
                      .colorTransform = kDefaultColorTransformMat,
                      .deviceHandlesColorTransform = false,
@@ -3938,7 +4006,7 @@
        usesExpectedDisplaySettingsForHdrOnlyClientCompositionWithSkipClientTransform) {
     verify().ifMixedCompositionIs(false)
             .andIfUsesHdr(true)
-            .withDisplayBrightnessNits(kUnknownLuminance)
+            .withDisplayBrightnessNits(kDisplayLuminance)
             .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
             .withRenderIntent(
                     aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3947,7 +4015,7 @@
                     {.physicalDisplay = kDefaultOutputDestinationClip,
                      .clip = kDefaultOutputViewport,
                      .maxLuminance = kDefaultMaxLuminance,
-                     .currentLuminanceNits = kDefaultMaxLuminance,
+                     .currentLuminanceNits = kDisplayLuminance,
                      .outputDataspace = kDefaultOutputDataspace,
                      .colorTransform = kDefaultColorTransformMat,
                      .deviceHandlesColorTransform = true,
@@ -4785,10 +4853,14 @@
     EXPECT_CALL(*layer1.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
     EXPECT_CALL(*layer2.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
 
     layer2.layerFEState.backgroundBlurRadius = 10;
     layer2.layerFEState.isOpaque = true;
@@ -4817,14 +4889,20 @@
     EXPECT_CALL(*layer1.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
     EXPECT_CALL(*layer2.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
     EXPECT_CALL(*layer3.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
 
     layer2.layerFEState.backgroundBlurRadius = 10;
     layer2.layerFEState.isOpaque = false;
@@ -4854,14 +4932,20 @@
     EXPECT_CALL(*layer1.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
     EXPECT_CALL(*layer2.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
     EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
     EXPECT_CALL(*layer3.outputLayer,
                 writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+    EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+            .WillRepeatedly(Return(false));
 
     BlurRegion region;
     layer2.layerFEState.blurRegions.push_back(region);
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index e5f9ebf..83937a6 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -61,8 +61,8 @@
     StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
     StrictMock<mock::CompositionEngine> mCompositionEngine;
     StrictMock<mock::Display> mDisplay;
-    sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
-    sp<mock::DisplaySurface> mDisplaySurface = new StrictMock<mock::DisplaySurface>();
+    sp<mock::NativeWindow> mNativeWindow = sp<StrictMock<mock::NativeWindow>>::make();
+    sp<mock::DisplaySurface> mDisplaySurface = sp<StrictMock<mock::DisplaySurface>>::make();
     impl::RenderSurface mSurface{mCompositionEngine, mDisplay,
                                  RenderSurfaceCreationArgsBuilder()
                                          .setDisplayWidth(DEFAULT_DISPLAY_WIDTH)
@@ -109,7 +109,7 @@
  */
 
 TEST_F(RenderSurfaceTest, getClientTargetAcquireFenceForwardsCall) {
-    sp<Fence> fence = new Fence();
+    sp<Fence> fence = sp<Fence>::make();
 
     EXPECT_CALL(*mDisplaySurface, getClientTargetAcquireFence()).WillOnce(ReturnRef(fence));
 
@@ -234,7 +234,7 @@
  */
 
 TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) {
-    sp<GraphicBuffer> buffer = new GraphicBuffer();
+    sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make();
 
     EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
             .WillOnce(
@@ -253,7 +253,7 @@
 TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) {
     const auto buffer = std::make_shared<
             renderengine::impl::
-                    ExternalTexture>(new GraphicBuffer(), mRenderEngine,
+                    ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine,
                                      renderengine::impl::ExternalTexture::Usage::READABLE |
                                              renderengine::impl::ExternalTexture::Usage::WRITEABLE);
     mSurface.mutableTextureForTest() = buffer;
@@ -271,8 +271,9 @@
 }
 
 TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) {
-    const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(),
-                                                                              mRenderEngine, false);
+    const auto buffer =
+            std::make_shared<renderengine::impl::ExternalTexture>(sp<GraphicBuffer>::make(),
+                                                                  mRenderEngine, false);
     mSurface.mutableTextureForTest() = buffer;
 
     impl::OutputCompositionState state;
@@ -290,8 +291,9 @@
 }
 
 TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) {
-    const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(),
-                                                                              mRenderEngine, false);
+    const auto buffer =
+            std::make_shared<renderengine::impl::ExternalTexture>(sp<GraphicBuffer>::make(),
+                                                                  mRenderEngine, false);
     mSurface.mutableTextureForTest() = buffer;
 
     impl::OutputCompositionState state;
@@ -309,7 +311,7 @@
 }
 
 TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) {
-    sp<GraphicBuffer> buffer = new GraphicBuffer();
+    sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make();
 
     impl::OutputCompositionState state;
     state.usesClientComposition = false;
@@ -329,8 +331,9 @@
 }
 
 TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) {
-    const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(),
-                                                                              mRenderEngine, false);
+    const auto buffer =
+            std::make_shared<renderengine::impl::ExternalTexture>(sp<GraphicBuffer>::make(),
+                                                                  mRenderEngine, false);
     mSurface.mutableTextureForTest() = buffer;
 
     impl::OutputCompositionState state;
@@ -359,17 +362,5 @@
     mSurface.onPresentDisplayCompleted();
 }
 
-/*
- * RenderSurface::flip()
- */
-
-TEST_F(RenderSurfaceTest, flipForwardsSignal) {
-    mSurface.setPageFlipCountForTest(500);
-
-    mSurface.flip();
-
-    EXPECT_EQ(501u, mSurface.getPageFlipCount());
-}
-
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 96c28c9..200278c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -108,11 +108,12 @@
         testLayer->outputLayerCompositionState.visibleRegion =
                 Region(Rect(pos + 1, pos + 1, pos + 2, pos + 2));
 
+        const auto kUsageFlags =
+                static_cast<uint64_t>(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+                                      GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE);
         testLayer->layerFECompositionState.buffer =
-                new GraphicBuffer(100, 100, HAL_PIXEL_FORMAT_RGBA_8888, 1,
-                                  GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
-                                          GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE,
-                                  "output");
+                sp<GraphicBuffer>::make(100u, 100u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags,
+                                        "output");
 
         testLayer->layerFE = sp<mock::LayerFE>::make();
 
@@ -1340,14 +1341,14 @@
     EXPECT_NE(nullptr, overrideBuffer4);
 }
 
-TEST_F(FlattenerTest, flattenLayers_skips_DISPLAY_DECORATION) {
+TEST_F(FlattenerTest, flattenLayers_includes_DISPLAY_DECORATION) {
     auto& layerState1 = mTestLayers[0]->layerState;
     const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
 
     auto& layerState2 = mTestLayers[1]->layerState;
     const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer;
 
-    // The third layer uses DISPLAY_DECORATION, which should never be cached.
+    // The third layer uses DISPLAY_DECORATION, which should be cached.
     auto& layerState3 = mTestLayers[2]->layerState;
     const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer;
     mTestLayers[2]->layerFECompositionState.compositionType =
@@ -1388,7 +1389,7 @@
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
-    EXPECT_EQ(nullptr, overrideBuffer3);
+    EXPECT_EQ(overrideBuffer1, overrideBuffer3);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
index 5c6e8da..47b6820 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
@@ -112,6 +112,9 @@
     sp<mock::LayerFE> mLayerFE = sp<mock::LayerFE>::make();
     mock::OutputLayer mOutputLayer;
     std::unique_ptr<LayerState> mLayerState;
+
+    static constexpr auto kUsageFlags = static_cast<uint32_t>(
+            AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN);
 };
 
 TEST_F(LayerStateTest, getOutputLayer) {
@@ -346,7 +349,7 @@
 TEST_F(LayerStateTest, updateBuffer) {
     OutputLayerCompositionState outputLayerCompositionState;
     LayerFECompositionState layerFECompositionState;
-    layerFECompositionState.buffer = new GraphicBuffer();
+    layerFECompositionState.buffer = sp<GraphicBuffer>::make();
     setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
                        layerFECompositionState);
     mLayerState = std::make_unique<LayerState>(&mOutputLayer);
@@ -354,7 +357,7 @@
     mock::OutputLayer newOutputLayer;
     sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
     LayerFECompositionState layerFECompositionStateTwo;
-    layerFECompositionStateTwo.buffer = new GraphicBuffer();
+    layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
     ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
@@ -364,7 +367,7 @@
 TEST_F(LayerStateTest, updateBufferSingleBufferedLegacy) {
     OutputLayerCompositionState outputLayerCompositionState;
     LayerFECompositionState layerFECompositionState;
-    layerFECompositionState.buffer = new GraphicBuffer();
+    layerFECompositionState.buffer = sp<GraphicBuffer>::make();
     setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
                        layerFECompositionState);
     mLayerState = std::make_unique<LayerState>(&mOutputLayer);
@@ -372,7 +375,7 @@
     mock::OutputLayer newOutputLayer;
     sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
     LayerFECompositionState layerFECompositionStateTwo;
-    layerFECompositionStateTwo.buffer = new GraphicBuffer();
+    layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
 
@@ -388,7 +391,7 @@
 TEST_F(LayerStateTest, updateBufferSingleBufferedUsage) {
     OutputLayerCompositionState outputLayerCompositionState;
     LayerFECompositionState layerFECompositionState;
-    layerFECompositionState.buffer = new GraphicBuffer();
+    layerFECompositionState.buffer = sp<GraphicBuffer>::make();
     setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
                        layerFECompositionState);
     mLayerState = std::make_unique<LayerState>(&mOutputLayer);
@@ -396,7 +399,7 @@
     mock::OutputLayer newOutputLayer;
     sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
     LayerFECompositionState layerFECompositionStateTwo;
-    layerFECompositionStateTwo.buffer = new GraphicBuffer();
+    layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
     layerFECompositionStateTwo.buffer->usage = static_cast<uint64_t>(BufferUsage::FRONT_BUFFER);
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
@@ -412,14 +415,14 @@
 TEST_F(LayerStateTest, compareBuffer) {
     OutputLayerCompositionState outputLayerCompositionState;
     LayerFECompositionState layerFECompositionState;
-    layerFECompositionState.buffer = new GraphicBuffer();
+    layerFECompositionState.buffer = sp<GraphicBuffer>::make();
     setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
                        layerFECompositionState);
     mLayerState = std::make_unique<LayerState>(&mOutputLayer);
     mock::OutputLayer newOutputLayer;
     sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
     LayerFECompositionState layerFECompositionStateTwo;
-    layerFECompositionStateTwo.buffer = new GraphicBuffer();
+    layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -720,10 +723,7 @@
     OutputLayerCompositionState outputLayerCompositionState;
     LayerFECompositionState layerFECompositionState;
     layerFECompositionState.buffer =
-            new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888,
-                              AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
-                                      AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
-                              "buffer1");
+            sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888, kUsageFlags, "buffer1");
     setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
                        layerFECompositionState);
     mLayerState = std::make_unique<LayerState>(&mOutputLayer);
@@ -732,10 +732,7 @@
     sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
     LayerFECompositionState layerFECompositionStateTwo;
     layerFECompositionStateTwo.buffer =
-            new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBX_8888,
-                              AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
-                                      AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
-                              "buffer2");
+            sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBX_8888, kUsageFlags, "buffer2");
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
     ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
@@ -748,10 +745,7 @@
     OutputLayerCompositionState outputLayerCompositionState;
     LayerFECompositionState layerFECompositionState;
     layerFECompositionState.buffer =
-            new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888,
-                              AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
-                                      AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
-                              "buffer1");
+            sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888, kUsageFlags, "buffer1");
     setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
                        layerFECompositionState);
     mLayerState = std::make_unique<LayerState>(&mOutputLayer);
@@ -759,10 +753,7 @@
     sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
     LayerFECompositionState layerFECompositionStateTwo;
     layerFECompositionStateTwo.buffer =
-            new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBX_8888,
-                              AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
-                                      AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
-                              "buffer2");
+            sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBX_8888, kUsageFlags, "buffer2");
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -1069,7 +1060,7 @@
 TEST_F(LayerStateTest, getNonBufferHash_filtersOutBuffers) {
     OutputLayerCompositionState outputLayerCompositionState;
     LayerFECompositionState layerFECompositionState;
-    layerFECompositionState.buffer = new GraphicBuffer();
+    layerFECompositionState.buffer = sp<GraphicBuffer>::make();
     setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
                        layerFECompositionState);
     mLayerState = std::make_unique<LayerState>(&mOutputLayer);
@@ -1077,7 +1068,7 @@
     mock::OutputLayer newOutputLayer;
     sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
     LayerFECompositionState layerFECompositionStateTwo;
-    layerFECompositionStateTwo.buffer = new GraphicBuffer();
+    layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
index 68c72e0..35d0ffb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
@@ -228,7 +228,7 @@
 }
 
 TEST_F(LayerStackTest, getApproximateMatch_exactMatchesSameBuffer) {
-    sp<GraphicBuffer> buffer = new GraphicBuffer();
+    sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make();
     mock::OutputLayer outputLayerOne;
     sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
     OutputLayerCompositionState outputLayerCompositionStateOne;
@@ -268,7 +268,7 @@
             .dataspace = ui::Dataspace::SRGB,
     };
     LayerFECompositionState layerFECompositionStateOne;
-    layerFECompositionStateOne.buffer = new GraphicBuffer();
+    layerFECompositionStateOne.buffer = sp<GraphicBuffer>::make();
     layerFECompositionStateOne.alpha = sAlphaOne;
     layerFECompositionStateOne.colorTransformIsIdentity = true;
     setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
@@ -285,7 +285,7 @@
             .dataspace = ui::Dataspace::DISPLAY_P3,
     };
     LayerFECompositionState layerFECompositionStateTwo;
-    layerFECompositionStateTwo.buffer = new GraphicBuffer();
+    layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
     layerFECompositionStateTwo.alpha = sAlphaTwo;
     layerFECompositionStateTwo.colorTransformIsIdentity = false;
     layerFECompositionStateTwo.colorTransform = sMat4One;
@@ -310,7 +310,7 @@
             .sourceCrop = sFloatRectOne,
     };
     LayerFECompositionState layerFECompositionStateOne;
-    layerFECompositionStateOne.buffer = new GraphicBuffer();
+    layerFECompositionStateOne.buffer = sp<GraphicBuffer>::make();
     setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
                        layerFECompositionStateOne);
     LayerState layerStateOne(&outputLayerOne);
@@ -321,7 +321,7 @@
             .sourceCrop = sFloatRectTwo,
     };
     LayerFECompositionState layerFECompositionStateTwo;
-    layerFECompositionStateTwo.buffer = new GraphicBuffer();
+    layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
     setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo,
                        layerFECompositionStateTwo);
     LayerState layerStateTwo(&outputLayerTwo);
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
deleted file mode 100644
index 3ccc229..0000000
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ /dev/null
@@ -1,47 +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.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-// #define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "ContainerLayer"
-
-#include "ContainerLayer.h"
-
-namespace android {
-
-ContainerLayer::ContainerLayer(const LayerCreationArgs& args) : Layer(args) {}
-
-ContainerLayer::~ContainerLayer() = default;
-
-bool ContainerLayer::isVisible() const {
-    return false;
-}
-
-sp<Layer> ContainerLayer::createClone() {
-    sp<ContainerLayer> layer = mFlinger->getFactory().createContainerLayer(
-            LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()));
-    layer->setInitialValuesForClone(this);
-    return layer;
-}
-
-} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
deleted file mode 100644
index 9b7bab1..0000000
--- a/services/surfaceflinger/ContainerLayer.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <sys/types.h>
-
-#include <cstdint>
-
-#include "Layer.h"
-
-namespace android {
-
-class ContainerLayer : public Layer {
-public:
-    explicit ContainerLayer(const LayerCreationArgs&);
-    ~ContainerLayer() override;
-
-    const char* getType() const override { return "ContainerLayer"; }
-    bool isVisible() const override;
-
-    bool isCreatedFromMainThread() const override { return true; }
-
-protected:
-    bool canDrawShadows() const override { return false; }
-    sp<Layer> createClone() override;
-};
-
-} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 65e7a7f..bff301e 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -24,7 +24,6 @@
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include <android-base/stringprintf.h>
 #include <compositionengine/CompositionEngine.h>
 #include <compositionengine/Display.h>
 #include <compositionengine/DisplayColorProfile.h>
@@ -49,8 +48,6 @@
 
 namespace hal = hardware::graphics::composer::hal;
 
-using android::base::StringAppendF;
-
 ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::Transform::ROT_0;
 
 DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(
@@ -92,6 +89,7 @@
     }
 
     mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy);
+    mCompositionDisplay->setTreat170mAsSrgb(mFlinger->mTreat170mAsSrgb);
     mCompositionDisplay->createDisplayColorProfile(
             compositionengine::DisplayColorProfileCreationArgsBuilder()
                     .setHasWideColorGamut(args.hasWideColorGamut)
@@ -138,10 +136,6 @@
     mDeviceProductInfo = std::move(info);
 }
 
-uint32_t DisplayDevice::getPageFlipCount() const {
-    return mCompositionDisplay->getRenderSurface()->getPageFlipCount();
-}
-
 auto DisplayDevice::getInputInfo() const -> InputInfo {
     gui::DisplayInfo info;
     info.displayId = getLayerStack().id;
@@ -213,6 +207,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(),
@@ -342,38 +337,40 @@
 }
 
 std::string DisplayDevice::getDebugName() const {
-    const char* type = "virtual";
+    using namespace std::string_literals;
+
+    std::string name = "Display "s + to_string(getId()) + " ("s;
+
     if (mConnectionType) {
-        type = isInternal() ? "internal" : "external";
+        name += isInternal() ? "internal"s : "external"s;
+    } else {
+        name += "virtual"s;
     }
 
-    return base::StringPrintf("DisplayDevice{%s, %s%s, \"%s\"}", to_string(getId()).c_str(), type,
-                              isPrimary() ? ", primary" : "", mDisplayName.c_str());
+    if (isPrimary()) {
+        name += ", primary"s;
+    }
+
+    return name + ", \""s + mDisplayName + "\")"s;
 }
 
 void DisplayDevice::dump(std::string& result) const {
-    StringAppendF(&result, "+ %s\n", getDebugName().c_str());
-    StringAppendF(&result, "   powerMode=%s (%d)\n", to_string(mPowerMode).c_str(),
-                  static_cast<int32_t>(mPowerMode));
-    const auto activeMode = getActiveMode();
-    StringAppendF(&result, "   activeMode=%s\n",
-                  activeMode ? to_string(*activeMode).c_str() : "none");
+    using namespace std::string_literals;
 
-    result.append("   supportedModes=\n");
-    for (const auto& [id, mode] : mSupportedModes) {
-        result.append("      ");
-        result.append(to_string(*mode));
-        result.push_back('\n');
+    result += getDebugName();
+
+    if (!isVirtual()) {
+        result += "\n   deviceProductInfo="s;
+        if (mDeviceProductInfo) {
+            mDeviceProductInfo->dump(result);
+        } else {
+            result += "{}"s;
+        }
     }
 
-    StringAppendF(&result, "   deviceProductInfo=");
-    if (mDeviceProductInfo) {
-        mDeviceProductInfo->dump(result);
-    } else {
-        result.append("{}");
-    }
-    result.append("\n");
-    getCompositionDisplay()->dump(result);
+    result += "\n   powerMode="s;
+    result += to_string(mPowerMode);
+    result += '\n';
 
     if (mRefreshRateConfigs) {
         mRefreshRateConfigs->dump(result);
@@ -537,6 +534,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..10fc095 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -249,13 +249,16 @@
     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();
 
     /* ------------------------------------------------------------------------
      * Debugging
      */
-    uint32_t getPageFlipCount() const;
     std::string getDebugName() const;
     void dump(std::string& result) const;
 
@@ -303,6 +306,8 @@
     TracedOrdinal<bool> mDesiredActiveModeChanged
             GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
     ActiveModeInfo mUpcomingActiveMode GUARDED_BY(kMainThreadContext);
+
+    std::atomic_int mNumModeSwitchesInPolicy = 0;
 };
 
 struct DisplayDeviceState {
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 8d685cf..eb14933 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -44,18 +44,10 @@
 #include "HWComposer.h"
 #include "../SurfaceFlinger.h"
 
-// ----------------------------------------------------------------------------
 namespace android {
-// ----------------------------------------------------------------------------
 
 using ui::Dataspace;
 
-/*
- * This implements the (main) framebuffer management. This class is used
- * mostly by SurfaceFlinger, but also by command line GL application.
- *
- */
-
 FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId,
                                        const sp<IGraphicBufferConsumer>& consumer,
                                        const ui::Size& size, const ui::Size& maxSize)
@@ -205,14 +197,14 @@
 
 void FramebufferSurface::dumpAsString(String8& result) const {
     Mutex::Autolock lock(mMutex);
-    result.appendFormat("  FramebufferSurface: dataspace: %s(%d)\n",
+    result.append("   FramebufferSurface\n");
+    result.appendFormat("      mDataSpace=%s (%d)\n",
                         dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
                         mDataSpace);
-    ConsumerBase::dumpLocked(result, "   ");
+    ConsumerBase::dumpLocked(result, "      ");
 }
 
-void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const
-{
+void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const {
     ConsumerBase::dumpLocked(result, prefix);
 }
 
@@ -220,9 +212,7 @@
     return mCurrentFence;
 }
 
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
+} // namespace android
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index adf4be3..16d3984 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -27,7 +27,6 @@
 #include "HWC2.h"
 
 #include <android/configuration.h>
-#include <ftl/future.h>
 #include <ui/Fence.h>
 #include <ui/FloatRect.h>
 #include <ui/GraphicBuffer.h>
@@ -370,7 +369,7 @@
     for (uint32_t element = 0; element < numElements; ++element) {
         auto layer = getLayerById(layerIds[element]);
         if (layer) {
-            sp<Fence> fence(new Fence(fenceFds[element]));
+            sp<Fence> fence(sp<Fence>::make(fenceFds[element]));
             releaseFences.emplace(layer.get(), fence);
         } else {
             ALOGE("getReleaseFences: invalid layer %" PRIu64
@@ -395,7 +394,7 @@
         return error;
     }
 
-    *outPresentFence = new Fence(presentFenceFd);
+    *outPresentFence = sp<Fence>::make(presentFenceFd);
     return Error::NONE;
 }
 
@@ -533,7 +532,7 @@
     }
 
     if (*state == 1) {
-        *outPresentFence = new Fence(presentFenceFd);
+        *outPresentFence = sp<Fence>::make(presentFenceFd);
     }
 
     if (*state == 0) {
@@ -543,7 +542,7 @@
     return error;
 }
 
-std::future<Error> Display::setDisplayBrightness(
+ftl::Future<Error> Display::setDisplayBrightness(
         float brightness, float brightnessNits,
         const Hwc2::Composer::DisplayBrightnessOptions& options) {
     return ftl::defer([composer = &mComposer, id = mId, brightness, brightnessNits, options] {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index d8ff440..486eaf8 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -18,6 +18,7 @@
 
 #include <android-base/expected.h>
 #include <android-base/thread_annotations.h>
+#include <ftl/future.h>
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
 #include <ui/HdrCapabilities.h>
@@ -28,7 +29,6 @@
 #include <utils/Timers.h>
 
 #include <functional>
-#include <future>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
@@ -147,7 +147,7 @@
                                                        uint32_t* outNumRequests,
                                                        android::sp<android::Fence>* outPresentFence,
                                                        uint32_t* state) = 0;
-    [[nodiscard]] virtual std::future<hal::Error> setDisplayBrightness(
+    [[nodiscard]] virtual ftl::Future<hal::Error> setDisplayBrightness(
             float brightness, float brightnessNits,
             const Hwc2::Composer::DisplayBrightnessOptions& options) = 0;
     [[nodiscard]] virtual hal::Error setActiveConfigWithConstraints(
@@ -229,7 +229,7 @@
                                  uint32_t* outNumRequests,
                                  android::sp<android::Fence>* outPresentFence,
                                  uint32_t* state) override;
-    std::future<hal::Error> setDisplayBrightness(
+    ftl::Future<hal::Error> setDisplayBrightness(
             float brightness, float brightnessNits,
             const Hwc2::Composer::DisplayBrightnessOptions& options) override;
     hal::Error setActiveConfigWithConstraints(hal::HWConfigId configId,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 670233a..c71b1f9 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -30,7 +30,6 @@
 #include <compositionengine/Output.h>
 #include <compositionengine/OutputLayer.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
-#include <ftl/future.h>
 #include <log/log.h>
 #include <ui/DebugUtils.h>
 #include <ui/GraphicBuffer.h>
@@ -287,17 +286,12 @@
 
 std::optional<hal::HWConfigId> HWComposer::getActiveMode(PhysicalDisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, std::nullopt);
-
     const auto hwcId = *fromPhysicalDisplayId(displayId);
-    ALOGV("[%" PRIu64 "] getActiveMode", hwcId);
+
     hal::HWConfigId configId;
-    auto error = static_cast<hal::Error>(mComposer->getActiveConfig(hwcId, &configId));
+    const auto error = static_cast<hal::Error>(mComposer->getActiveConfig(hwcId, &configId));
 
-    if (error == hal::Error::BAD_CONFIG) {
-        LOG_DISPLAY_ERROR(displayId, "No active mode");
-        return std::nullopt;
-    }
-
+    RETURN_IF_HWC_ERROR_FOR("getActiveConfig", error, displayId, std::nullopt);
     return configId;
 }
 
@@ -376,11 +370,6 @@
     }
 
     ATRACE_CALL();
-    if (displayData.powerMode == hal::PowerMode::DOZE && enabled == hal::Vsync::ENABLE) {
-        ALOGV("%s will not enable vsync for display %s due to power mode %s", __FUNCTION__,
-              to_string(displayId).c_str(), to_string(displayData.powerMode).c_str());
-        return;
-    }
     auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
     RETURN_IF_HWC_ERROR(error, displayId);
 
@@ -557,7 +546,6 @@
         setVsyncEnabled(displayId, hal::Vsync::DISABLE);
     }
 
-    mDisplayData[displayId].powerMode = mode;
     const auto& displayData = mDisplayData[displayId];
     auto& hwcDisplay = displayData.hwcDisplay;
     switch (mode) {
@@ -726,13 +714,13 @@
     return NO_ERROR;
 }
 
-std::future<status_t> HWComposer::setDisplayBrightness(
+ftl::Future<status_t> HWComposer::setDisplayBrightness(
         PhysicalDisplayId displayId, float brightness, float brightnessNits,
         const Hwc2::Composer::DisplayBrightnessOptions& options) {
     RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield<status_t>(BAD_INDEX));
     auto& display = mDisplayData[displayId].hwcDisplay;
 
-    return ftl::chain(display->setDisplayBrightness(brightness, brightnessNits, options))
+    return display->setDisplayBrightness(brightness, brightnessNits, options)
             .then([displayId](hal::Error error) -> status_t {
                 if (error == hal::Error::UNSUPPORTED) {
                     RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
@@ -745,6 +733,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 8d67589..92a8f30 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -17,7 +17,6 @@
 #pragma once
 
 #include <cstdint>
-#include <future>
 #include <memory>
 #include <mutex>
 #include <optional>
@@ -26,6 +25,7 @@
 #include <vector>
 
 #include <android-base/thread_annotations.h>
+#include <ftl/future.h>
 #include <ui/DisplayIdentification.h>
 #include <ui/FenceTime.h>
 
@@ -195,10 +195,13 @@
                                                DisplayedFrameStats* outStats) = 0;
 
     // Sets the brightness of a display.
-    virtual std::future<status_t> setDisplayBrightness(
+    virtual ftl::Future<status_t> setDisplayBrightness(
             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
@@ -372,7 +375,7 @@
                                               uint64_t maxFrames) override;
     status_t getDisplayedContentSample(HalDisplayId, uint64_t maxFrames, uint64_t timestamp,
                                        DisplayedFrameStats* outStats) override;
-    std::future<status_t> setDisplayBrightness(
+    ftl::Future<status_t> setDisplayBrightness(
             PhysicalDisplayId, float brightness, float brightnessNits,
             const Hwc2::Composer::DisplayBrightnessOptions&) override;
 
@@ -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;
@@ -462,8 +467,6 @@
         std::mutex vsyncEnabledLock;
         hal::Vsync vsyncEnabled GUARDED_BY(vsyncEnabledLock) = hal::Vsync::DISABLE;
 
-        hal::PowerMode powerMode = hal::PowerMode::ON;
-
         nsecs_t lastHwVsync = 0;
     };
 
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index cbafdd3..929f9dc 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -64,9 +64,10 @@
 PowerAdvisor::~PowerAdvisor() = default;
 
 namespace {
-int32_t getUpdateTimeout() {
+std::chrono::milliseconds getUpdateTimeout() {
     // Default to a timeout of 80ms if nothing else is specified
-    static int32_t timeout = sysprop::display_update_imminent_timeout_ms(80);
+    static std::chrono::milliseconds timeout =
+            std::chrono::milliseconds(sysprop::display_update_imminent_timeout_ms(80));
     return timeout;
 }
 
@@ -80,22 +81,35 @@
 
 } // namespace
 
-PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger)
-      : mFlinger(flinger),
-        mUseScreenUpdateTimer(getUpdateTimeout() > 0),
-        mScreenUpdateTimer(
-                "UpdateImminentTimer", OneShotTimer::Interval(getUpdateTimeout()),
-                /* resetCallback */ [this] { mSendUpdateImminent.store(false); },
-                /* timeoutCallback */
-                [this] {
-                    mSendUpdateImminent.store(true);
-                    mFlinger.disableExpensiveRendering();
-                }) {}
+PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger) : mFlinger(flinger) {
+    if (getUpdateTimeout() > 0ms) {
+        mScreenUpdateTimer.emplace("UpdateImminentTimer", getUpdateTimeout(),
+                                   /* resetCallback */ nullptr,
+                                   /* timeoutCallback */
+                                   [this] {
+                                       while (true) {
+                                           auto timeSinceLastUpdate = std::chrono::nanoseconds(
+                                                   systemTime() - mLastScreenUpdatedTime.load());
+                                           if (timeSinceLastUpdate >= getUpdateTimeout()) {
+                                               break;
+                                           }
+                                           // We may try to disable expensive rendering and allow
+                                           // for sending DISPLAY_UPDATE_IMMINENT hints too early if
+                                           // we idled very shortly after updating the screen, so
+                                           // make sure we wait enough time.
+                                           std::this_thread::sleep_for(getUpdateTimeout() -
+                                                                       timeSinceLastUpdate);
+                                       }
+                                       mSendUpdateImminent.store(true);
+                                       mFlinger.disableExpensiveRendering();
+                                   });
+    }
+}
 
 void PowerAdvisor::init() {
     // Defer starting the screen update timer until SurfaceFlinger finishes construction.
-    if (mUseScreenUpdateTimer) {
-        mScreenUpdateTimer.start();
+    if (mScreenUpdateTimer) {
+        mScreenUpdateTimer->start();
     }
 }
 
@@ -135,7 +149,7 @@
         return;
     }
 
-    if (mSendUpdateImminent.load()) {
+    if (mSendUpdateImminent.exchange(false)) {
         std::lock_guard lock(mPowerHalMutex);
         HalWrapper* const halWrapper = getPowerHal();
         if (halWrapper == nullptr) {
@@ -147,10 +161,18 @@
             mReconnectPowerHal = true;
             return;
         }
+
+        if (mScreenUpdateTimer) {
+            mScreenUpdateTimer->reset();
+        } else {
+            // If we don't have a screen update timer, then we don't throttle power hal calls so
+            // flip this bit back to allow for calling into power hal again.
+            mSendUpdateImminent.store(true);
+        }
     }
 
-    if (mUseScreenUpdateTimer) {
-        mScreenUpdateTimer.reset();
+    if (mScreenUpdateTimer) {
+        mLastScreenUpdatedTime.store(systemTime());
     }
 }
 
@@ -165,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;
 }
@@ -174,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;
@@ -183,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;
 }
@@ -222,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)) {}
@@ -303,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() {
@@ -310,7 +650,7 @@
         mPowerHintSession->close();
         mPowerHintSession = nullptr;
     }
-};
+}
 
 std::unique_ptr<PowerAdvisor::HalWrapper> AidlPowerHalWrapper::connect() {
     // This only waits if the service is actually declared
@@ -348,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;
 }
@@ -402,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());
@@ -434,75 +758,53 @@
     }
 }
 
-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 will go stale next frame
     if (!mLastActualDurationSent.has_value() ||
-        (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
+        (mLastTargetDurationSent + systemTime() - mLastActualReportTimestamp) >
+                kStaleTimeout.count()) {
         return true;
     }
 
     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);
@@ -512,8 +814,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;
     }
 }
 
@@ -529,12 +831,13 @@
     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;
@@ -543,7 +846,7 @@
         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;
 
@@ -560,14 +863,15 @@
 
     if (sHalWrapper != nullptr) {
         auto wrapper = sHalWrapper.get();
-        // if the wrapper is fine, return it, but if it indicates a reconnect, remake it
+        // 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;
     }
 
-    // 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
@@ -576,13 +880,14 @@
     // If that didn't succeed, attempt to connect to the HIDL Power HAL
     if (sHalWrapper == nullptr) {
         sHalWrapper = HidlPowerHalWrapper::connect();
-    } else { // if AIDL, pass on any existing hint session values
-        // thread ids always safe to set
+    } else {
+        ALOGD("Successfully connecting AIDL Power HAL");
+        // If AIDL, pass on any existing hint session values
         sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
-        // only set duration and start if duration is defined
+        // 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
+            // Only start if possible to run and both threadids and duration are defined
             if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) {
                 mPowerHintSessionRunning = sHalWrapper->startPowerHintSession();
             }
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 61bb32b..859cf3d 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,10 +129,29 @@
     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:
     HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex);
@@ -100,23 +159,118 @@
     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;
 
     SurfaceFlinger& mFlinger;
-    const bool mUseScreenUpdateTimer;
     std::atomic_bool mSendUpdateImminent = true;
-    scheduler::OneShotTimer mScreenUpdateTimer;
+    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,52 +287,52 @@
     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
+    // actually 100ms but we use 80 here to give some slack
     static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
 };
 
diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp
index e8c590e..d8bbc30 100644
--- a/services/surfaceflinger/EffectLayer.cpp
+++ b/services/surfaceflinger/EffectLayer.cpp
@@ -74,7 +74,7 @@
 }
 
 bool EffectLayer::isVisible() const {
-    return !isHiddenByPolicy() && (getAlpha() > 0.0_hf || hasBlur()) && hasSomethingToDraw();
+    return hasSomethingToDraw() && !isHiddenByPolicy() && (getAlpha() > 0.0_hf || hasBlur());
 }
 
 bool EffectLayer::setColor(const half3& color) {
@@ -144,7 +144,7 @@
 sp<Layer> EffectLayer::createClone() {
     sp<EffectLayer> layer = mFlinger->getFactory().createEffectLayer(
             LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()));
-    layer->setInitialValuesForClone(this);
+    layer->setInitialValuesForClone(sp<Layer>::fromExisting(this));
     return layer;
 }
 
diff --git a/services/surfaceflinger/FlagManager.cpp b/services/surfaceflinger/FlagManager.cpp
index bd3cf74..f8ad8f6 100644
--- a/services/surfaceflinger/FlagManager.cpp
+++ b/services/surfaceflinger/FlagManager.cpp
@@ -96,7 +96,8 @@
 }
 
 bool FlagManager::use_adpf_cpu_hint() const {
-    std::optional<bool> sysPropVal = std::nullopt;
+    std::optional<bool> sysPropVal =
+            doParse<bool>(base::GetProperty("debug.sf.enable_adpf_cpu_hint", "").c_str());
     return getValue("AdpfFeature__adpf_cpu_hint", sysPropVal, false);
 }
 
diff --git a/services/surfaceflinger/FpsReporter.cpp b/services/surfaceflinger/FpsReporter.cpp
index c89c9ff..155cf4d 100644
--- a/services/surfaceflinger/FpsReporter.cpp
+++ b/services/surfaceflinger/FpsReporter.cpp
@@ -63,7 +63,8 @@
                 for (TrackedListener& listener : localListeners) {
                     if (listener.taskId == taskId) {
                         seenTasks.insert(taskId);
-                        listenersAndLayersToReport.push_back({listener, sp<Layer>(layer)});
+                        listenersAndLayersToReport.push_back(
+                                {listener, sp<Layer>::fromExisting(layer)});
                         break;
                     }
                 }
@@ -90,7 +91,7 @@
 
 void FpsReporter::addListener(const sp<gui::IFpsListener>& listener, int32_t taskId) {
     sp<IBinder> asBinder = IInterface::asBinder(listener);
-    asBinder->linkToDeath(this);
+    asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
     std::lock_guard lock(mMutex);
     mListeners.emplace(wp<IBinder>(asBinder), TrackedListener{listener, taskId});
 }
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 66beff2..c73a75c 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -109,11 +109,11 @@
         jankType &= ~JankType::DisplayHAL;
     }
     if (jankType & JankType::SurfaceFlingerCpuDeadlineMissed) {
-        janks.emplace_back("SurfaceFlinger CPU Deadline Missed");
+        janks.emplace_back("SurfaceFlinger deadline missed (while in HWC)");
         jankType &= ~JankType::SurfaceFlingerCpuDeadlineMissed;
     }
     if (jankType & JankType::SurfaceFlingerGpuDeadlineMissed) {
-        janks.emplace_back("SurfaceFlinger GPU Deadline Missed");
+        janks.emplace_back("SurfaceFlinger deadline missed (while in GPU comp)");
         jankType &= ~JankType::SurfaceFlingerGpuDeadlineMissed;
     }
     if (jankType & JankType::AppDeadlineMissed) {
@@ -289,7 +289,7 @@
         minTime = std::min(minTime, actuals.endTime);
     }
     if (actuals.presentTime != 0) {
-        minTime = std::min(minTime, actuals.endTime);
+        minTime = std::min(minTime, actuals.presentTime);
     }
     return minTime;
 }
@@ -986,11 +986,8 @@
                                     mJankClassificationThresholds.presentThreshold) {
                     // Classify CPU vs GPU if SF wasn't stuffed or if SF was stuffed but this frame
                     // was presented more than a vsync late.
-                    if (mGpuFence != FenceTime::NO_FENCE &&
-                        mSurfaceFlingerActuals.endTime - mSurfaceFlingerActuals.startTime <
-                                mRefreshRate.getPeriodNsecs()) {
-                        // If SF was in GPU composition and the CPU work finished before the vsync
-                        // period, classify it as GPU deadline missed.
+                    if (mGpuFence != FenceTime::NO_FENCE) {
+                        // If SF was in GPU composition, classify it as GPU deadline missed.
                         mJankType = JankType::SurfaceFlingerGpuDeadlineMissed;
                     } else {
                         mJankType = JankType::SurfaceFlingerCpuDeadlineMissed;
diff --git a/services/surfaceflinger/HdrLayerInfoReporter.cpp b/services/surfaceflinger/HdrLayerInfoReporter.cpp
index c06e300..c88554e 100644
--- a/services/surfaceflinger/HdrLayerInfoReporter.cpp
+++ b/services/surfaceflinger/HdrLayerInfoReporter.cpp
@@ -51,7 +51,7 @@
 
 void HdrLayerInfoReporter::addListener(const sp<gui::IHdrLayerInfoListener>& listener) {
     sp<IBinder> asBinder = IInterface::asBinder(listener);
-    asBinder->linkToDeath(this);
+    asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
     std::lock_guard lock(mMutex);
     mListeners.emplace(wp<IBinder>(asBinder), TrackedListener{listener, HdrLayerInfo{}});
 }
diff --git a/services/surfaceflinger/HwcSlotGenerator.cpp b/services/surfaceflinger/HwcSlotGenerator.cpp
new file mode 100644
index 0000000..939c35b
--- /dev/null
+++ b/services/surfaceflinger/HwcSlotGenerator.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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 "HwcSlotGenerator"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <gui/BufferQueue.h>
+
+#include "HwcSlotGenerator.h"
+
+namespace android {
+
+HwcSlotGenerator::HwcSlotGenerator() {
+    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        mFreeHwcCacheSlots.push(i);
+    }
+}
+
+void HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) {
+    std::lock_guard lock(mMutex);
+    if (!clientCacheId.isValid()) {
+        ALOGE("invalid process, failed to erase buffer");
+        return;
+    }
+    eraseBufferLocked(clientCacheId);
+}
+
+int HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    auto itr = mCachedBuffers.find(clientCacheId);
+    if (itr == mCachedBuffers.end()) {
+        return addCachedBuffer(clientCacheId);
+    }
+    auto& [hwcCacheSlot, counter] = itr->second;
+    counter = mCounter++;
+    return hwcCacheSlot;
+}
+
+int HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex) {
+    if (!clientCacheId.isValid()) {
+        ALOGE("invalid process, returning invalid slot");
+        return BufferQueue::INVALID_BUFFER_SLOT;
+    }
+
+    ClientCache::getInstance().registerErasedRecipient(clientCacheId,
+                                                       wp<ErasedRecipient>::fromExisting(this));
+
+    int hwcCacheSlot = getFreeHwcCacheSlot();
+    mCachedBuffers[clientCacheId] = {hwcCacheSlot, mCounter++};
+    return hwcCacheSlot;
+}
+
+int HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) {
+    if (mFreeHwcCacheSlots.empty()) {
+        evictLeastRecentlyUsed();
+    }
+
+    int hwcCacheSlot = mFreeHwcCacheSlots.top();
+    mFreeHwcCacheSlots.pop();
+    return hwcCacheSlot;
+}
+
+void HwcSlotGenerator::evictLeastRecentlyUsed() REQUIRES(mMutex) {
+    uint64_t minCounter = UINT_MAX;
+    client_cache_t minClientCacheId = {};
+    for (const auto& [clientCacheId, slotCounter] : mCachedBuffers) {
+        const auto& [hwcCacheSlot, counter] = slotCounter;
+        if (counter < minCounter) {
+            minCounter = counter;
+            minClientCacheId = clientCacheId;
+        }
+    }
+    eraseBufferLocked(minClientCacheId);
+
+    ClientCache::getInstance().unregisterErasedRecipient(minClientCacheId,
+                                                         wp<ErasedRecipient>::fromExisting(this));
+}
+
+void HwcSlotGenerator::eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex) {
+    auto itr = mCachedBuffers.find(clientCacheId);
+    if (itr == mCachedBuffers.end()) {
+        return;
+    }
+    auto& [hwcCacheSlot, counter] = itr->second;
+
+    // TODO send to hwc cache and resources
+
+    mFreeHwcCacheSlots.push(hwcCacheSlot);
+    mCachedBuffers.erase(clientCacheId);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/HwcSlotGenerator.h b/services/surfaceflinger/HwcSlotGenerator.h
new file mode 100644
index 0000000..5a1b6d7
--- /dev/null
+++ b/services/surfaceflinger/HwcSlotGenerator.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <functional>
+#include <mutex>
+#include <stack>
+#include <unordered_map>
+
+#include "ClientCache.h"
+
+namespace android {
+
+class HwcSlotGenerator : public ClientCache::ErasedRecipient {
+public:
+    HwcSlotGenerator();
+    void bufferErased(const client_cache_t& clientCacheId);
+    int getHwcCacheSlot(const client_cache_t& clientCacheId);
+
+private:
+    friend class SlotGenerationTest;
+    int addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex);
+    int getFreeHwcCacheSlot() REQUIRES(mMutex);
+    void evictLeastRecentlyUsed() REQUIRES(mMutex);
+    void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex);
+
+    struct CachedBufferHash {
+        std::size_t operator()(const client_cache_t& clientCacheId) const {
+            return std::hash<uint64_t>{}(clientCacheId.id);
+        }
+    };
+
+    std::mutex mMutex;
+
+    std::unordered_map<client_cache_t, std::pair<int /*HwcCacheSlot*/, uint64_t /*counter*/>,
+                       CachedBufferHash>
+            mCachedBuffers GUARDED_BY(mMutex);
+    std::stack<int /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex);
+
+    // The cache increments this counter value when a slot is updated or used.
+    // Used to track the least recently-used buffer
+    uint64_t mCounter = 0;
+};
+} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 791ab06..5e1a858 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -47,6 +47,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <sys/types.h>
+#include <system/graphics-base-v1.0.h>
 #include <ui/DataspaceUtils.h>
 #include <ui/DebugUtils.h>
 #include <ui/GraphicBuffer.h>
@@ -61,7 +62,6 @@
 #include <mutex>
 #include <sstream>
 
-#include "BufferLayer.h"
 #include "Colorizer.h"
 #include "DisplayDevice.h"
 #include "DisplayHardware/HWComposer.h"
@@ -69,8 +69,6 @@
 #include "FrameTimeline.h"
 #include "FrameTracer/FrameTracer.h"
 #include "LayerProtoHelper.h"
-#include "LayerRejecter.h"
-#include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
 #include "TimeStats/TimeStats.h"
 #include "TunnelModeEnabledReporter.h"
@@ -80,6 +78,7 @@
 namespace android {
 namespace {
 constexpr int kDumpTableRowLength = 159;
+const ui::Transform kIdentityTransform;
 } // namespace
 
 using namespace ftl::flag_operators;
@@ -95,12 +94,13 @@
 
 Layer::Layer(const LayerCreationArgs& args)
       : sequence(args.sequence.value_or(sSequence++)),
-        mFlinger(args.flinger),
+        mFlinger(sp<SurfaceFlinger>::fromExisting(args.flinger)),
         mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)),
         mClientRef(args.client),
         mWindowType(static_cast<WindowInfo::Type>(
                 args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))),
-        mLayerCreationFlags(args.flags) {
+        mLayerCreationFlags(args.flags),
+        mBorderEnabled(false) {
     uint32_t layerFlags = 0;
     if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
     if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
@@ -146,6 +146,7 @@
     mDrawingState.isTrustedOverlay = false;
     mDrawingState.dropInputMode = gui::DropInputMode::NONE;
     mDrawingState.dimmingEnabled = true;
+    mDrawingState.defaultFrameRateCompatibility = FrameRateCompatibility::Default;
 
     if (args.flags & ISurfaceComposerClient::eNoColorFill) {
         // Set an invalid color so there is no color fill.
@@ -154,10 +155,8 @@
         mDrawingState.color.b = -1.0_hf;
     }
 
-    CompositorTiming compositorTiming;
-    args.flinger->getCompositorTiming(&compositorTiming);
-    mFrameEventHistory.initializeCompositorTiming(compositorTiming);
-    mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval);
+    mFrameTracker.setDisplayRefreshPeriod(
+            args.flinger->mScheduler->getVsyncPeriodFromRefreshRateConfigs());
 
     mCallingPid = args.callingPid;
     mCallingUid = args.callingUid;
@@ -215,8 +214,7 @@
  * Layer.  So, the implementation is done in BufferLayer.  When called on a
  * EffectLayer object, it's essentially a NOP.
  */
-void Layer::onLayerDisplayed(
-        std::shared_future<renderengine::RenderEngineResult> /*futureRenderEngineResult*/) {}
+void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult>) {}
 
 void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
     if (mDrawingState.zOrderRelativeOf == nullptr) {
@@ -230,7 +228,7 @@
     }
 
     if (!std::binary_search(layersInTree.begin(), layersInTree.end(), strongRelative.get())) {
-        strongRelative->removeZOrderRelative(this);
+        strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this));
         mFlinger->setTransactionFlags(eTraversalNeeded);
         setZOrderRelativeOf(nullptr);
     }
@@ -242,13 +240,13 @@
         mFlinger->mScheduler->deregisterLayer(this);
     }
 
-    mFlinger->markLayerPendingRemovalLocked(this);
+    mFlinger->markLayerPendingRemovalLocked(sp<Layer>::fromExisting(this));
 }
 
 sp<Layer> Layer::getRootLayer() {
     sp<Layer> parent = getParent();
     if (parent == nullptr) {
-        return this;
+        return sp<Layer>::fromExisting(this);
     }
     return parent->getRootLayer();
 }
@@ -291,7 +289,7 @@
         return nullptr;
     }
     mGetHandleCalled = true;
-    return new Handle(mFlinger, this);
+    return sp<Handle>::make(mFlinger, sp<Layer>::fromExisting(this));
 }
 
 // ---------------------------------------------------------------------------
@@ -410,7 +408,7 @@
     const auto& drawingState{getDrawingState()};
     const auto alpha = static_cast<float>(getAlpha());
     const bool opaque = isOpaque(drawingState);
-    const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
+    const bool usesRoundedCorners = hasRoundedCorners();
 
     auto blendMode = Hwc2::IComposerClient::BlendMode::NONE;
     if (!opaque || alpha != 1.0f) {
@@ -486,7 +484,7 @@
     compositionState->hasProtectedContent = isProtected();
     compositionState->dimmingEnabled = isDimmingEnabled();
 
-    const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
+    const bool usesRoundedCorners = hasRoundedCorners();
 
     compositionState->isOpaque =
             isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
@@ -523,8 +521,9 @@
 }
 
 sp<compositionengine::LayerFE> Layer::asLayerFE() const {
-    return const_cast<compositionengine::LayerFE*>(
+    compositionengine::LayerFE* layerFE = const_cast<compositionengine::LayerFE*>(
             static_cast<const compositionengine::LayerFE*>(this));
+    return sp<compositionengine::LayerFE>::fromExisting(layerFE);
 }
 
 sp<compositionengine::LayerFE> Layer::getCompositionEngineLayerFE() const {
@@ -603,6 +602,18 @@
     layerSettings.alpha = alpha;
     layerSettings.sourceDataspace = getDataSpace();
 
+    // Override the dataspace transfer from 170M to sRGB if the device configuration requests this.
+    // We do this here instead of in buffer info so that dumpsys can still report layers that are
+    // using the 170M transfer.
+    if (mFlinger->mTreat170mAsSrgb &&
+        (layerSettings.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) ==
+                HAL_DATASPACE_TRANSFER_SMPTE_170M) {
+        layerSettings.sourceDataspace = static_cast<ui::Dataspace>(
+                (layerSettings.sourceDataspace & HAL_DATASPACE_STANDARD_MASK) |
+                (layerSettings.sourceDataspace & HAL_DATASPACE_RANGE_MASK) |
+                HAL_DATASPACE_TRANSFER_SRGB);
+    }
+
     layerSettings.whitePointNits = targetSettings.whitePointNits;
     switch (targetSettings.blurSetting) {
         case LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled:
@@ -713,7 +724,7 @@
 
     if (s.sequence != mLastCommittedTxSequence) {
         // invalidate and recompute the visible regions if needed
-         mLastCommittedTxSequence = s.sequence;
+        mLastCommittedTxSequence = s.sequence;
         flags |= eVisibleRegion;
         this->contentDirty = true;
 
@@ -721,6 +732,10 @@
         mNeedsFiltering = getActiveTransform(s).needsBilinearFiltering();
     }
 
+    if (!mPotentialCursor && (flags & Layer::eVisibleRegion)) {
+        mFlinger->mUpdateInputInfo = true;
+    }
+
     commitTransaction(mDrawingState);
 
     return flags;
@@ -799,7 +814,7 @@
     if (mDrawingState.zOrderRelativeOf != nullptr) {
         sp<Layer> strongRelative = mDrawingState.zOrderRelativeOf.promote();
         if (strongRelative != nullptr) {
-            strongRelative->removeZOrderRelative(this);
+            strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this));
         }
         setZOrderRelativeOf(nullptr);
     }
@@ -857,10 +872,10 @@
 
     auto oldZOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote();
     if (oldZOrderRelativeOf != nullptr) {
-        oldZOrderRelativeOf->removeZOrderRelative(this);
+        oldZOrderRelativeOf->removeZOrderRelative(wp<Layer>::fromExisting(this));
     }
     setZOrderRelativeOf(relative);
-    relative->addZOrderRelative(this);
+    relative->addZOrderRelative(wp<Layer>::fromExisting(this));
 
     setTransactionFlags(eTransactionNeeded);
 
@@ -871,7 +886,7 @@
     if (mDrawingState.isTrustedOverlay == isTrustedOverlay) return false;
     mDrawingState.isTrustedOverlay = isTrustedOverlay;
     mDrawingState.modified = true;
-    mFlinger->mInputInfoChanged = true;
+    mFlinger->mUpdateInputInfo = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -968,6 +983,13 @@
     return true;
 }
 bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
+    if (matrix.dsdx == mDrawingState.transform.dsdx() &&
+        matrix.dtdy == mDrawingState.transform.dtdy() &&
+        matrix.dtdx == mDrawingState.transform.dtdx() &&
+        matrix.dsdy == mDrawingState.transform.dsdy()) {
+        return false;
+    }
+
     ui::Transform t;
     t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
 
@@ -1079,6 +1101,19 @@
     return Layer::PRIORITY_UNSET;
 }
 
+bool Layer::setDefaultFrameRateCompatibility(FrameRateCompatibility compatibility) {
+    if (mDrawingState.defaultFrameRateCompatibility == compatibility) return false;
+    mDrawingState.defaultFrameRateCompatibility = compatibility;
+    mDrawingState.modified = true;
+    mFlinger->mScheduler->setDefaultFrameRateCompatibility(this);
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+scheduler::LayerInfo::FrameRateCompatibility Layer::getDefaultFrameRateCompatibility() const {
+    return mDrawingState.defaultFrameRateCompatibility;
+}
+
 bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) {
     return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE;
 };
@@ -1143,6 +1178,28 @@
     return StretchEffect{};
 }
 
+bool Layer::enableBorder(bool shouldEnable, float width, const half4& color) {
+    if (mBorderEnabled == shouldEnable && mBorderWidth == width && mBorderColor == color) {
+        return false;
+    }
+    mBorderEnabled = shouldEnable;
+    mBorderWidth = width;
+    mBorderColor = color;
+    return true;
+}
+
+bool Layer::isBorderEnabled() {
+    return mBorderEnabled;
+}
+
+float Layer::getBorderWidth() {
+    return mBorderWidth;
+}
+
+const half4& Layer::getBorderColor() {
+    return mBorderColor;
+}
+
 bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded) {
     // The frame rate for layer tree is this layer's frame rate if present, or the parent frame rate
     const auto frameRate = [&] {
@@ -1185,7 +1242,7 @@
 
 void Layer::updateTreeHasFrameRateVote() {
     const auto root = [&]() -> sp<Layer> {
-        sp<Layer> layer = this;
+        sp<Layer> layer = sp<Layer>::fromExisting(this);
         while (auto parent = layer->getParent()) {
             layer = parent;
         }
@@ -1522,53 +1579,17 @@
     mFrameTracker.getStats(outStats);
 }
 
-void Layer::dumpFrameEvents(std::string& result) {
-    StringAppendF(&result, "- Layer %s (%s, %p)\n", getName().c_str(), getType(), this);
-    Mutex::Autolock lock(mFrameEventHistoryMutex);
-    mFrameEventHistory.checkFencesForCompletion();
-    mFrameEventHistory.dump(result);
-}
-
 void Layer::dumpCallingUidPid(std::string& result) const {
     StringAppendF(&result, "Layer %s (%s) callingPid:%d callingUid:%d ownerUid:%d\n",
                   getName().c_str(), getType(), mCallingPid, mCallingUid, mOwnerUid);
 }
 
 void Layer::onDisconnect() {
-    Mutex::Autolock lock(mFrameEventHistoryMutex);
-    mFrameEventHistory.onDisconnect();
     const int32_t layerId = getSequence();
     mFlinger->mTimeStats->onDestroy(layerId);
     mFlinger->mFrameTracer->onDestroy(layerId);
 }
 
-void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
-                                     FrameEventHistoryDelta* outDelta) {
-    if (newTimestamps) {
-        mFlinger->mTimeStats->setPostTime(getSequence(), newTimestamps->frameNumber,
-                                          getName().c_str(), mOwnerUid, newTimestamps->postedTime,
-                                          getGameMode());
-        mFlinger->mTimeStats->setAcquireFence(getSequence(), newTimestamps->frameNumber,
-                                              newTimestamps->acquireFence);
-    }
-
-    Mutex::Autolock lock(mFrameEventHistoryMutex);
-    if (newTimestamps) {
-        // If there are any unsignaled fences in the aquire timeline at this
-        // point, the previously queued frame hasn't been latched yet. Go ahead
-        // and try to get the signal time here so the syscall is taken out of
-        // the main thread's critical path.
-        mAcquireTimeline.updateSignalTimes();
-        // Push the new fence after updating since it's likely still pending.
-        mAcquireTimeline.push(newTimestamps->acquireFence);
-        mFrameEventHistory.addQueue(*newTimestamps);
-    }
-
-    if (outDelta) {
-        mFrameEventHistory.getAndResetDelta(outDelta);
-    }
-}
-
 size_t Layer::getChildrenCount() const {
     size_t count = 0;
     for (const sp<Layer>& child : mCurrentChildren) {
@@ -1594,7 +1615,7 @@
     setTransactionFlags(eTransactionNeeded);
 
     mCurrentChildren.add(layer);
-    layer->setParent(this);
+    layer->setParent(sp<Layer>::fromExisting(this));
     layer->setGameModeForTree(mGameMode);
     updateTreeHasFrameRateVote();
 }
@@ -1616,8 +1637,10 @@
 void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
     for (const sp<Layer>& child : mDrawingChildren) {
         child->mDrawingParent = newParent;
+        const float parentShadowRadius =
+                newParent->canDrawShadows() ? 0.f : newParent->mEffectiveShadowRadius;
         child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform,
-                             newParent->mEffectiveShadowRadius);
+                             parentShadowRadius);
     }
 }
 
@@ -1637,11 +1660,11 @@
 
     sp<Layer> parent = getParent();
     if (parent != nullptr) {
-        parent->removeChild(this);
+        parent->removeChild(sp<Layer>::fromExisting(this));
     }
 
     if (newParentHandle != nullptr) {
-        newParent->addChild(this);
+        newParent->addChild(sp<Layer>::fromExisting(this));
         if (!newParent->isRemovedFromCurrentState()) {
             addToCurrentState();
         } else {
@@ -1923,8 +1946,11 @@
 }
 
 int32_t Layer::getBackgroundBlurRadius() const {
-    const auto& p = mDrawingParent.promote();
+    if (getDrawingState().backgroundBlurRadius == 0) {
+        return 0;
+    }
 
+    const auto& p = mDrawingParent.promote();
     half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
     return parentAlpha * getDrawingState().backgroundBlurRadius;
 }
@@ -1944,27 +1970,22 @@
     const auto& parent = mDrawingParent.promote();
     if (parent != nullptr) {
         parentSettings = parent->getRoundedCornerState();
-        if (parentSettings.radius > 0) {
+        if (parentSettings.hasRoundedCorners()) {
             ui::Transform t = getActiveTransform(getDrawingState());
             t = t.inverse();
             parentSettings.cropRect = t.transform(parentSettings.cropRect);
-            // The rounded corners shader only accepts 1 corner radius for performance reasons,
-            // but a transform matrix can define horizontal and vertical scales.
-            // Let's take the average between both of them and pass into the shader, practically we
-            // never do this type of transformation on windows anyway.
-            auto scaleX = sqrtf(t[0][0] * t[0][0] + t[0][1] * t[0][1]);
-            auto scaleY = sqrtf(t[1][0] * t[1][0] + t[1][1] * t[1][1]);
-            parentSettings.radius *= (scaleX + scaleY) / 2.0f;
+            parentSettings.radius.x *= t.getScaleX();
+            parentSettings.radius.y *= t.getScaleY();
         }
     }
 
     // Get layer settings
     Rect layerCropRect = getCroppedBufferSize(getDrawingState());
-    const float radius = getDrawingState().cornerRadius;
+    const vec2 radius(getDrawingState().cornerRadius, getDrawingState().cornerRadius);
     RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius);
-    const bool layerSettingsValid = layerSettings.radius > 0 && layerCropRect.isValid();
+    const bool layerSettingsValid = layerSettings.hasRoundedCorners() && layerCropRect.isValid();
 
-    if (layerSettingsValid && parentSettings.radius > 0) {
+    if (layerSettingsValid && parentSettings.hasRoundedCorners()) {
         // If the parent and the layer have rounded corner settings, use the parent settings if the
         // parent crop is entirely inside the layer crop.
         // This has limitations and cause rendering artifacts. See b/200300845 for correct fix.
@@ -1978,7 +1999,7 @@
         }
     } else if (layerSettingsValid) {
         return layerSettings;
-    } else if (parentSettings.radius > 0) {
+    } else if (parentSettings.hasRoundedCorners()) {
         return parentSettings;
     }
     return {};
@@ -2044,7 +2065,7 @@
                   zOrderRelativeOf->mName.c_str());
             ALOGE("Severing rel Z loop, potentially dangerous");
             mDrawingState.isRelativeOf = false;
-            zOrderRelativeOf->removeZOrderRelative(this);
+            zOrderRelativeOf->removeZOrderRelative(wp<Layer>::fromExisting(this));
         }
     }
 }
@@ -2054,7 +2075,7 @@
     mDrawingState.inputInfo = info;
     mDrawingState.touchableRegionCrop = fromHandle(info.touchableRegionCropHandle.promote());
     mDrawingState.modified = true;
-    mFlinger->mInputInfoChanged = true;
+    mFlinger->mUpdateInputInfo = true;
     setTransactionFlags(eTransactionNeeded);
 }
 
@@ -2096,10 +2117,9 @@
     layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(getDataSpace())));
     layerInfo->set_queued_frames(getQueuedFrameCount());
     layerInfo->set_curr_frame(mCurrentFrameNumber);
-    layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
-
     layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius);
-    layerInfo->set_corner_radius(getRoundedCornerState().radius);
+    layerInfo->set_corner_radius(
+            (getRoundedCornerState().radius.x + getRoundedCornerState().radius.y) / 2.0);
     layerInfo->set_background_blur_radius(getBackgroundBlurRadius());
     layerInfo->set_is_trusted_overlay(isTrustedOverlay());
     LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform());
@@ -2192,7 +2212,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;
         }
@@ -2224,6 +2245,37 @@
     return getCroppedBufferSize(getDrawingState());
 }
 
+// Applies the given transform to the region, while protecting against overflows caused by any
+// offsets. If applying the offset in the transform to any of the Rects in the region would result
+// in an overflow, they are not added to the output Region.
+static Region transformTouchableRegionSafely(const ui::Transform& t, const Region& r,
+                                             const std::string& debugWindowName) {
+    // Round the translation using the same rounding strategy used by ui::Transform.
+    const auto tx = static_cast<int32_t>(t.tx() + 0.5);
+    const auto ty = static_cast<int32_t>(t.ty() + 0.5);
+
+    ui::Transform transformWithoutOffset = t;
+    transformWithoutOffset.set(0.f, 0.f);
+
+    const Region transformed = transformWithoutOffset.transform(r);
+
+    // Apply the translation to each of the Rects in the region while discarding any that overflow.
+    Region ret;
+    for (const auto& rect : transformed) {
+        Rect newRect;
+        if (__builtin_add_overflow(rect.left, tx, &newRect.left) ||
+            __builtin_add_overflow(rect.top, ty, &newRect.top) ||
+            __builtin_add_overflow(rect.right, tx, &newRect.right) ||
+            __builtin_add_overflow(rect.bottom, ty, &newRect.bottom)) {
+            ALOGE("Applying transform to touchable region of window '%s' resulted in an overflow.",
+                  debugWindowName.c_str());
+            continue;
+        }
+        ret.orSelf(newRect);
+    }
+    return ret;
+}
+
 void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
     Rect tmpBounds = getInputBounds();
     if (!tmpBounds.isValid()) {
@@ -2286,11 +2338,12 @@
     info.transform = inputToDisplay.inverse();
 
     // The touchable region is specified in the input coordinate space. Change it to display space.
-    info.touchableRegion = inputToDisplay.transform(info.touchableRegion);
+    info.touchableRegion =
+            transformTouchableRegionSafely(inputToDisplay, info.touchableRegion, mName);
 }
 
 void Layer::fillTouchOcclusionMode(WindowInfo& info) {
-    sp<Layer> p = this;
+    sp<Layer> p = sp<Layer>::fromExisting(this);
     while (p != nullptr && !p->hasInputInfo()) {
         p = p->mDrawingParent.promote();
     }
@@ -2367,7 +2420,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;
@@ -2376,12 +2429,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
@@ -2399,7 +2461,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;
     }
 
@@ -2421,6 +2483,7 @@
     // If the layer is a clone, we need to crop the input region to cloned root to prevent
     // touches from going outside the cloned area.
     if (isClone()) {
+        info.inputConfig |= WindowInfo::InputConfig::CLONE;
         if (const sp<Layer> clonedRoot = getClonedRoot()) {
             const Rect rect = displayTransform.transform(Rect{clonedRoot->mScreenBounds});
             info.touchableRegion = info.touchableRegion.intersect(rect);
@@ -2432,7 +2495,7 @@
 
 sp<Layer> Layer::getClonedRoot() {
     if (mClonedChild != nullptr) {
-        return this;
+        return sp<Layer>::fromExisting(this);
     }
     if (mDrawingParent == nullptr || mDrawingParent.promote() == nullptr) {
         return nullptr;
@@ -2486,7 +2549,7 @@
     }
 
     mClonedChild->updateClonedDrawingState(clonedLayersMap);
-    mClonedChild->updateClonedChildren(this, clonedLayersMap);
+    mClonedChild->updateClonedChildren(sp<Layer>::fromExisting(this), clonedLayersMap);
     mClonedChild->updateClonedRelatives(clonedLayersMap);
 }
 
@@ -2497,7 +2560,7 @@
     if (isClonedFromAlive()) {
         sp<Layer> clonedFrom = getClonedFrom();
         cloneDrawingState(clonedFrom.get());
-        clonedLayersMap.emplace(clonedFrom, this);
+        clonedLayersMap.emplace(clonedFrom, sp<Layer>::fromExisting(this));
     }
 
     // The clone layer may have children in drawingState since they may have been created and
@@ -2541,7 +2604,7 @@
         if (clonedLayersMap.count(cropLayer) == 0) {
             // Real layer had a crop layer but it's not in the cloned hierarchy. Just set to
             // self as crop layer to avoid going outside bounds.
-            mDrawingState.touchableRegionCrop = this;
+            mDrawingState.touchableRegionCrop = wp<Layer>::fromExisting(this);
         } else {
             const sp<Layer>& clonedCropLayer = clonedLayersMap.at(cropLayer);
             mDrawingState.touchableRegionCrop = clonedCropLayer;
@@ -2553,7 +2616,7 @@
 }
 
 void Layer::updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
-    mDrawingState.zOrderRelativeOf = nullptr;
+    mDrawingState.zOrderRelativeOf = wp<Layer>();
     mDrawingState.zOrderRelatives.clear();
 
     if (!isClonedFromAlive()) {
@@ -2589,7 +2652,7 @@
 
 void Layer::addChildToDrawing(const sp<Layer>& layer) {
     mDrawingChildren.add(layer);
-    layer->mDrawingParent = this;
+    layer->mDrawingParent = sp<Layer>::fromExisting(this);
 }
 
 Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t compatibility) {
@@ -2600,6 +2663,8 @@
             return FrameRateCompatibility::ExactOrMultiple;
         case ANATIVEWINDOW_FRAME_RATE_EXACT:
             return FrameRateCompatibility::Exact;
+        case ANATIVEWINDOW_FRAME_RATE_MIN:
+            return FrameRateCompatibility::Min;
         case ANATIVEWINDOW_FRAME_RATE_NO_VOTE:
             return FrameRateCompatibility::NoVote;
         default:
@@ -2649,7 +2714,7 @@
     }
 
     // We can safely cast this binder since its local and we verified its interface descriptor.
-    sp<Handle> handle = static_cast<Handle*>(handleBinder.get());
+    sp<Handle> handle = sp<Handle>::cast(handleBinder);
     return handle->owner;
 }
 
@@ -2668,6 +2733,18 @@
     mDrawingState.callbackHandles = {};
 }
 
+bool Layer::setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) {
+    if (handles.empty()) {
+        return false;
+    }
+
+    for (const auto& handle : handles) {
+        mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle);
+    }
+
+    return true;
+}
+
 // ---------------------------------------------------------------------------
 
 std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c89b254..22bb866 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -53,7 +53,6 @@
 #include "DisplayHardware/HWComposer.h"
 #include "FrameTracker.h"
 #include "LayerVector.h"
-#include "MonitoredProducer.h"
 #include "RenderArea.h"
 #include "Scheduler/LayerInfo.h"
 #include "SurfaceFlinger.h"
@@ -137,13 +136,14 @@
 
     struct RoundedCornerState {
         RoundedCornerState() = default;
-        RoundedCornerState(FloatRect cropRect, float radius)
+        RoundedCornerState(const FloatRect& cropRect, const vec2& radius)
               : cropRect(cropRect), radius(radius) {}
 
         // Rounded rectangle in local layer coordinate space.
         FloatRect cropRect = FloatRect();
         // Radius of the rounded rectangle.
-        float radius = 0.0f;
+        vec2 radius;
+        bool hasRoundedCorners() const { return radius.x > 0.0f && radius.y > 0.0f; }
     };
 
     using FrameRate = scheduler::LayerInfo::FrameRate;
@@ -235,6 +235,9 @@
         // Priority of the layer assigned by Window Manager.
         int32_t frameRateSelectionPriority;
 
+        // Default frame rate compatibility used to set the layer refresh rate votetype.
+        FrameRateCompatibility defaultFrameRateCompatibility;
+
         FrameRate frameRate;
 
         // The combined frame rate of parents / children of this layer
@@ -434,16 +437,11 @@
     virtual bool setApi(int32_t /*api*/) { return false; };
     virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
     virtual bool setTransactionCompletedListeners(
-            const std::vector<sp<CallbackHandle>>& /*handles*/) {
-        return false;
-    };
-    virtual bool addFrameEvent(const sp<Fence>& /*acquireFence*/, nsecs_t /*postedTime*/,
-                               nsecs_t /*requestedPresentTime*/) {
-        return false;
-    }
+            const std::vector<sp<CallbackHandle>>& /*handles*/);
     virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
     virtual bool setColorSpaceAgnostic(const bool agnostic);
     virtual bool setDimmingEnabled(const bool dimmingEnabled);
+    virtual bool setDefaultFrameRateCompatibility(FrameRateCompatibility compatibility);
     virtual bool setFrameRateSelectionPriority(int32_t priority);
     virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
     virtual void setAutoRefresh(bool /* autoRefresh */) {}
@@ -452,6 +450,9 @@
     //  If the variable is not set on the layer, it traverses up the tree to inherit the frame
     //  rate priority from its parent.
     virtual int32_t getFrameRateSelectionPriority() const;
+    //
+    virtual FrameRateCompatibility getDefaultFrameRateCompatibility() const;
+    //
     virtual ui::Dataspace getDataSpace() const { return ui::Dataspace::UNKNOWN; }
 
     virtual sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const;
@@ -527,8 +528,6 @@
 
     virtual bool isHdrY410() const { return false; }
 
-    virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
-
     /*
      * called after composition.
      * returns true if the layer latched a new buffer this frame.
@@ -541,17 +540,13 @@
     // If a buffer was replaced this frame, release the former buffer
     virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
 
-    virtual void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
-                                           const CompositorTiming& /*compositorTiming*/) {}
-
     /*
      * latchBuffer - called each time the screen is redrawn and returns whether
      * the visible regions need to be recomputed (this is a fairly heavy
      * operation, so this should be set only if needed). Typically this is used
      * to figure out if the content or size of a surface has changed.
      */
-    virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
-                             nsecs_t /*expectedPresentTime*/) {
+    virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/) {
         return false;
     }
 
@@ -605,7 +600,7 @@
     // corner crop does not intersect with its own rounded corner crop.
     virtual RoundedCornerState getRoundedCornerState() const;
 
-    bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; }
+    bool hasRoundedCorners() const override { return getRoundedCornerState().hasRoundedCorners(); }
 
     virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
     /**
@@ -625,11 +620,11 @@
     void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
     std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
             compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
-    void onLayerDisplayed(
-            std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
+    void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override;
 
     void setWasClientComposed(const sp<Fence>& fence) override {
         mLastClientCompositionFence = fence;
+        mClearClientCompositionFenceOnLayerDisplayed = false;
     }
 
     const char* getDebugName() const override;
@@ -748,14 +743,11 @@
 
     void miniDump(std::string& result, const DisplayDevice&) const;
     void dumpFrameStats(std::string& result) const;
-    void dumpFrameEvents(std::string& result);
     void dumpCallingUidPid(std::string& result) const;
     void clearFrameStats();
     void logFrameStats();
     void getFrameStats(FrameStats* outStats) const;
     void onDisconnect();
-    void addAndGetFrameTimestamps(const NewFrameEventsEntry* newEntry,
-                                  FrameEventHistoryDelta* outDelta);
 
     ui::Transform getTransform() const;
     bool isTransformValid() const;
@@ -856,7 +848,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.
@@ -897,6 +893,10 @@
 
     bool setStretchEffect(const StretchEffect& effect);
     StretchEffect getStretchEffect() const;
+    bool enableBorder(bool shouldEnable, float width, const half4& color);
+    bool isBorderEnabled();
+    float getBorderWidth();
+    const half4& getBorderColor();
 
     virtual bool setBufferCrop(const Rect& /* bufferCrop */) { return false; }
     virtual bool setDestinationFrame(const Rect& /* destinationFrame */) { return false; }
@@ -924,11 +924,6 @@
     virtual void commitTransaction(State& stateToCommit);
     virtual void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&) {}
 
-    // Returns mCurrentScaling mode (originating from the
-    // Client) or mOverrideScalingMode mode (originating from
-    // the Surface Controller) if set.
-    virtual uint32_t getEffectiveScalingMode() const { return 0; }
-
     sp<compositionengine::LayerFE> asLayerFE() const;
     sp<Layer> getClonedFrom() { return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr; }
     bool isClone() { return mClonedFrom != nullptr; }
@@ -1000,13 +995,6 @@
     // Timestamp history for UIAutomation. Thread safe.
     FrameTracker mFrameTracker;
 
-    // Timestamp history for the consumer to query.
-    // Accessed by both consumer and producer on main and binder threads.
-    Mutex mFrameEventHistoryMutex;
-    ConsumerFrameEventHistory mFrameEventHistory;
-    FenceTimeline mAcquireTimeline;
-    FenceTimeline mReleaseTimeline;
-
     // main thread
     sp<NativeHandle> mSidebandStream;
     // False if the buffer and its contents have been previously used for GPU
@@ -1055,7 +1043,7 @@
     mutable bool mDrawingStateModified = false;
 
     sp<Fence> mLastClientCompositionFence;
-    bool mAlreadyDisplayedThisCompose = false;
+    bool mClearClientCompositionFenceOnLayerDisplayed = false;
 private:
     virtual void setTransformHint(ui::Transform::RotationFlags) {}
 
@@ -1145,7 +1133,12 @@
     bool mIsAtRoot = false;
 
     uint32_t mLayerCreationFlags;
+
     bool findInHierarchy(const sp<Layer>&);
+
+    bool mBorderEnabled = false;
+    float mBorderWidth;
+    half4 mBorderColor;
 };
 
 std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate);
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
deleted file mode 100644
index 1c0263b..0000000
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-#include "LayerRejecter.h"
-
-#include <gui/BufferItem.h>
-#include <system/window.h>
-
-#define DEBUG_RESIZE 0
-
-namespace android {
-
-LayerRejecter::LayerRejecter(Layer::State& front, Layer::State& current,
-                             bool& recomputeVisibleRegions, bool stickySet, const std::string& name,
-                             bool transformToDisplayInverse)
-      : mFront(front),
-        mCurrent(current),
-        mRecomputeVisibleRegions(recomputeVisibleRegions),
-        mStickyTransformSet(stickySet),
-        mName(name),
-        mTransformToDisplayInverse(transformToDisplayInverse) {}
-
-bool LayerRejecter::reject(const sp<GraphicBuffer>& buf, const BufferItem& item) {
-    if (buf == nullptr) {
-        return false;
-    }
-
-    uint32_t bufWidth = buf->getWidth();
-    uint32_t bufHeight = buf->getHeight();
-
-    // check that we received a buffer of the right size
-    // (Take the buffer's orientation into account)
-    if (item.mTransform & ui::Transform::ROT_90) {
-        std::swap(bufWidth, bufHeight);
-    }
-
-    if (mTransformToDisplayInverse) {
-        uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
-        if (invTransform & ui::Transform::ROT_90) {
-            std::swap(bufWidth, bufHeight);
-        }
-    }
-
-    int actualScalingMode = item.mScalingMode;
-    bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
-    if (mFront.active_legacy != mFront.requested_legacy) {
-        if (isFixedSize ||
-            (bufWidth == mFront.requested_legacy.w && bufHeight == mFront.requested_legacy.h)) {
-            // Here we pretend the transaction happened by updating the
-            // current and drawing states. Drawing state is only accessed
-            // in this thread, no need to have it locked
-            mFront.active_legacy = mFront.requested_legacy;
-
-            // We also need to update the current state so that
-            // we don't end-up overwriting the drawing state with
-            // this stale current state during the next transaction
-            //
-            // NOTE: We don't need to hold the transaction lock here
-            // because State::active_legacy is only accessed from this thread.
-            mCurrent.active_legacy = mFront.active_legacy;
-            mCurrent.modified = true;
-
-            // recompute visible region
-            mRecomputeVisibleRegions = true;
-
-            if (mFront.crop != mFront.requestedCrop) {
-                mFront.crop = mFront.requestedCrop;
-                mCurrent.crop = mFront.requestedCrop;
-                mRecomputeVisibleRegions = true;
-            }
-        }
-
-        ALOGD_IF(DEBUG_RESIZE,
-                 "[%s] latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n"
-                 "  drawing={ active_legacy   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} "
-                 "(%4d,%4d) "
-                 "}\n"
-                 "            requested_legacy={ wh={%4u,%4u} }}\n",
-                 mName.c_str(), bufWidth, bufHeight, item.mTransform, item.mScalingMode,
-                 mFront.active_legacy.w, mFront.active_legacy.h, mFront.crop.left, mFront.crop.top,
-                 mFront.crop.right, mFront.crop.bottom, mFront.crop.getWidth(),
-                 mFront.crop.getHeight(), mFront.requested_legacy.w, mFront.requested_legacy.h);
-    }
-
-    if (!isFixedSize && !mStickyTransformSet) {
-        if (mFront.active_legacy.w != bufWidth || mFront.active_legacy.h != bufHeight) {
-            // reject this buffer
-            ALOGE("[%s] rejecting buffer: "
-                  "bufWidth=%d, bufHeight=%d, front.active_legacy.{w=%d, h=%d}",
-                  mName.c_str(), bufWidth, bufHeight, mFront.active_legacy.w,
-                  mFront.active_legacy.h);
-            return true;
-        }
-    }
-
-    // if the transparent region has changed (this test is
-    // conservative, but that's fine, worst case we're doing
-    // a bit of extra work), we latch the new one and we
-    // trigger a visible-region recompute.
-    //
-    // We latch the transparent region here, instead of above where we latch
-    // the rest of the geometry because it is only content but not necessarily
-    // resize dependent.
-    if (!mFront.activeTransparentRegion_legacy.hasSameRects(
-                mFront.requestedTransparentRegion_legacy)) {
-        mFront.activeTransparentRegion_legacy = mFront.requestedTransparentRegion_legacy;
-
-        // We also need to update the current state so that
-        // we don't end-up overwriting the drawing state with
-        // this stale current state during the next transaction
-        //
-        // NOTE: We don't need to hold the transaction lock here
-        // because State::active_legacy is only accessed from this thread.
-        mCurrent.activeTransparentRegion_legacy = mFront.activeTransparentRegion_legacy;
-
-        // recompute visible region
-        mRecomputeVisibleRegions = true;
-    }
-
-    return false;
-}
-
-}  // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h
deleted file mode 100644
index 4981f45..0000000
--- a/services/surfaceflinger/LayerRejecter.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "Layer.h"
-#include "BufferLayerConsumer.h"
-
-namespace android {
-
-class LayerRejecter : public BufferLayerConsumer::BufferRejecter {
-public:
-    LayerRejecter(Layer::State& front, Layer::State& current, bool& recomputeVisibleRegions,
-                  bool stickySet, const std::string& name,
-                  bool transformToDisplayInverse);
-
-    virtual bool reject(const sp<GraphicBuffer>&, const BufferItem&);
-
-private:
-    Layer::State& mFront;
-    Layer::State& mCurrent;
-    bool& mRecomputeVisibleRegions;
-    const bool mStickyTransformSet;
-    const std::string& mName;
-    const bool mTransformToDisplayInverse;
-};
-
-} // namespace android
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index 896f254..e17b01f 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -17,8 +17,8 @@
 #include <ui/GraphicTypes.h>
 #include <ui/Transform.h>
 
-#include "ContainerLayer.h"
 #include "DisplayDevice.h"
+#include "EffectLayer.h"
 #include "Layer.h"
 #include "LayerRenderArea.h"
 #include "SurfaceFlinger.h"
@@ -110,8 +110,9 @@
         // layer which has no properties set and which does not draw.
         //  We hold the statelock as the reparent-for-drawing operation modifies the
         //  hierarchy and there could be readers on Binder threads, like dump.
-        sp<ContainerLayer> screenshotParentLayer = mFlinger.getFactory().createContainerLayer(
-                  {&mFlinger, nullptr, "Screenshot Parent"s, 0, LayerMetadata()});
+        sp<EffectLayer> screenshotParentLayer = mFlinger.getFactory().createEffectLayer(
+                {&mFlinger, nullptr, "Screenshot Parent"s, ISurfaceComposerClient::eNoColorFill,
+                 LayerMetadata()});
         {
             Mutex::Autolock _l(mFlinger.mStateLock);
             reparentForDrawing(mLayer, screenshotParentLayer, sourceCrop);
diff --git a/services/surfaceflinger/LocklessQueue.h b/services/surfaceflinger/LocklessQueue.h
new file mode 100644
index 0000000..6b63360
--- /dev/null
+++ b/services/surfaceflinger/LocklessQueue.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#pragma once
+#include <atomic>
+#include <optional>
+
+template <typename T>
+// Single consumer multi producer stack. We can understand the two operations independently to see
+// why they are without race condition.
+//
+// push is responsible for maintaining a linked list stored in mPush, and called from multiple
+// threads without lock. We can see that if two threads never observe the same value from
+// mPush.load, it just functions as a normal linked list. In the case where two threads observe the
+// same value, one of them has to execute the compare_exchange first. The one that doesn't execute
+// the compare exchange first, will receive false from compare_exchange. previousHead is updated (by
+// compare_exchange) to the most recent value of mPush, and we try again. It's relatively clear to
+// see that the process can repeat with an arbitrary number of threads.
+//
+// Pop is much simpler. If mPop is empty (as it begins) it atomically exchanges
+// the entire push list with null. This is safe, since the only other reader (push)
+// of mPush will retry if it changes in between it's read and atomic compare. We
+// then store the list and pop one element.
+//
+// If we already had something in the pop list we just pop directly.
+class LocklessQueue {
+public:
+    class Entry {
+    public:
+        T mValue;
+        std::atomic<Entry*> mNext;
+        Entry(T value) : mValue(value) {}
+    };
+    std::atomic<Entry*> mPush = nullptr;
+    std::atomic<Entry*> mPop = nullptr;
+    bool isEmpty() { return (mPush.load() == nullptr) && (mPop.load() == nullptr); }
+
+    void push(T value) {
+        Entry* entry = new Entry(value);
+        Entry* previousHead = mPush.load(/*std::memory_order_relaxed*/);
+        do {
+            entry->mNext = previousHead;
+        } while (!mPush.compare_exchange_weak(previousHead, entry)); /*std::memory_order_release*/
+    }
+    std::optional<T> pop() {
+        Entry* popped = mPop.load(/*std::memory_order_acquire*/);
+        if (popped) {
+            // Single consumer so this is fine
+            mPop.store(popped->mNext /* , std::memory_order_release */);
+            auto value = popped->mValue;
+            delete popped;
+            return std::move(value);
+        } else {
+            Entry* grabbedList = mPush.exchange(nullptr /* , std::memory_order_acquire */);
+            if (!grabbedList) return std::nullopt;
+            // Reverse the list
+            while (grabbedList->mNext) {
+                Entry* next = grabbedList->mNext;
+                grabbedList->mNext = popped;
+                popped = grabbedList;
+                grabbedList = next;
+            }
+            mPop.store(popped /* , std::memory_order_release */);
+            auto value = grabbedList->mValue;
+            delete grabbedList;
+            return std::move(value);
+        }
+    }
+};
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
deleted file mode 100644
index df76f50..0000000
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-#include "MonitoredProducer.h"
-#include "Layer.h"
-#include "SurfaceFlinger.h"
-
-#include "Scheduler/MessageQueue.h"
-
-namespace android {
-
-MonitoredProducer::MonitoredProducer(const sp<IGraphicBufferProducer>& producer,
-        const sp<SurfaceFlinger>& flinger,
-        const wp<Layer>& layer) :
-    mProducer(producer),
-    mFlinger(flinger),
-    mLayer(layer) {}
-
-MonitoredProducer::~MonitoredProducer() {}
-
-status_t MonitoredProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
-    return mProducer->requestBuffer(slot, buf);
-}
-
-status_t MonitoredProducer::setMaxDequeuedBufferCount(
-        int maxDequeuedBuffers) {
-    return mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers);
-}
-
-status_t MonitoredProducer::setAsyncMode(bool async) {
-    return mProducer->setAsyncMode(async);
-}
-
-status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
-                                          PixelFormat format, uint64_t usage,
-                                          uint64_t* outBufferAge,
-                                          FrameEventHistoryDelta* outTimestamps) {
-    return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outBufferAge, outTimestamps);
-}
-
-status_t MonitoredProducer::detachBuffer(int slot) {
-    return mProducer->detachBuffer(slot);
-}
-
-status_t MonitoredProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
-        sp<Fence>* outFence) {
-    return mProducer->detachNextBuffer(outBuffer, outFence);
-}
-
-status_t MonitoredProducer::attachBuffer(int* outSlot,
-        const sp<GraphicBuffer>& buffer) {
-    return mProducer->attachBuffer(outSlot, buffer);
-}
-
-status_t MonitoredProducer::queueBuffer(int slot, const QueueBufferInput& input,
-        QueueBufferOutput* output) {
-    return mProducer->queueBuffer(slot, input, output);
-}
-
-status_t MonitoredProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
-    return mProducer->cancelBuffer(slot, fence);
-}
-
-int MonitoredProducer::query(int what, int* value) {
-    return mProducer->query(what, value);
-}
-
-status_t MonitoredProducer::connect(const sp<IProducerListener>& listener,
-        int api, bool producerControlledByApp, QueueBufferOutput* output) {
-    return mProducer->connect(listener, api, producerControlledByApp, output);
-}
-
-status_t MonitoredProducer::disconnect(int api, DisconnectMode mode) {
-    return mProducer->disconnect(api, mode);
-}
-
-status_t MonitoredProducer::setSidebandStream(const sp<NativeHandle>& stream) {
-    return mProducer->setSidebandStream(stream);
-}
-
-void MonitoredProducer::allocateBuffers(uint32_t width, uint32_t height,
-        PixelFormat format, uint64_t usage) {
-    mProducer->allocateBuffers(width, height, format, usage);
-}
-
-status_t MonitoredProducer::allowAllocation(bool allow) {
-    return mProducer->allowAllocation(allow);
-}
-
-status_t MonitoredProducer::setGenerationNumber(uint32_t generationNumber) {
-    return mProducer->setGenerationNumber(generationNumber);
-}
-
-String8 MonitoredProducer::getConsumerName() const {
-    return mProducer->getConsumerName();
-}
-
-status_t MonitoredProducer::setSharedBufferMode(bool sharedBufferMode) {
-    return mProducer->setSharedBufferMode(sharedBufferMode);
-}
-
-status_t MonitoredProducer::setAutoRefresh(bool autoRefresh) {
-    return mProducer->setAutoRefresh(autoRefresh);
-}
-
-status_t MonitoredProducer::setDequeueTimeout(nsecs_t timeout) {
-    return mProducer->setDequeueTimeout(timeout);
-}
-
-status_t MonitoredProducer::setLegacyBufferDrop(bool drop) {
-    return mProducer->setLegacyBufferDrop(drop);
-}
-
-status_t MonitoredProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
-        sp<Fence>* outFence, float outTransformMatrix[16]) {
-    return mProducer->getLastQueuedBuffer(outBuffer, outFence,
-            outTransformMatrix);
-}
-
-status_t MonitoredProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence,
-                                                Rect* outRect, uint32_t* outTransform) {
-    return mProducer->getLastQueuedBuffer(outBuffer, outFence, outRect, outTransform);
-}
-
-void MonitoredProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
-    mProducer->getFrameTimestamps(outDelta);
-}
-
-status_t MonitoredProducer::getUniqueId(uint64_t* outId) const {
-    return mProducer->getUniqueId(outId);
-}
-
-status_t MonitoredProducer::getConsumerUsage(uint64_t* outUsage) const {
-    return mProducer->getConsumerUsage(outUsage);
-}
-
-status_t MonitoredProducer::setAutoPrerotation(bool autoPrerotation) {
-    return mProducer->setAutoPrerotation(autoPrerotation);
-}
-
-IBinder* MonitoredProducer::onAsBinder() {
-    return this;
-}
-
-sp<Layer> MonitoredProducer::getLayer() const {
-    return mLayer.promote();
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
deleted file mode 100644
index 3778277..0000000
--- a/services/surfaceflinger/MonitoredProducer.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MONITORED_PRODUCER_H
-#define ANDROID_MONITORED_PRODUCER_H
-
-#include <gui/IGraphicBufferProducer.h>
-
-namespace android {
-
-class IProducerListener;
-class NativeHandle;
-class SurfaceFlinger;
-class Layer;
-
-// MonitoredProducer wraps an IGraphicBufferProducer so that SurfaceFlinger will
-// be notified upon its destruction
-class MonitoredProducer : public BnGraphicBufferProducer {
-public:
-    MonitoredProducer(const sp<IGraphicBufferProducer>& producer,
-            const sp<SurfaceFlinger>& flinger,
-            const wp<Layer>& layer);
-    virtual ~MonitoredProducer();
-
-    // From IGraphicBufferProducer
-    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
-    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
-    virtual status_t setAsyncMode(bool async);
-    virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
-                                   PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
-                                   FrameEventHistoryDelta* outTimestamps);
-    virtual status_t detachBuffer(int slot);
-    virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
-            sp<Fence>* outFence);
-    virtual status_t attachBuffer(int* outSlot,
-            const sp<GraphicBuffer>& buffer);
-    virtual status_t queueBuffer(int slot, const QueueBufferInput& input,
-            QueueBufferOutput* output);
-    virtual status_t cancelBuffer(int slot, const sp<Fence>& fence);
-    virtual int query(int what, int* value);
-    virtual status_t connect(const sp<IProducerListener>& token, int api,
-            bool producerControlledByApp, QueueBufferOutput* output);
-    virtual status_t disconnect(int api, DisconnectMode mode);
-    virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
-    virtual void allocateBuffers(uint32_t width, uint32_t height,
-            PixelFormat format, uint64_t usage);
-    virtual status_t allowAllocation(bool allow);
-    virtual status_t setGenerationNumber(uint32_t generationNumber);
-    virtual String8 getConsumerName() const override;
-    virtual status_t setDequeueTimeout(nsecs_t timeout) override;
-    virtual status_t setLegacyBufferDrop(bool drop) override;
-    virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
-            sp<Fence>* outFence, float outTransformMatrix[16]) override;
-    virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence,
-                                         Rect* outRect, uint32_t* outTransform) override;
-    virtual IBinder* onAsBinder();
-    virtual status_t setSharedBufferMode(bool sharedBufferMode) override;
-    virtual status_t setAutoRefresh(bool autoRefresh) override;
-    virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override;
-    virtual status_t getUniqueId(uint64_t* outId) const override;
-    virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
-    virtual status_t setAutoPrerotation(bool autoPrerotation) override;
-
-    // The Layer which created this producer, and on which queued Buffer's will be displayed.
-    sp<Layer> getLayer() const;
-
-private:
-    sp<IGraphicBufferProducer> mProducer;
-    sp<SurfaceFlinger> mFlinger;
-    // The Layer which created this producer, and on which queued Buffer's will be displayed.
-    wp<Layer> mLayer;
-};
-
-}; // namespace android
-
-#endif // ANDROID_MONITORED_PRODUCER_H
diff --git a/services/surfaceflinger/NativeWindowSurface.cpp b/services/surfaceflinger/NativeWindowSurface.cpp
index 3fff928..a6a3eec 100644
--- a/services/surfaceflinger/NativeWindowSurface.cpp
+++ b/services/surfaceflinger/NativeWindowSurface.cpp
@@ -30,7 +30,7 @@
     class NativeWindowSurface final : public surfaceflinger::NativeWindowSurface {
     public:
         explicit NativeWindowSurface(const sp<IGraphicBufferProducer>& producer)
-              : mSurface(new Surface(producer, /* controlledByApp */ false)) {}
+              : mSurface(sp<Surface>::make(producer, /* controlledByApp */ false)) {}
 
         ~NativeWindowSurface() override = default;
 
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index d4435c2..9b19afb 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 = [&]() {
@@ -143,13 +152,13 @@
             }
         }();
 
-        sp<GraphicBuffer> buffer =
-                new GraphicBuffer(static_cast<uint32_t>(bufferWidth),
-                                  static_cast<uint32_t>(bufferHeight), HAL_PIXEL_FORMAT_RGBA_8888,
-                                  1,
-                                  GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
-                                          GRALLOC_USAGE_HW_TEXTURE,
-                                  "RefreshRateOverlayBuffer");
+        const auto kUsageFlags =
+                static_cast<uint64_t>(GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
+                                      GRALLOC_USAGE_HW_TEXTURE);
+        sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth),
+                                                           static_cast<uint32_t>(bufferHeight),
+                                                           HAL_PIXEL_FORMAT_RGBA_8888, 1u,
+                                                           kUsageFlags, "RefreshRateOverlayBuffer");
 
         const status_t bufferStatus = buffer->initCheck();
         LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
@@ -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/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index e29e6ab..5705255 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -132,7 +132,7 @@
 void RegionSamplingThread::addListener(const Rect& samplingArea, const wp<Layer>& stopLayer,
                                        const sp<IRegionSamplingListener>& listener) {
     sp<IBinder> asBinder = IInterface::asBinder(listener);
-    asBinder->linkToDeath(this);
+    asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
     std::lock_guard lock(mSamplingMutex);
     mDescriptors.emplace(wp<IBinder>(asBinder), Descriptor{samplingArea, stopLayer, listener});
 }
@@ -344,8 +344,8 @@
         const uint32_t usage =
                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
         sp<GraphicBuffer> graphicBuffer =
-                new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(),
-                                  PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
+                sp<GraphicBuffer>::make(sampledBounds.getWidth(), sampledBounds.getHeight(),
+                                        PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
         const status_t bufferStatus = graphicBuffer->initCheck();
         LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d",
                             bufferStatus);
@@ -355,12 +355,15 @@
                                                              WRITEABLE);
     }
 
-    auto captureScreenResultFuture =
-            mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
-                                         true /* regionSampling */, false /* grayscale */, nullptr);
-    auto& captureScreenResult = captureScreenResultFuture.get();
-    if (captureScreenResult.drawFence.ok()) {
-        sync_wait(captureScreenResult.drawFence.get(), -1);
+    constexpr bool kRegionSampling = true;
+    constexpr bool kGrayscale = false;
+
+    if (const auto fenceResult =
+                mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
+                                             kRegionSampling, kGrayscale, nullptr)
+                        .get();
+        fenceResult.ok()) {
+        fenceResult.value()->waitForever(LOG_TAG);
     }
 
     std::vector<Descriptor> activeDescriptors;
diff --git a/services/surfaceflinger/Scheduler/Android.bp b/services/surfaceflinger/Scheduler/Android.bp
index 5de796d..5bd8a99 100644
--- a/services/surfaceflinger/Scheduler/Android.bp
+++ b/services/surfaceflinger/Scheduler/Android.bp
@@ -18,6 +18,7 @@
         "libbase",
         "libcutils",
         "liblog",
+        "libui",
         "libutils",
     ],
 }
@@ -39,6 +40,7 @@
     name: "libscheduler",
     defaults: ["libscheduler_defaults"],
     srcs: [
+        "src/PresentLatencyTracker.cpp",
         "src/Timer.cpp",
     ],
     local_include_dirs: ["include"],
@@ -50,6 +52,7 @@
     test_suites: ["device-tests"],
     defaults: ["libscheduler_defaults"],
     srcs: [
+        "tests/PresentLatencyTrackerTest.cpp",
         "tests/TimerTest.cpp",
     ],
     static_libs: [
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index cbea77e..d3f53c1 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -157,9 +157,9 @@
 
 } // namespace
 
-EventThreadConnection::EventThreadConnection(
-        EventThread* eventThread, uid_t callingUid, ResyncCallback resyncCallback,
-        ISurfaceComposer::EventRegistrationFlags eventRegistration)
+EventThreadConnection::EventThreadConnection(EventThread* eventThread, uid_t callingUid,
+                                             ResyncCallback resyncCallback,
+                                             EventRegistrationFlags eventRegistration)
       : resyncCallback(std::move(resyncCallback)),
         mOwnerUid(callingUid),
         mEventRegistration(eventRegistration),
@@ -173,30 +173,37 @@
 
 void EventThreadConnection::onFirstRef() {
     // NOTE: mEventThread doesn't hold a strong reference on us
-    mEventThread->registerDisplayEventConnection(this);
+    mEventThread->registerDisplayEventConnection(sp<EventThreadConnection>::fromExisting(this));
 }
 
 binder::Status EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) {
+    std::scoped_lock lock(mLock);
+    if (mChannel.initCheck() != NO_ERROR) {
+        return binder::Status::fromStatusT(NAME_NOT_FOUND);
+    }
+
     outChannel->setReceiveFd(mChannel.moveReceiveFd());
     outChannel->setSendFd(base::unique_fd(dup(mChannel.getSendFd())));
     return binder::Status::ok();
 }
 
 binder::Status EventThreadConnection::setVsyncRate(int rate) {
-    mEventThread->setVsyncRate(static_cast<uint32_t>(rate), this);
+    mEventThread->setVsyncRate(static_cast<uint32_t>(rate),
+                               sp<EventThreadConnection>::fromExisting(this));
     return binder::Status::ok();
 }
 
 binder::Status EventThreadConnection::requestNextVsync() {
     ATRACE_CALL();
-    mEventThread->requestNextVsync(this);
+    mEventThread->requestNextVsync(sp<EventThreadConnection>::fromExisting(this));
     return binder::Status::ok();
 }
 
 binder::Status EventThreadConnection::getLatestVsyncEventData(
         ParcelableVsyncEventData* outVsyncEventData) {
     ATRACE_CALL();
-    outVsyncEventData->vsync = mEventThread->getLatestVsyncEventData(this);
+    outVsyncEventData->vsync =
+            mEventThread->getLatestVsyncEventData(sp<EventThreadConnection>::fromExisting(this));
     return binder::Status::ok();
 }
 
@@ -283,11 +290,10 @@
 }
 
 sp<EventThreadConnection> EventThread::createEventConnection(
-        ResyncCallback resyncCallback,
-        ISurfaceComposer::EventRegistrationFlags eventRegistration) const {
-    return new EventThreadConnection(const_cast<EventThread*>(this),
-                                     IPCThreadState::self()->getCallingUid(),
-                                     std::move(resyncCallback), eventRegistration);
+        ResyncCallback resyncCallback, EventRegistrationFlags eventRegistration) const {
+    return sp<EventThreadConnection>::make(const_cast<EventThread*>(this),
+                                           IPCThreadState::self()->getCallingUid(),
+                                           std::move(resyncCallback), eventRegistration);
 }
 
 status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
@@ -548,7 +554,7 @@
 
         case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: {
             return connection->mEventRegistration.test(
-                    ISurfaceComposer::EventRegistration::modeChanged);
+                    gui::ISurfaceComposer::EventRegistration::modeChanged);
         }
 
         case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
@@ -581,7 +587,7 @@
             [[fallthrough]];
         case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
             return connection->mEventRegistration.test(
-                    ISurfaceComposer::EventRegistration::frameRateOverride);
+                    gui::ISurfaceComposer::EventRegistration::frameRateOverride);
 
         default:
             return false;
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index c406478..d85d140 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -92,7 +92,7 @@
 class EventThreadConnection : public gui::BnDisplayEventConnection {
 public:
     EventThreadConnection(EventThread*, uid_t callingUid, ResyncCallback,
-                          ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
+                          EventRegistrationFlags eventRegistration = {});
     virtual ~EventThreadConnection();
 
     virtual status_t postEvent(const DisplayEventReceiver::Event& event);
@@ -107,12 +107,13 @@
 
     VSyncRequest vsyncRequest = VSyncRequest::None;
     const uid_t mOwnerUid;
-    const ISurfaceComposer::EventRegistrationFlags mEventRegistration;
+    const EventRegistrationFlags mEventRegistration;
 
 private:
     virtual void onFirstRef();
     EventThread* const mEventThread;
-    gui::BitTube mChannel;
+    std::mutex mLock;
+    gui::BitTube mChannel GUARDED_BY(mLock);
 
     std::vector<DisplayEventReceiver::Event> mPendingEvents;
 };
@@ -122,8 +123,7 @@
     virtual ~EventThread();
 
     virtual sp<EventThreadConnection> createEventConnection(
-            ResyncCallback,
-            ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) const = 0;
+            ResyncCallback, EventRegistrationFlags eventRegistration = {}) const = 0;
 
     // called before the screen is turned off from main thread
     virtual void onScreenReleased() = 0;
@@ -170,8 +170,7 @@
     ~EventThread();
 
     sp<EventThreadConnection> createEventConnection(
-            ResyncCallback,
-            ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) const override;
+            ResyncCallback, EventRegistrationFlags eventRegistration = {}) const override;
 
     status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
     void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 5f64efa..ae111c3 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -72,6 +72,20 @@
 
     ALOGD("%s: %s @ %d Hz", __FUNCTION__, info.getName().c_str(), fps);
 }
+
+LayerHistory::LayerVoteType getVoteType(LayerInfo::FrameRateCompatibility compatibility,
+                                        bool contentDetectionEnabled) {
+    LayerHistory::LayerVoteType voteType;
+    if (!contentDetectionEnabled || compatibility == LayerInfo::FrameRateCompatibility::NoVote) {
+        voteType = LayerHistory::LayerVoteType::NoVote;
+    } else if (compatibility == LayerInfo::FrameRateCompatibility::Min) {
+        voteType = LayerHistory::LayerVoteType::Min;
+    } else {
+        voteType = LayerHistory::LayerVoteType::Heuristic;
+    }
+    return voteType;
+}
+
 } // namespace
 
 LayerHistory::LayerHistory()
@@ -81,10 +95,12 @@
 
 LayerHistory::~LayerHistory() = default;
 
-void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) {
+void LayerHistory::registerLayer(Layer* layer, bool contentDetectionEnabled) {
     std::lock_guard lock(mLock);
     LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first != LayerStatus::NotFound,
                         "%s already registered", layer->getName().c_str());
+    LayerVoteType type =
+            getVoteType(layer->getDefaultFrameRateCompatibility(), contentDetectionEnabled);
     auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type);
 
     // The layer can be placed on either map, it is assumed that partitionLayers() will be called
@@ -132,6 +148,22 @@
     }
 }
 
+void LayerHistory::setDefaultFrameRateCompatibility(Layer* layer, bool contentDetectionEnabled) {
+    std::lock_guard lock(mLock);
+    auto id = layer->getSequence();
+
+    auto [found, layerPair] = findLayer(id);
+    if (found == LayerStatus::NotFound) {
+        // Offscreen layer
+        ALOGV("%s: %s not registered", __func__, layer->getName().c_str());
+        return;
+    }
+
+    const auto& info = layerPair->second;
+    info->setDefaultLayerVote(
+            getVoteType(layer->getDefaultFrameRateCompatibility(), contentDetectionEnabled));
+}
+
 auto LayerHistory::summarize(const RefreshRateConfigs& configs, nsecs_t now) -> Summary {
     Summary summary;
 
@@ -203,6 +235,8 @@
                 switch (frameRate.type) {
                     case Layer::FrameRateCompatibility::Default:
                         return LayerVoteType::ExplicitDefault;
+                    case Layer::FrameRateCompatibility::Min:
+                        return LayerVoteType::Min;
                     case Layer::FrameRateCompatibility::ExactOrMultiple:
                         return LayerVoteType::ExplicitExactOrMultiple;
                     case Layer::FrameRateCompatibility::NoVote:
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 7b6096f..12bec8d 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -45,7 +45,7 @@
     ~LayerHistory();
 
     // Layers are unregistered when the weak reference expires.
-    void registerLayer(Layer*, LayerVoteType type);
+    void registerLayer(Layer*, bool contentDetectionEnabled);
 
     // Sets the display size. Client is responsible for synchronization.
     void setDisplayArea(uint32_t displayArea) { mDisplayArea = displayArea; }
@@ -63,6 +63,10 @@
     // Marks the layer as active, and records the given state to its history.
     void record(Layer*, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType);
 
+    // Updates the default frame rate compatibility which takes effect when the app
+    // does not set a preference for refresh rate.
+    void setDefaultFrameRateCompatibility(Layer*, bool contentDetectionEnabled);
+
     using Summary = std::vector<RefreshRateConfigs::LayerRequirement>;
 
     // Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 8a3b0b9..28cb24a 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -74,6 +74,8 @@
     enum class FrameRateCompatibility {
         Default, // Layer didn't specify any specific handling strategy
 
+        Min, // Layer needs the minimum frame rate.
+
         Exact, // Layer needs the exact frame rate.
 
         ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index f2af85e..e1ac301 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -30,11 +30,11 @@
 
 namespace android::impl {
 
-void MessageQueue::Handler::dispatchFrame(int64_t vsyncId, nsecs_t expectedVsyncTime) {
+void MessageQueue::Handler::dispatchFrame(VsyncId vsyncId, TimePoint expectedVsyncTime) {
     if (!mFramePending.exchange(true)) {
         mVsyncId = vsyncId;
         mExpectedVsyncTime = expectedVsyncTime;
-        mQueue.mLooper->sendMessage(this, Message());
+        mQueue.mLooper->sendMessage(sp<MessageHandler>::fromExisting(this), Message());
     }
 }
 
@@ -44,16 +44,7 @@
 
 void MessageQueue::Handler::handleMessage(const Message&) {
     mFramePending.store(false);
-
-    const nsecs_t frameTime = systemTime();
-    auto& compositor = mQueue.mCompositor;
-
-    if (!compositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) {
-        return;
-    }
-
-    compositor.composite(frameTime, mVsyncId);
-    compositor.sample();
+    mQueue.onFrameSignal(mQueue.mCompositor, mVsyncId, mExpectedVsyncTime);
 }
 
 MessageQueue::MessageQueue(ICompositor& compositor)
@@ -102,16 +93,17 @@
     // Trace VSYNC-sf
     mVsync.value = (mVsync.value + 1) % 2;
 
+    const auto expectedVsyncTime = TimePoint::fromNs(vsyncTime);
     {
         std::lock_guard lock(mVsync.mutex);
-        mVsync.lastCallbackTime = std::chrono::nanoseconds(vsyncTime);
+        mVsync.lastCallbackTime = expectedVsyncTime;
         mVsync.scheduledFrameTime.reset();
     }
 
-    const auto vsyncId = mVsync.tokenManager->generateTokenForPredictions(
-            {targetWakeupTime, readyTime, vsyncTime});
+    const auto vsyncId = VsyncId{mVsync.tokenManager->generateTokenForPredictions(
+            {targetWakeupTime, readyTime, vsyncTime})};
 
-    mHandler->dispatchFrame(vsyncId, vsyncTime);
+    mHandler->dispatchFrame(vsyncId, expectedVsyncTime);
 }
 
 void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch,
@@ -133,9 +125,10 @@
     std::lock_guard lock(mVsync.mutex);
     mVsync.workDuration = workDuration;
     if (mVsync.scheduledFrameTime) {
-        mVsync.scheduledFrameTime = mVsync.registration->schedule(
-                {mVsync.workDuration.get().count(),
-                 /*readyDuration=*/0, mVsync.lastCallbackTime.count()});
+        mVsync.scheduledFrameTime =
+                mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
+                                               .readyDuration = 0,
+                                               .earliestVsync = mVsync.lastCallbackTime.ns()});
     }
 }
 
@@ -171,7 +164,7 @@
     {
         std::lock_guard lock(mInjector.mutex);
         if (CC_UNLIKELY(mInjector.connection)) {
-            ALOGD("%s while injecting VSYNC", __FUNCTION__);
+            ALOGD("%s while injecting VSYNC", __func__);
             mInjector.connection->requestNextVsync();
             return;
         }
@@ -181,7 +174,7 @@
     mVsync.scheduledFrameTime =
             mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
                                            .readyDuration = 0,
-                                           .earliestVsync = mVsync.lastCallbackTime.count()});
+                                           .earliestVsync = mVsync.lastCallbackTime.ns()});
 }
 
 void MessageQueue::injectorCallback() {
@@ -190,9 +183,10 @@
     while ((n = DisplayEventReceiver::getEvents(&mInjector.tube, buffer, 8)) > 0) {
         for (int i = 0; i < n; i++) {
             if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
-                auto& vsync = buffer[i].vsync;
-                mHandler->dispatchFrame(vsync.vsyncData.preferredVsyncId(),
-                                        vsync.vsyncData.preferredExpectedPresentationTime());
+                auto& vsync = buffer[i].vsync.vsyncData;
+                mHandler->dispatchFrame(VsyncId{vsync.preferredVsyncId()},
+                                        TimePoint::fromNs(
+                                                vsync.preferredExpectedPresentationTime()));
                 break;
             }
         }
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 4082e26..506f27b 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -25,8 +25,12 @@
 #include <android/gui/IDisplayEventConnection.h>
 #include <private/gui/BitTube.h>
 #include <utils/Looper.h>
+#include <utils/StrongPointer.h>
 #include <utils/Timers.h>
 
+#include <scheduler/Time.h>
+#include <scheduler/VsyncId.h>
+
 #include "EventThread.h"
 #include "TracedOrdinal.h"
 #include "VSyncDispatch.h"
@@ -34,8 +38,8 @@
 namespace android {
 
 struct ICompositor {
-    virtual bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) = 0;
-    virtual void composite(nsecs_t frameTime, int64_t vsyncId) = 0;
+    virtual bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) = 0;
+    virtual void composite(TimePoint frameTime, VsyncId) = 0;
     virtual void sample() = 0;
 
 protected:
@@ -47,6 +51,9 @@
     template <typename G>
     friend auto makeTask(G&&);
 
+    template <typename... Args>
+    friend sp<Task<F>> sp<Task<F>>::make(Args&&... args);
+
     explicit Task(F&& f) : mTask(std::move(f)) {}
 
     void handleMessage(const Message&) override { mTask(); }
@@ -57,7 +64,7 @@
 
 template <typename F>
 inline auto makeTask(F&& f) {
-    sp<Task<F>> task = new Task<F>(std::move(f));
+    sp<Task<F>> task = sp<Task<F>>::make(std::forward<F>(f));
     return std::make_pair(task, task->mTask.get_future());
 }
 
@@ -84,8 +91,9 @@
     class Handler : public MessageHandler {
         MessageQueue& mQueue;
         std::atomic_bool mFramePending = false;
-        std::atomic<int64_t> mVsyncId = 0;
-        std::atomic<nsecs_t> mExpectedVsyncTime = 0;
+
+        std::atomic<VsyncId> mVsyncId;
+        std::atomic<TimePoint> mExpectedVsyncTime;
 
     public:
         explicit Handler(MessageQueue& queue) : mQueue(queue) {}
@@ -93,7 +101,7 @@
 
         bool isFramePending() const;
 
-        virtual void dispatchFrame(int64_t vsyncId, nsecs_t expectedVsyncTime);
+        virtual void dispatchFrame(VsyncId, TimePoint expectedVsyncTime);
     };
 
     friend class Handler;
@@ -104,6 +112,8 @@
     void vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime);
 
 private:
+    virtual void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) = 0;
+
     ICompositor& mCompositor;
     const sp<Looper> mLooper;
     const sp<Handler> mHandler;
@@ -115,7 +125,7 @@
         mutable std::mutex mutex;
         TracedOrdinal<std::chrono::nanoseconds> workDuration
                 GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)};
-        std::chrono::nanoseconds lastCallbackTime GUARDED_BY(mutex) = std::chrono::nanoseconds{0};
+        TimePoint lastCallbackTime GUARDED_BY(mutex);
         std::optional<nsecs_t> scheduledFrameTime GUARDED_BY(mutex);
         TracedOrdinal<int> value = {"VSYNC-sf", 0};
     };
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
index 16f041a..3c8dc64 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
@@ -47,6 +47,7 @@
         mInterval(interval),
         mResetCallback(resetCallback),
         mTimeoutCallback(timeoutCallback) {
+    mLastResetTime = std::chrono::steady_clock::time_point::min();
     LOG_ALWAYS_FATAL_IF(!mClock, "Clock must not be provided");
 }
 
@@ -116,25 +117,35 @@
 
         auto triggerTime = mClock->now() + mInterval;
         state = TimerState::WAITING;
-        while (state == TimerState::WAITING) {
-            constexpr auto zero = std::chrono::steady_clock::duration::zero();
-            // Wait for mInterval time for semaphore signal.
-            struct timespec ts;
-            calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts);
-            int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts);
-            if (result && errno != ETIMEDOUT && errno != EINTR) {
-                std::stringstream ss;
-                ss << "sem_clockwait failed (" << errno << ")";
-                LOG_ALWAYS_FATAL("%s", ss.str().c_str());
+        while (true) {
+            // Wait until triggerTime time to check if we need to reset or drop into the idle state.
+            if (const auto triggerInterval = triggerTime - mClock->now(); triggerInterval > 0ns) {
+                mWaiting = true;
+                struct timespec ts;
+                calculateTimeoutTime(triggerInterval, &ts);
+                int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts);
+                if (result && errno != ETIMEDOUT && errno != EINTR) {
+                    std::stringstream ss;
+                    ss << "sem_clockwait failed (" << errno << ")";
+                    LOG_ALWAYS_FATAL("%s", ss.str().c_str());
+                }
             }
 
+            mWaiting = false;
             state = checkForResetAndStop(state);
-            if (state == TimerState::RESET) {
-                triggerTime = mClock->now() + mInterval;
-                state = TimerState::WAITING;
-            } else if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= zero) {
+            if (state == TimerState::STOPPED) {
+                break;
+            }
+
+            if (state == TimerState::WAITING && (triggerTime - mClock->now()) <= 0ns) {
                 triggerTimeout = true;
                 state = TimerState::IDLE;
+                break;
+            }
+
+            if (state == TimerState::RESET) {
+                triggerTime = mLastResetTime.load() + mInterval;
+                state = TimerState::WAITING;
             }
         }
 
@@ -158,9 +169,14 @@
 }
 
 void OneShotTimer::reset() {
+    mLastResetTime = mClock->now();
     mResetTriggered = true;
-    int result = sem_post(&mSemaphore);
-    LOG_ALWAYS_FATAL_IF(result, "sem_post failed");
+    // If mWaiting is true, then we are guaranteed to be in a block where we are waiting on
+    // mSemaphore for a timeout, rather than idling. So we can avoid a sem_post call since we can
+    // just check that we triggered a reset on timeout.
+    if (!mWaiting) {
+        LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed");
+    }
 }
 
 std::string OneShotTimer::dump() const {
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h
index 09265bb..2017c31 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.h
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.h
@@ -103,6 +103,8 @@
     // check in the main loop if they were.
     std::atomic<bool> mResetTriggered = false;
     std::atomic<bool> mStopTriggered = false;
+    std::atomic<bool> mWaiting = false;
+    std::atomic<std::chrono::steady_clock::time_point> mLastResetTime;
 };
 
 } // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 3226f22..ca83496 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -133,9 +133,9 @@
 } // namespace
 
 std::string RefreshRateConfigs::Policy::toString() const {
-    return base::StringPrintf("default mode ID: %d, allowGroupSwitching = %d"
-                              ", primary range: %s, app request range: %s",
-                              defaultMode.value(), allowGroupSwitching,
+    return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s"
+                              ", primaryRange=%s, appRequestRange=%s}",
+                              defaultMode.value(), allowGroupSwitching ? "true" : "false",
                               to_string(primaryRange).c_str(), to_string(appRequestRange).c_str());
 }
 
@@ -922,41 +922,46 @@
 }
 
 void RefreshRateConfigs::dump(std::string& result) const {
+    using namespace std::string_literals;
+
     std::lock_guard lock(mLock);
-    base::StringAppendF(&result, "DesiredDisplayModeSpecs (DisplayManager): %s\n\n",
-                        mDisplayManagerPolicy.toString().c_str());
-    scheduler::RefreshRateConfigs::Policy currentPolicy = *getCurrentPolicyLocked();
-    if (mOverridePolicy && currentPolicy != mDisplayManagerPolicy) {
-        base::StringAppendF(&result, "DesiredDisplayModeSpecs (Override): %s\n\n",
-                            currentPolicy.toString().c_str());
-    }
 
-    base::StringAppendF(&result, "Active mode: %s\n", to_string(*mActiveModeIt->second).c_str());
+    const auto activeModeId = mActiveModeIt->first;
+    result += "   activeModeId="s;
+    result += std::to_string(activeModeId.value());
 
-    result.append("Display modes:\n");
+    result += "\n   displayModes=\n"s;
     for (const auto& [id, mode] : mDisplayModes) {
-        result.push_back('\t');
-        result.append(to_string(*mode));
-        result.push_back('\n');
+        result += "      "s;
+        result += to_string(*mode);
+        result += '\n';
     }
 
-    base::StringAppendF(&result, "Supports Frame Rate Override By Content: %s\n",
-                        mSupportsFrameRateOverrideByContent ? "yes" : "no");
+    base::StringAppendF(&result, "   displayManagerPolicy=%s\n",
+                        mDisplayManagerPolicy.toString().c_str());
 
-    result.append("Idle timer: ");
-    if (const auto controller = mConfig.kernelIdleTimerController) {
-        base::StringAppendF(&result, "(kernel via %s) ", ftl::enum_string(*controller).c_str());
-    } else {
-        result.append("(platform) ");
+    if (const Policy& currentPolicy = *getCurrentPolicyLocked();
+        mOverridePolicy && currentPolicy != mDisplayManagerPolicy) {
+        base::StringAppendF(&result, "   overridePolicy=%s\n", currentPolicy.toString().c_str());
     }
 
+    base::StringAppendF(&result, "   supportsFrameRateOverrideByContent=%s\n",
+                        mSupportsFrameRateOverrideByContent ? "true" : "false");
+
+    result += "   idleTimer="s;
     if (mIdleTimer) {
-        result.append(mIdleTimer->dump());
+        result += mIdleTimer->dump();
     } else {
-        result.append("off");
+        result += "off"s;
     }
 
-    result.append("\n\n");
+    if (const auto controller = mConfig.kernelIdleTimerController) {
+        base::StringAppendF(&result, " (kernel via %s)", ftl::enum_string(*controller).c_str());
+    } else {
+        result += " (platform)"s;
+    }
+
+    result += '\n';
 }
 
 std::chrono::milliseconds RefreshRateConfigs::getIdleTimerTimeout() {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 3aa0a5f..55ae013 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -25,9 +25,9 @@
 #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>
 #include <utils/Timers.h>
 #include <utils/Trace.h>
 
@@ -94,9 +94,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();
@@ -127,6 +131,18 @@
     }
 }
 
+void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
+                              TimePoint expectedVsyncTime) {
+    const TimePoint frameTime = SchedulerClock::now();
+
+    if (!compositor.commit(frameTime, vsyncId, expectedVsyncTime)) {
+        return;
+    }
+
+    compositor.composite(frameTime, vsyncId);
+    compositor.sample();
+}
+
 void Scheduler::createVsyncSchedule(FeatureFlags features) {
     mVsyncSchedule.emplace(features);
 }
@@ -147,38 +163,38 @@
             .getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent);
 }
 
-bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const {
+bool Scheduler::isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const {
     const auto frameRate = getFrameRateOverride(uid);
     if (!frameRate.has_value()) {
         return true;
     }
 
-    return mVsyncSchedule->getTracker().isVSyncInPhase(expectedVsyncTimestamp, *frameRate);
+    return mVsyncSchedule->getTracker().isVSyncInPhase(expectedVsyncTimestamp.ns(), *frameRate);
 }
 
 impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const {
     std::scoped_lock lock(mRefreshRateConfigsLock);
 
     return [this](nsecs_t expectedVsyncTimestamp, uid_t uid) {
-        return !isVsyncValid(expectedVsyncTimestamp, uid);
+        return !isVsyncValid(TimePoint::fromNs(expectedVsyncTimestamp), uid);
     };
 }
 
 impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
     return [this](uid_t uid) {
         const Fps refreshRate = holdRefreshRateConfigs()->getActiveMode()->getFps();
-        const nsecs_t basePeriod = refreshRate.getPeriodNsecs();
+        const nsecs_t currentPeriod = mVsyncSchedule->period().ns() ?: refreshRate.getPeriodNsecs();
 
         const auto frameRate = getFrameRateOverride(uid);
         if (!frameRate.has_value()) {
-            return basePeriod;
+            return currentPeriod;
         }
 
         const auto divisor = RefreshRateConfigs::getFrameRateDivisor(refreshRate, *frameRate);
         if (divisor <= 1) {
-            return basePeriod;
+            return currentPeriod;
         }
-        return basePeriod * divisor;
+        return currentPeriod * divisor;
     };
 }
 
@@ -208,12 +224,12 @@
 }
 
 sp<EventThreadConnection> Scheduler::createConnectionInternal(
-        EventThread* eventThread, ISurfaceComposer::EventRegistrationFlags eventRegistration) {
+        EventThread* eventThread, EventRegistrationFlags eventRegistration) {
     return eventThread->createEventConnection([&] { resync(); }, eventRegistration);
 }
 
 sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
-        ConnectionHandle handle, ISurfaceComposer::EventRegistrationFlags eventRegistration) {
+        ConnectionHandle handle, EventRegistrationFlags eventRegistration) {
     std::lock_guard<std::mutex> lock(mConnectionsLock);
     RETURN_IF_INVALID_HANDLE(handle, nullptr);
     return createConnectionInternal(mConnections[handle].thread.get(), eventRegistration);
@@ -355,12 +371,6 @@
     thread->setDuration(workDuration, readyDuration);
 }
 
-DisplayStatInfo Scheduler::getDisplayStatInfo(nsecs_t now) {
-    const auto vsyncTime = mVsyncSchedule->getTracker().nextAnticipatedVSyncTimeFrom(now);
-    const auto vsyncPeriod = mVsyncSchedule->getTracker().currentPeriod();
-    return DisplayStatInfo{.vsyncTime = vsyncTime, .vsyncPeriod = vsyncPeriod};
-}
-
 ConnectionHandle Scheduler::enableVSyncInjection(bool enable) {
     if (mInjectVSyncs == enable) {
         return {};
@@ -491,24 +501,10 @@
 }
 
 void Scheduler::registerLayer(Layer* layer) {
-    using WindowType = gui::WindowInfo::Type;
-
-    scheduler::LayerHistory::LayerVoteType voteType;
-
-    if (!mFeatures.test(Feature::kContentDetection) ||
-        layer->getWindowType() == WindowType::STATUS_BAR) {
-        voteType = scheduler::LayerHistory::LayerVoteType::NoVote;
-    } else if (layer->getWindowType() == WindowType::WALLPAPER) {
-        // Running Wallpaper at Min is considered as part of content detection.
-        voteType = scheduler::LayerHistory::LayerVoteType::Min;
-    } else {
-        voteType = scheduler::LayerHistory::LayerVoteType::Heuristic;
-    }
-
     // If the content detection feature is off, we still keep the layer history,
     // since we use it for other features (like Frame Rate API), so layers
     // still need to be registered.
-    mLayerHistory.registerLayer(layer, voteType);
+    mLayerHistory.registerLayer(layer, mFeatures.test(Feature::kContentDetection));
 }
 
 void Scheduler::deregisterLayer(Layer* layer) {
@@ -529,6 +525,11 @@
     mLayerHistory.setModeChangePending(pending);
 }
 
+void Scheduler::setDefaultFrameRateCompatibility(Layer* layer) {
+    mLayerHistory.setDefaultFrameRateCompatibility(layer,
+                                                   mFeatures.test(Feature::kContentDetection));
+}
+
 void Scheduler::chooseRefreshRateForContent() {
     const auto configs = holdRefreshRateConfigs();
     if (!configs->canSwitch()) return;
@@ -553,11 +554,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();
@@ -705,7 +707,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};
     }
@@ -768,11 +771,4 @@
     mFrameRateOverrideMappings.setPreferredRefreshRateForUid(frameRateOverride);
 }
 
-std::chrono::steady_clock::time_point Scheduler::getPreviousVsyncFrom(
-        nsecs_t expectedPresentTime) const {
-    const auto presentTime = std::chrono::nanoseconds(expectedPresentTime);
-    const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule->getTracker().currentPeriod());
-    return std::chrono::steady_clock::time_point(presentTime - vsyncPeriod);
-}
-
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 0c72124..4730493 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -33,6 +33,7 @@
 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
 
 #include <scheduler/Features.h>
+#include <scheduler/Time.h>
 
 #include "EventThread.h"
 #include "FrameRateOverrideMappings.h"
@@ -131,7 +132,7 @@
                                       impl::EventThread::InterceptVSyncsCallback);
 
     sp<IDisplayEventConnection> createDisplayEventConnection(
-            ConnectionHandle, ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
+            ConnectionHandle, EventRegistrationFlags eventRegistration = {});
 
     sp<EventThreadConnection> getEventConnection(ConnectionHandle);
 
@@ -148,8 +149,6 @@
     void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration,
                      std::chrono::nanoseconds readyDuration);
 
-    DisplayStatInfo getDisplayStatInfo(nsecs_t now);
-
     // Returns injector handle if injection has toggled, or an invalid handle otherwise.
     ConnectionHandle enableVSyncInjection(bool enable);
     // Returns false if injection is disabled.
@@ -176,6 +175,7 @@
     void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType)
             EXCLUDES(mRefreshRateConfigsLock);
     void setModeChangePending(bool pending);
+    void setDefaultFrameRateCompatibility(Layer*);
     void deregisterLayer(Layer*);
 
     // Detects content using layer history, and selects a matching refresh rate.
@@ -186,15 +186,13 @@
     // Indicates that touch interaction is taking place.
     void onTouchHint();
 
-    void setDisplayPowerState(bool normal);
+    void setDisplayPowerMode(hal::PowerMode powerMode);
 
-    VSyncDispatch& getVsyncDispatch() { return mVsyncSchedule->getDispatch(); }
+    VsyncSchedule& getVsyncSchedule() { return *mVsyncSchedule; }
 
     // Returns true if a given vsync timestamp is considered valid vsync
     // for a given uid
-    bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const;
-
-    std::chrono::steady_clock::time_point getPreviousVsyncFrom(nsecs_t expectedPresentTime) const;
+    bool isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const;
 
     void dump(std::string&) const;
     void dump(ConnectionHandle, std::string&) const;
@@ -245,10 +243,13 @@
     enum class TimerState { Reset, Expired };
     enum class TouchState { Inactive, Active };
 
+    // impl::MessageQueue overrides:
+    void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override;
+
     // Create a connection on the given EventThread.
     ConnectionHandle createConnection(std::unique_ptr<EventThread>);
     sp<EventThreadConnection> createConnectionInternal(
-            EventThread*, ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
+            EventThread*, EventRegistrationFlags eventRegistration = {});
 
     // Update feature state machine to given state when corresponding timer resets or expires.
     void kernelIdleTimerCallback(TimerState) EXCLUDES(mRefreshRateConfigsLock);
@@ -325,7 +326,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/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 27f4311..cc9f7cf 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -100,14 +100,8 @@
         return getExpectedCallbackTime(nextVsyncTime, timing);
     }
 
-    bool const alreadyDispatchedForVsync = mLastDispatchTime &&
-            ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
-             (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
-    if (alreadyDispatchedForVsync) {
-        nextVsyncTime =
-                tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance);
-        nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
-    }
+    nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
+    nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
 
     auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
     mScheduleTiming = timing;
@@ -123,6 +117,25 @@
     return mWorkloadUpdateInfo.has_value();
 }
 
+nsecs_t VSyncDispatchTimerQueueEntry::adjustVsyncIfNeeded(VSyncTracker& tracker,
+                                                          nsecs_t nextVsyncTime) const {
+    bool const alreadyDispatchedForVsync = mLastDispatchTime &&
+            ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
+             (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
+    const nsecs_t currentPeriod = tracker.currentPeriod();
+    bool const nextVsyncTooClose = mLastDispatchTime &&
+            (nextVsyncTime - *mLastDispatchTime + mMinVsyncDistance) <= currentPeriod;
+    if (alreadyDispatchedForVsync) {
+        return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance);
+    }
+
+    if (nextVsyncTooClose) {
+        return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + currentPeriod);
+    }
+
+    return nextVsyncTime;
+}
+
 void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
     if (!mArmedInfo && !mWorkloadUpdateInfo) {
         return;
@@ -136,7 +149,9 @@
     const auto earliestReadyBy = now + mScheduleTiming.workDuration + mScheduleTiming.readyDuration;
     const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.earliestVsync);
 
-    const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(earliestVsync);
+    const auto nextVsyncTime =
+            adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/
+                                tracker.nextAnticipatedVSyncTimeFrom(earliestVsync));
     const auto nextReadyTime = nextVsyncTime - mScheduleTiming.readyDuration;
     const auto nextWakeupTime = nextReadyTime - mScheduleTiming.workDuration;
 
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index 4923031..4f2f87a 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -84,6 +84,8 @@
     void dump(std::string& result) const;
 
 private:
+    nsecs_t adjustVsyncIfNeeded(VSyncTracker& tracker, nsecs_t nextVsyncTime) const;
+
     const std::string mName;
     const VSyncDispatch::Callback mCallback;
 
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 77782e9..898e865 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -167,7 +167,9 @@
         vsyncTS[i] = timestamp;
         meanTS += timestamp;
 
-        const auto ordinal = (vsyncTS[i] + currentPeriod / 2) / currentPeriod * kScalingFactor;
+        const auto ordinal = currentPeriod == 0
+                ? 0
+                : (vsyncTS[i] + currentPeriod / 2) / currentPeriod * kScalingFactor;
         ordinals[i] = ordinal;
         meanOrdinal += ordinal;
     }
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index bdcab51..13cd304 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -146,6 +146,11 @@
         return false;
     }
 
+    if (mDisplayPowerMode == hal::PowerMode::DOZE ||
+        mDisplayPowerMode == hal::PowerMode::DOZE_SUSPEND) {
+        return true;
+    }
+
     if (!mLastHwVsync && !HwcVsyncPeriod) {
         return false;
     }
@@ -206,6 +211,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/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
index be57b2a..138d8d6 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
@@ -53,14 +53,14 @@
         case Schedule::EarlyStart:
             if (token) {
                 mEarlyWakeupRequests.emplace(token);
-                token->linkToDeath(this);
+                token->linkToDeath(sp<DeathRecipient>::fromExisting(this));
             } else {
                 ALOGW("%s: EarlyStart requested without a valid token", __func__);
             }
             break;
         case Schedule::EarlyEnd: {
             if (token && mEarlyWakeupRequests.erase(token) > 0) {
-                token->unlinkToDeath(this);
+                token->unlinkToDeath(sp<DeathRecipient>::fromExisting(this));
             } else {
                 ALOGW("%s: Unexpected EarlyEnd", __func__);
             }
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
index e611658..95bc31f 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include <scheduler/Fps.h>
 #include <scheduler/Timer.h>
 
@@ -66,6 +68,14 @@
 VsyncSchedule::VsyncSchedule(VsyncSchedule&&) = default;
 VsyncSchedule::~VsyncSchedule() = default;
 
+Period VsyncSchedule::period() const {
+    return Period::fromNs(mTracker->currentPeriod());
+}
+
+TimePoint VsyncSchedule::vsyncDeadlineAfter(TimePoint timePoint) const {
+    return TimePoint::fromNs(mTracker->nextAnticipatedVSyncTimeFrom(timePoint.ns()));
+}
+
 void VsyncSchedule::dump(std::string& out) const {
     out.append("VsyncController:\n");
     mController->dump(out);
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h
index 0d9b114..8c17409 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.h
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h
@@ -20,6 +20,7 @@
 #include <string>
 
 #include <scheduler/Features.h>
+#include <scheduler/Time.h>
 
 namespace android::scheduler {
 
@@ -38,6 +39,9 @@
     VsyncSchedule(VsyncSchedule&&);
     ~VsyncSchedule();
 
+    Period period() const;
+    TimePoint vsyncDeadlineAfter(TimePoint) const;
+
     // TODO(b/185535769): Hide behind API.
     const VsyncTracker& getTracker() const { return *mTracker; }
     VsyncTracker& getTracker() { return *mTracker; }
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/PresentLatencyTracker.h b/services/surfaceflinger/Scheduler/include/scheduler/PresentLatencyTracker.h
new file mode 100644
index 0000000..23ae83f
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/PresentLatencyTracker.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <queue>
+#include <utility>
+
+#include <scheduler/Time.h>
+
+namespace android {
+
+class FenceTime;
+
+namespace scheduler {
+
+// Computes composite-to-present latency by tracking recently composited frames pending to present.
+class PresentLatencyTracker {
+public:
+    // For tests.
+    static constexpr size_t kMaxPendingFrames = 4;
+
+    // Returns the present latency of the latest frame.
+    Duration trackPendingFrame(TimePoint compositeTime,
+                               std::shared_ptr<FenceTime> presentFenceTime);
+
+private:
+    struct PendingFrame {
+        PendingFrame(TimePoint compositeTime, std::shared_ptr<FenceTime> presentFenceTime)
+              : compositeTime(compositeTime), presentFenceTime(std::move(presentFenceTime)) {}
+
+        const TimePoint compositeTime;
+        const std::shared_ptr<FenceTime> presentFenceTime;
+    };
+
+    std::queue<PendingFrame> mPendingFrames;
+};
+
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Time.h b/services/surfaceflinger/Scheduler/include/scheduler/Time.h
new file mode 100644
index 0000000..f00d456
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Time.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <chrono>
+
+#include <utils/Timers.h>
+
+namespace android {
+namespace scheduler {
+
+// TODO(b/185535769): Pull Clock.h to libscheduler to reuse this.
+using SchedulerClock = std::chrono::high_resolution_clock;
+static_assert(SchedulerClock::is_steady);
+
+} // namespace scheduler
+
+struct Duration;
+
+struct TimePoint : scheduler::SchedulerClock::time_point {
+    constexpr TimePoint() = default;
+    explicit constexpr TimePoint(const Duration&);
+
+    // Implicit conversion from std::chrono counterpart.
+    constexpr TimePoint(scheduler::SchedulerClock::time_point p)
+          : scheduler::SchedulerClock::time_point(p) {}
+
+    static constexpr TimePoint fromNs(nsecs_t);
+
+    nsecs_t ns() const;
+};
+
+struct Duration : TimePoint::duration {
+    // Implicit conversion from std::chrono counterpart.
+    template <typename R, typename P>
+    constexpr Duration(std::chrono::duration<R, P> d) : TimePoint::duration(d) {}
+
+    static constexpr Duration fromNs(nsecs_t ns) { return {std::chrono::nanoseconds(ns)}; }
+
+    nsecs_t ns() const { return std::chrono::nanoseconds(*this).count(); }
+};
+
+using Period = Duration;
+
+constexpr TimePoint::TimePoint(const Duration& d) : scheduler::SchedulerClock::time_point(d) {}
+
+constexpr TimePoint TimePoint::fromNs(nsecs_t ns) {
+    return TimePoint(Duration::fromNs(ns));
+}
+
+inline nsecs_t TimePoint::ns() const {
+    return Duration(time_since_epoch()).ns();
+}
+
+// Shorthand to convert the tick count of a Duration to Period and Rep. For example:
+//
+//     const auto i = ticks<std::ratio<1>>(d);      // Integer seconds.
+//     const auto f = ticks<std::milli, float>(d);  // Floating-point milliseconds.
+//
+template <typename Period, typename Rep = Duration::rep>
+constexpr Rep ticks(Duration d) {
+    using D = std::chrono::duration<Rep, Period>;
+    return std::chrono::duration_cast<D>(d).count();
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/VsyncId.h b/services/surfaceflinger/Scheduler/include/scheduler/VsyncId.h
new file mode 100644
index 0000000..c64a3cd
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/VsyncId.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+namespace android {
+
+// TODO(b/185536303): Import StrongTyping.h into FTL so it can be used here.
+
+// Sequential frame identifier, also known as FrameTimeline token.
+struct VsyncId {
+    int64_t value = -1;
+};
+
+inline bool operator==(VsyncId lhs, VsyncId rhs) {
+    return lhs.value == rhs.value;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/src/PresentLatencyTracker.cpp b/services/surfaceflinger/Scheduler/src/PresentLatencyTracker.cpp
new file mode 100644
index 0000000..8f3e081
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/src/PresentLatencyTracker.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#include <scheduler/PresentLatencyTracker.h>
+
+#include <cutils/compiler.h>
+#include <log/log.h>
+#include <ui/FenceTime.h>
+
+namespace android::scheduler {
+
+Duration PresentLatencyTracker::trackPendingFrame(TimePoint compositeTime,
+                                                  std::shared_ptr<FenceTime> presentFenceTime) {
+    Duration presentLatency = Duration::zero();
+    while (!mPendingFrames.empty()) {
+        const auto& pendingFrame = mPendingFrames.front();
+        const auto presentTime =
+                TimePoint::fromNs(pendingFrame.presentFenceTime->getCachedSignalTime());
+
+        if (presentTime == TimePoint::fromNs(Fence::SIGNAL_TIME_PENDING)) {
+            break;
+        }
+
+        if (presentTime == TimePoint::fromNs(Fence::SIGNAL_TIME_INVALID)) {
+            ALOGE("%s: Invalid present fence", __func__);
+        } else {
+            presentLatency = presentTime - pendingFrame.compositeTime;
+        }
+
+        mPendingFrames.pop();
+    }
+
+    mPendingFrames.emplace(compositeTime, std::move(presentFenceTime));
+
+    if (CC_UNLIKELY(mPendingFrames.size() > kMaxPendingFrames)) {
+        ALOGE("%s: Too many pending frames", __func__);
+        mPendingFrames.pop();
+    }
+
+    return presentLatency;
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp b/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp
new file mode 100644
index 0000000..8952ca9
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <array>
+
+#include <scheduler/PresentLatencyTracker.h>
+#include <ui/FenceTime.h>
+
+namespace android::scheduler {
+namespace {
+
+using FencePair = std::pair<sp<Fence>, std::shared_ptr<FenceTime>>;
+
+FencePair makePendingFence(FenceToFenceTimeMap& fenceMap) {
+    const auto fence = sp<Fence>::make();
+    return {fence, fenceMap.createFenceTimeForTest(fence)};
+}
+
+} // namespace
+
+TEST(PresentLatencyTrackerTest, skipsInvalidFences) {
+    PresentLatencyTracker tracker;
+
+    const TimePoint kCompositeTime = TimePoint::fromNs(999);
+    EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), Duration::zero());
+    EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), Duration::zero());
+    EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), Duration::zero());
+
+    FenceToFenceTimeMap fenceMap;
+    const auto [fence, fenceTime] = makePendingFence(fenceMap);
+    EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, fenceTime), Duration::zero());
+
+    fenceTime->signalForTest(9999);
+
+    EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE),
+              Duration::fromNs(9000));
+}
+
+TEST(PresentLatencyTrackerTest, tracksPendingFrames) {
+    PresentLatencyTracker tracker;
+
+    FenceToFenceTimeMap fenceMap;
+    std::array<FencePair, PresentLatencyTracker::kMaxPendingFrames> fences;
+    std::generate(fences.begin(), fences.end(), [&fenceMap] { return makePendingFence(fenceMap); });
+
+    // The present latency is 0 if all fences are pending.
+    const TimePoint kCompositeTime = TimePoint::fromNs(1234);
+    for (const auto& [fence, fenceTime] : fences) {
+        EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, fenceTime), Duration::zero());
+    }
+
+    // If multiple frames have been presented...
+    constexpr size_t kPresentCount = fences.size() / 2;
+    for (size_t i = 0; i < kPresentCount; i++) {
+        fences[i].second->signalForTest(kCompositeTime.ns() + static_cast<nsecs_t>(i));
+    }
+
+    const auto fence = makePendingFence(fenceMap);
+
+    // ...then the present latency is measured using the latest frame.
+    constexpr Duration kPresentLatency = Duration::fromNs(static_cast<nsecs_t>(kPresentCount) - 1);
+    EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, fence.second), kPresentLatency);
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 03e493e..db551d7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -105,12 +105,9 @@
 
 #include <ui/DisplayIdentification.h>
 #include "BackgroundExecutor.h"
-#include "BufferLayer.h"
-#include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
 #include "Client.h"
 #include "Colorizer.h"
-#include "ContainerLayer.h"
 #include "DisplayDevice.h"
 #include "DisplayHardware/ComposerHal.h"
 #include "DisplayHardware/FramebufferSurface.h"
@@ -130,7 +127,6 @@
 #include "LayerProtoHelper.h"
 #include "LayerRenderArea.h"
 #include "LayerVector.h"
-#include "MonitoredProducer.h"
 #include "MutexUtils.h"
 #include "NativeWindowSurface.h"
 #include "RefreshRateOverlay.h"
@@ -156,8 +152,13 @@
 #define NO_THREAD_SAFETY_ANALYSIS \
     _Pragma("GCC error \"Prefer <ftl/fake_guard.h> or MutexUtils.h helpers.\"")
 
+// To enable layer borders in the system, change the below flag to true.
+#undef DOES_CONTAIN_BORDER
+#define DOES_CONTAIN_BORDER false
+
 namespace android {
 
+using namespace std::chrono_literals;
 using namespace std::string_literals;
 
 using namespace hardware::configstore;
@@ -278,6 +279,8 @@
 
 const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled";
 
+static const int MAX_TRACING_MEMORY = 1024 * 1024 * 1024; // 1GB
+
 // ---------------------------------------------------------------------------
 int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
 bool SurfaceFlinger::useHwcForRgbToYuv;
@@ -332,11 +335,11 @@
         mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, mPid)),
         mCompositionEngine(mFactory.createCompositionEngine()),
         mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
-        mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
+        mTunnelModeEnabledReporter(sp<TunnelModeEnabledReporter>::make()),
         mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
         mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
         mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)),
-        mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make(*this)) {
+        mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make()) {
     ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
 }
 
@@ -407,7 +410,7 @@
     property_get("ro.sf.blurs_are_expensive", value, "0");
     mBlursAreExpensive = atoi(value);
 
-    const size_t defaultListSize = ISurfaceComposer::MAX_LAYERS;
+    const size_t defaultListSize = MAX_LAYERS;
     auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
     mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
     mGraphicBufferProducerListSizeLogThreshold =
@@ -424,6 +427,9 @@
     property_get("debug.sf.predict_hwc_composition_strategy", value, "1");
     mPredictCompositionStrategy = atoi(value);
 
+    property_get("debug.sf.treat_170m_as_sRGB", value, "0");
+    mTreat170mAsSrgb = atoi(value);
+
     // We should be reading 'persist.sys.sf.color_saturation' here
     // but since /data may be encrypted, we need to wait until after vold
     // comes online to attempt to read the property. The property is
@@ -446,17 +452,22 @@
     }
 
     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() {
-    if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) {
-        return LatchUnsignaledConfig::Always;
-    }
-
     if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, true)) {
         return LatchUnsignaledConfig::AutoSingleLayer;
     }
 
+    if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) {
+        return LatchUnsignaledConfig::Always;
+    }
+
     return LatchUnsignaledConfig::Disabled;
 }
 
@@ -467,7 +478,8 @@
     mBootFinished = false;
 
     // Sever the link to inputflinger since it's gone as well.
-    static_cast<void>(mScheduler->schedule([=] { mInputFlinger = nullptr; }));
+    static_cast<void>(mScheduler->schedule(
+            [this] { mInputFlinger.clear(); }));
 
     // restore initial conditions (default device unblank, etc)
     initializeDisplays();
@@ -495,7 +507,7 @@
         virtual ~DisplayToken() {
              // no more references, this display must be terminated
              Mutex::Autolock _l(flinger->mStateLock);
-             flinger->mCurrentState.displays.removeItem(this);
+             flinger->mCurrentState.displays.removeItem(wp<IBinder>::fromExisting(this));
              flinger->setTransactionFlags(eDisplayTransactionNeeded);
          }
      public:
@@ -504,7 +516,7 @@
         }
     };
 
-    sp<BBinder> token = new DisplayToken(this);
+    sp<BBinder> token = sp<DisplayToken>::make(sp<SurfaceFlinger>::fromExisting(this));
 
     Mutex::Autolock _l(mStateLock);
     // Display ID is assigned when virtual display is allocated by HWC.
@@ -583,14 +595,8 @@
 std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const {
     std::vector<PhysicalDisplayId> displayIds;
     displayIds.reserve(mPhysicalDisplayTokens.size());
-    const auto defaultDisplayId = [this]() REQUIRES(mStateLock) {
-        if (const auto display = getDefaultDisplayDeviceLocked()) {
-            return display->getPhysicalId();
-        }
 
-        // fallback to the internal display id if the active display is unknown
-        return getInternalDisplayIdLocked();
-    }();
+    const auto defaultDisplayId = getDefaultDisplayDeviceLocked()->getPhysicalId();
     displayIds.push_back(defaultDisplayId);
 
     for (const auto& [id, token] : mPhysicalDisplayTokens) {
@@ -602,12 +608,6 @@
     return displayIds;
 }
 
-status_t SurfaceFlinger::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) const {
-    Mutex::Autolock lock(mStateLock);
-    *id = getInternalDisplayIdLocked();
-    return NO_ERROR;
-}
-
 sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
     Mutex::Autolock lock(mStateLock);
     return getPhysicalDisplayTokenLocked(displayId);
@@ -658,7 +658,7 @@
     const String16 name("window");
     mWindowManager = defaultServiceManager()->getService(name);
     if (mWindowManager != 0) {
-        mWindowManager->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
+        mWindowManager->linkToDeath(sp<IBinder::DeathRecipient>::fromExisting(this));
     }
 
     // stop boot animation
@@ -681,8 +681,12 @@
 
         readPersistentProperties();
         mPowerAdvisor->onBootFinished();
-        mPowerAdvisor->enablePowerHint(mFlagManager.use_adpf_cpu_hint());
-        if (mPowerAdvisor->usePowerHintSession()) {
+        const bool powerHintEnabled = mFlagManager.use_adpf_cpu_hint();
+        mPowerAdvisor->enablePowerHint(powerHintEnabled);
+        const bool powerHintUsed = mPowerAdvisor->usePowerHintSession();
+        ALOGD("Power hint is %s",
+              powerHintUsed ? "supported" : (powerHintEnabled ? "unsupported" : "disabled"));
+        if (powerHintUsed) {
             std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid();
             std::vector<int32_t> tidList;
             tidList.emplace_back(gettid());
@@ -1044,12 +1048,14 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* stats) {
-    if (!stats) {
+status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* outStats) {
+    if (!outStats) {
         return BAD_VALUE;
     }
 
-    *stats = mScheduler->getDisplayStatInfo(systemTime());
+    const auto& schedule = mScheduler->getVsyncSchedule();
+    outStats->vsyncTime = schedule.vsyncDeadlineAfter(scheduler::SchedulerClock::now()).ns();
+    outStats->vsyncPeriod = schedule.period().ns();
     return NO_ERROR;
 }
 
@@ -1304,17 +1310,25 @@
 }
 
 status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayToken,
-                                                   ui::DisplayPrimaries &primaries) {
+                                                   ui::DisplayPrimaries& primaries) {
     if (!displayToken) {
         return BAD_VALUE;
     }
 
-    // Currently we only support this API for a single internal display.
-    if (getInternalDisplayToken() != displayToken) {
+    Mutex::Autolock lock(mStateLock);
+
+    const auto display = getDisplayDeviceLocked(displayToken);
+    if (!display) {
         return NAME_NOT_FOUND;
     }
 
-    memcpy(&primaries, &mInternalDisplayPrimaries, sizeof(ui::DisplayPrimaries));
+    const auto connectionType = display->getConnectionType();
+    if (connectionType != ui::DisplayConnectionType::Internal) {
+        return INVALID_OPERATION;
+    }
+
+    // TODO(b/229846990): For now, assume that all internal displays have the same primaries.
+    primaries = mInternalDisplayPrimaries;
     return NO_ERROR;
 }
 
@@ -1429,18 +1443,6 @@
     }));
 }
 
-status_t SurfaceFlinger::clearAnimationFrameStats() {
-    Mutex::Autolock _l(mStateLock);
-    mAnimFrameTracker.clearStats();
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const {
-    Mutex::Autolock _l(mStateLock);
-    mAnimFrameTracker.getStats(outStats);
-    return NO_ERROR;
-}
-
 status_t SurfaceFlinger::overrideHdrTypes(const sp<IBinder>& displayToken,
                                           const std::vector<ui::Hdr>& hdrTypes) {
     Mutex::Autolock lock(mStateLock);
@@ -1550,12 +1552,10 @@
 
 status_t SurfaceFlinger::injectVSync(nsecs_t when) {
     Mutex::Autolock lock(mStateLock);
-    const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(when);
-    const auto expectedPresent = calculateExpectedPresentTime(stats);
-    return mScheduler->injectVSync(when, /*expectedVSyncTime=*/expectedPresent,
-                                   /*deadlineTimestamp=*/expectedPresent)
-            ? NO_ERROR
-            : BAD_VALUE;
+    const nsecs_t expectedPresentTime = calculateExpectedPresentTime(TimePoint::fromNs(when)).ns();
+    const nsecs_t deadlineTimestamp = expectedPresentTime;
+    return mScheduler->injectVSync(when, expectedPresentTime, deadlineTimestamp) ? NO_ERROR
+                                                                                 : BAD_VALUE;
 }
 
 status_t SurfaceFlinger::getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) {
@@ -1673,7 +1673,7 @@
     }
 
     const char* const whence = __func__;
-    return ftl::chain(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
+    return ftl::Future(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
                if (const auto display = getDisplayDeviceLocked(displayToken)) {
                    const bool supportsDisplayBrightnessCommand =
                            getHwComposer().getComposer()->isSupported(
@@ -1711,7 +1711,7 @@
                    return ftl::yield<status_t>(NAME_NOT_FOUND);
                }
            }))
-            .then([](std::future<status_t> task) { return task; })
+            .then([](ftl::Future<status_t> task) { return task; })
             .get();
 }
 
@@ -1790,10 +1790,11 @@
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
-        ISurfaceComposer::VsyncSource vsyncSource,
-        ISurfaceComposer::EventRegistrationFlags eventRegistration) {
+        gui::ISurfaceComposer::VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) {
     const auto& handle =
-            vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;
+            vsyncSource == gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger
+            ? mSfConnectionHandle
+            : mAppConnectionHandle;
 
     return mScheduler->createDisplayEventConnection(handle, eventRegistration);
 }
@@ -1866,11 +1867,6 @@
     }
 }
 
-void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
-    std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
-    *compositorTiming = getBE().mCompositorTiming;
-}
-
 void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId,
                                           hal::Connection connection) {
     const bool connected = connection == hal::Connection::CONNECTED;
@@ -1931,18 +1927,15 @@
     }));
 }
 
-SurfaceFlinger::FenceWithFenceTime SurfaceFlinger::previousFrameFence() {
-    const auto now = systemTime();
-    const auto vsyncPeriod = mScheduler->getDisplayStatInfo(now).vsyncPeriod;
-    const bool expectedPresentTimeIsTheNextVsync = mExpectedPresentTime - now <= vsyncPeriod;
-    return expectedPresentTimeIsTheNextVsync ? mPreviousPresentFences[0]
-                                             : mPreviousPresentFences[1];
+auto SurfaceFlinger::getPreviousPresentFence(TimePoint frameTime, Period vsyncPeriod)
+        -> const FenceTimePtr& {
+    const bool isTwoVsyncsAhead = mExpectedPresentTime - frameTime > vsyncPeriod;
+    const size_t i = static_cast<size_t>(isTwoVsyncsAhead);
+    return mPreviousPresentFences[i].fenceTime;
 }
 
-bool SurfaceFlinger::previousFramePending(int graceTimeMs) {
+bool SurfaceFlinger::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
     ATRACE_CALL();
-    const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime;
-
     if (fence == FenceTime::NO_FENCE) {
         return false;
     }
@@ -1953,54 +1946,38 @@
     return status == -ETIME;
 }
 
-nsecs_t SurfaceFlinger::previousFramePresentTime() {
-    const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime;
+TimePoint SurfaceFlinger::calculateExpectedPresentTime(TimePoint frameTime) const {
+    const auto& schedule = mScheduler->getVsyncSchedule();
 
-    if (fence == FenceTime::NO_FENCE) {
-        return Fence::SIGNAL_TIME_INVALID;
+    const TimePoint vsyncDeadline = schedule.vsyncDeadlineAfter(frameTime);
+    if (mVsyncModulator->getVsyncConfig().sfOffset > 0) {
+        return vsyncDeadline;
     }
 
-    return fence->getSignalTime();
+    // Inflate the expected present time if we're targeting the next vsync.
+    return vsyncDeadline + schedule.period();
 }
 
-nsecs_t SurfaceFlinger::calculateExpectedPresentTime(DisplayStatInfo stats) const {
-    // Inflate the expected present time if we're targetting the next vsync.
-    return mVsyncModulator->getVsyncConfig().sfOffset > 0 ? stats.vsyncTime
-                                                          : stats.vsyncTime + stats.vsyncPeriod;
-}
-
-bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
+bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint 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.
-    if (expectedVsyncTime >= frameTime) {
-        mExpectedPresentTime = expectedVsyncTime;
-    } else {
-        const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(frameTime);
-        mExpectedPresentTime = calculateExpectedPresentTime(stats);
-    }
-
-    const nsecs_t lastScheduledPresentTime = mScheduledPresentTime;
+    // The expectedVsyncTime, which was predicted when this frame was scheduled, is normally in the
+    // future relative to frameTime, but may not be for delayed frames. Adjust mExpectedPresentTime
+    // accordingly, but not mScheduledPresentTime.
+    const TimePoint 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;
-    }();
-    ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, vsyncId, vsyncIn,
+    // Calculate the expected present time once and use the cached value throughout this frame to
+    // make sure all layers are seeing this same value.
+    mExpectedPresentTime = expectedVsyncTime >= frameTime ? expectedVsyncTime
+                                                          : calculateExpectedPresentTime(frameTime);
+
+    ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, vsyncId.value,
+                  ticks<std::milli, float>(mExpectedPresentTime - scheduler::SchedulerClock::now()),
                   mExpectedPresentTime == expectedVsyncTime ? "" : " (adjusted)");
 
+    const Period vsyncPeriod = mScheduler->getVsyncSchedule().period();
+    const FenceTimePtr& previousPresentFence = getPreviousPresentFence(frameTime, vsyncPeriod);
+
     // When Backpressure propagation is enabled we want to give a small grace period
     // for the present fence to fire instead of just giving up on this frame to handle cases
     // where present fence is just about to get signaled.
@@ -2009,7 +1986,8 @@
 
     // Pending frames may trigger backpressure propagation.
     const TracedOrdinal<bool> framePending = {"PrevFramePending",
-                                              previousFramePending(graceTimeForPresentFenceMs)};
+                                              isFencePending(previousPresentFence,
+                                                             graceTimeForPresentFenceMs)};
 
     // Frame missed counts for metrics tracking.
     // A frame is missed if the prior frame is still pending. If no longer pending,
@@ -2019,13 +1997,12 @@
     // Add some slop to correct for drift. This should generally be
     // smaller than a typical frame duration, but should not be so small
     // that it reports reasonable drift as a missed frame.
-    const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(systemTime());
-    const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2;
-    const nsecs_t previousPresentTime = previousFramePresentTime();
+    const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
+    const nsecs_t previousPresentTime = previousPresentFence->getSignalTime();
     const TracedOrdinal<bool> frameMissed = {"PrevFrameMissed",
                                              framePending ||
                                                      (previousPresentTime >= 0 &&
-                                                      (lastScheduledPresentTime <
+                                                      (lastScheduledPresentTime.ns() <
                                                        previousPresentTime - frameMissedSlop))};
     const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed",
                                                 mHadDeviceComposition && frameMissed};
@@ -2045,6 +2022,11 @@
         mGpuFrameMissedCount++;
     }
 
+    if (mTracingEnabledChanged) {
+        mLayerTracingEnabled = mLayerTracing.isEnabled();
+        mTracingEnabledChanged = false;
+    }
+
     // If we are in the middle of a mode change and the fence hasn't
     // fired yet just wait for the next commit.
     if (mSetActiveModePending) {
@@ -2069,9 +2051,31 @@
         }
     }
 
-    if (mTracingEnabledChanged) {
-        mLayerTracingEnabled = mLayerTracing.isEnabled();
-        mTracingEnabledChanged = false;
+    // 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();
+        const nsecs_t vsyncPeriod = display->getActiveMode()->getVsyncPeriod();
+        mPowerAdvisor->setCommitStart(frameTime.ns());
+        mPowerAdvisor->setExpectedPresentTime(mExpectedPresentTime.ns());
+
+        // Frame delay is how long we should have minus how long we actually have.
+        const Duration idealSfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration;
+        const Duration frameDelay = idealSfWorkDuration - (mExpectedPresentTime - frameTime);
+
+        mPowerAdvisor->setFrameDelay(frameDelay.ns());
+        mPowerAdvisor->setTotalFrameTargetWorkDuration(idealSfWorkDuration.ns());
+        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 (mRefreshRateOverlaySpinner) {
@@ -2084,11 +2088,13 @@
     // Composite if transactions were committed, or if requested by HWC.
     bool mustComposite = mMustComposite.exchange(false);
     {
-        mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(stats.vsyncPeriod));
+        mFrameTimeline->setSfWakeUp(vsyncId.value, frameTime.ns(),
+                                    Fps::fromPeriodNsecs(vsyncPeriod.ns()));
 
         bool needsTraversal = false;
         if (clearTransactionFlags(eTransactionFlushNeeded)) {
-            needsTraversal |= commitCreatedLayers();
+            needsTraversal |= commitMirrorDisplays(vsyncId);
+            needsTraversal |= commitCreatedLayers(vsyncId);
             needsTraversal |= flushTransactionQueues(vsyncId);
         }
 
@@ -2133,32 +2139,48 @@
 
     if (mLayerTracingEnabled && !mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
         // This will block and tracing should only be enabled for debugging.
-        mLayerTracing.notify(mVisibleRegionsDirty, frameTime);
+        mLayerTracing.notify(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value);
     }
+    mLastCommittedVsyncId = vsyncId;
 
     persistDisplayBrightness(mustComposite);
 
     return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
 }
 
-void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId)
+void SurfaceFlinger::composite(TimePoint frameTime, VsyncId vsyncId)
         FTL_FAKE_GUARD(kMainThreadContext) {
-    ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId);
-
-    if (mPowerHintSessionData.sessionEnabled) {
-        mPowerHintSessionData.compositeStart = systemTime();
-    }
+    ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId.value);
 
     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);
     });
+
+    if (DOES_CONTAIN_BORDER) {
+        refreshArgs.borderInfoList.clear();
+        mDrawingState.traverse([&refreshArgs](Layer* layer) {
+            if (layer->isBorderEnabled()) {
+                compositionengine::BorderRenderInfo info;
+                info.width = layer->getBorderWidth();
+                info.color = layer->getBorderColor();
+                layer->traverse(LayerVector::StateSet::Drawing, [&info](Layer* ilayer) {
+                    info.layerIds.push_back(ilayer->getSequence());
+                });
+                refreshArgs.borderInfoList.emplace_back(std::move(info));
+            }
+        });
+    }
+
     refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
     for (auto layer : mLayersWithQueuedFrames) {
         if (auto layerFE = layer->getCompositionEngineLayerFE())
@@ -2188,13 +2210,13 @@
         refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugFlashDelay);
     }
 
-    const auto expectedPresentTime = mExpectedPresentTime.load();
-    const auto prevVsyncTime = mScheduler->getPreviousVsyncFrom(expectedPresentTime);
+    const auto prevVsyncTime = mExpectedPresentTime - mScheduler->getVsyncSchedule().period();
     const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
+
     refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
     refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime;
     refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
-    refreshArgs.expectedPresentTime = expectedPresentTime;
+    refreshArgs.expectedPresentTime = mExpectedPresentTime.ns();
 
     // Store the present time just before calling to the composition engine so we could notify
     // the scheduler.
@@ -2202,17 +2224,21 @@
 
     mCompositionEngine->present(refreshArgs);
 
-    if (mPowerHintSessionData.sessionEnabled) {
-        mPowerHintSessionData.presentEnd = systemTime();
-    }
+    mTimeStats->recordFrameDuration(frameTime.ns(), 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);
     }
 
-    postFrame();
     postComposition();
 
     const bool prevFrameHadClientComposition = mHadClientComposition;
@@ -2242,7 +2268,7 @@
     mLayersWithQueuedFrames.clear();
     if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
         // This will block and should only be used for debugging.
-        mLayerTracing.notify(mVisibleRegionsDirty, frameTime);
+        mLayerTracing.notify(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value);
     }
 
     mVisibleRegionsWereDirtyThisFrame = mVisibleRegionsDirty; // Cache value for use in post-comp
@@ -2252,11 +2278,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());
     }
 }
 
@@ -2275,66 +2298,6 @@
     mLayersPendingRefresh.clear();
 }
 
-void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
-                                            std::shared_ptr<FenceTime>& presentFenceTime) {
-    // Update queue of past composite+present times and determine the
-    // most recently known composite to present latency.
-    getBE().mCompositePresentTimes.push({compositeTime, presentFenceTime});
-    nsecs_t compositeToPresentLatency = -1;
-    while (!getBE().mCompositePresentTimes.empty()) {
-        SurfaceFlingerBE::CompositePresentTime& cpt = getBE().mCompositePresentTimes.front();
-        // Cached values should have been updated before calling this method,
-        // which helps avoid duplicate syscalls.
-        nsecs_t displayTime = cpt.display->getCachedSignalTime();
-        if (displayTime == Fence::SIGNAL_TIME_PENDING) {
-            break;
-        }
-        compositeToPresentLatency = displayTime - cpt.composite;
-        getBE().mCompositePresentTimes.pop();
-    }
-
-    // Don't let mCompositePresentTimes grow unbounded, just in case.
-    while (getBE().mCompositePresentTimes.size() > 16) {
-        getBE().mCompositePresentTimes.pop();
-    }
-
-    setCompositorTimingSnapped(stats, compositeToPresentLatency);
-}
-
-void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats,
-                                                nsecs_t compositeToPresentLatency) {
-    // Avoid division by 0 by defaulting to 60Hz
-    const auto vsyncPeriod = stats.vsyncPeriod ?: (60_Hz).getPeriodNsecs();
-
-    // Integer division and modulo round toward 0 not -inf, so we need to
-    // treat negative and positive offsets differently.
-    nsecs_t idealLatency = (mVsyncConfiguration->getCurrentConfigs().late.sfOffset > 0)
-            ? (vsyncPeriod -
-               (mVsyncConfiguration->getCurrentConfigs().late.sfOffset % vsyncPeriod))
-            : ((-mVsyncConfiguration->getCurrentConfigs().late.sfOffset) % vsyncPeriod);
-
-    // Just in case mVsyncConfiguration->getCurrentConfigs().late.sf == -vsyncInterval.
-    if (idealLatency <= 0) {
-        idealLatency = vsyncPeriod;
-    }
-
-    // Snap the latency to a value that removes scheduling jitter from the
-    // composition and present times, which often have >1ms of jitter.
-    // Reducing jitter is important if an app attempts to extrapolate
-    // something (such as user input) to an accurate diasplay time.
-    // Snapping also allows an app to precisely calculate
-    // mVsyncConfiguration->getCurrentConfigs().late.sf with (presentLatency % interval).
-    const nsecs_t bias = vsyncPeriod / 2;
-    const int64_t extraVsyncs = ((compositeToPresentLatency - idealLatency + bias) / vsyncPeriod);
-    const nsecs_t snappedCompositeToPresentLatency =
-            (extraVsyncs > 0) ? idealLatency + (extraVsyncs * vsyncPeriod) : idealLatency;
-
-    std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
-    getBE().mCompositorTiming.deadline = stats.vsyncTime - idealLatency;
-    getBE().mCompositorTiming.interval = vsyncPeriod;
-    getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
-}
-
 bool SurfaceFlinger::isHdrLayer(Layer* layer) const {
     // Treat all layers as non-HDR if:
     // 1. They do not have a valid HDR dataspace. Currently we treat those as PQ or HLG. and
@@ -2391,56 +2354,55 @@
 
 void SurfaceFlinger::postComposition() {
     ATRACE_CALL();
-    ALOGV("postComposition");
+    ALOGV(__func__);
 
     const auto* display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
 
-    getBE().mGlCompositionDoneTimeline.updateSignalTimes();
     std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
     if (display && display->getCompositionDisplay()->getState().usesClientComposition) {
         glCompositionDoneFenceTime =
                 std::make_shared<FenceTime>(display->getCompositionDisplay()
                                                     ->getRenderSurface()
                                                     ->getClientTargetAcquireFence());
-        getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
     } else {
         glCompositionDoneFenceTime = FenceTime::NO_FENCE;
     }
 
-    getBE().mDisplayTimeline.updateSignalTimes();
     mPreviousPresentFences[1] = mPreviousPresentFences[0];
-    mPreviousPresentFences[0].fence =
+
+    auto presentFence =
             display ? getHwComposer().getPresentFence(display->getPhysicalId()) : Fence::NO_FENCE;
-    mPreviousPresentFences[0].fenceTime =
-            std::make_shared<FenceTime>(mPreviousPresentFences[0].fence);
 
-    getBE().mDisplayTimeline.push(mPreviousPresentFences[0].fenceTime);
+    auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
+    mPreviousPresentFences[0] = {presentFence, presentFenceTime};
 
-    nsecs_t now = systemTime();
+    const TimePoint presentTime = scheduler::SchedulerClock::now();
 
     // Set presentation information before calling Layer::releasePendingBuffer, such that jank
     // information from previous' frame classification is already available when sending jank info
     // to clients, so they get jank classification as early as possible.
-    mFrameTimeline->setSfPresent(/* sfPresentTime */ now, mPreviousPresentFences[0].fenceTime,
-                                 glCompositionDoneFenceTime);
-
-    const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now);
+    mFrameTimeline->setSfPresent(presentTime.ns(), presentFenceTime, glCompositionDoneFenceTime);
 
     // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might
     // be sampled a little later than when we started doing work for this frame,
-    // but that should be okay since updateCompositorTiming has snapping logic.
-    updateCompositorTiming(stats, mCompositionEngine->getLastFrameRefreshTimestamp(),
-                           mPreviousPresentFences[0].fenceTime);
-    CompositorTiming compositorTiming;
-    {
-        std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
-        compositorTiming = getBE().mCompositorTiming;
-    }
+    // but that should be okay since CompositorTiming has snapping logic.
+    const TimePoint compositeTime =
+            TimePoint::fromNs(mCompositionEngine->getLastFrameRefreshTimestamp());
+    const Duration presentLatency =
+            mPresentLatencyTracker.trackPendingFrame(compositeTime, presentFenceTime);
+
+    const auto& schedule = mScheduler->getVsyncSchedule();
+    const TimePoint vsyncDeadline = schedule.vsyncDeadlineAfter(presentTime);
+    const Period vsyncPeriod = schedule.period();
+    const nsecs_t vsyncPhase = mVsyncConfiguration->getCurrentConfigs().late.sfOffset;
+
+    const CompositorTiming compositorTiming(vsyncDeadline.ns(), vsyncPeriod.ns(), vsyncPhase,
+                                            presentLatency.ns());
 
     for (const auto& layer: mLayersWithQueuedFrames) {
-        layer->onPostComposition(display, glCompositionDoneFenceTime,
-                                 mPreviousPresentFences[0].fenceTime, compositorTiming);
-        layer->releasePendingBuffer(/*dequeueReadyTime*/ now);
+        layer->onPostComposition(display, glCompositionDoneFenceTime, presentFenceTime,
+                                 compositorTiming);
+        layer->releasePendingBuffer(presentTime.ns());
     }
 
     std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>>
@@ -2497,13 +2459,16 @@
     mSomeDataspaceChanged = false;
     mVisibleRegionsWereDirtyThisFrame = false;
 
-    mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence);
+    mTransactionCallbackInvoker.addPresentFence(std::move(presentFence));
     mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */);
     mTransactionCallbackInvoker.clearCompletedTransactions();
 
+    mTimeStats->incrementTotalFrames();
+    mTimeStats->setPresentFenceGlobal(presentFenceTime);
+
     if (display && display->isInternal() && display->getPowerMode() == hal::PowerMode::ON &&
-        mPreviousPresentFences[0].fenceTime->isValid()) {
-        mScheduler->addPresentFence(mPreviousPresentFences[0].fenceTime);
+        presentFenceTime->isValid()) {
+        mScheduler->addPresentFence(std::move(presentFenceTime));
     }
 
     const bool isDisplayConnected =
@@ -2515,24 +2480,6 @@
         }
     }
 
-    if (mAnimCompositionPending) {
-        mAnimCompositionPending = false;
-
-        if (mPreviousPresentFences[0].fenceTime->isValid()) {
-            mAnimFrameTracker.setActualPresentFence(mPreviousPresentFences[0].fenceTime);
-        } else if (isDisplayConnected) {
-            // The HWC doesn't support present fences, so use the refresh
-            // timestamp instead.
-            const nsecs_t presentTime = display->getRefreshTimestamp();
-            mAnimFrameTracker.setActualPresentTime(presentTime);
-        }
-        mAnimFrameTracker.advanceFrame();
-    }
-
-    mTimeStats->incrementTotalFrames();
-
-    mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime);
-
     const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle);
     const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle);
     mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections);
@@ -2542,21 +2489,6 @@
         return;
     }
 
-    nsecs_t currentTime = systemTime();
-    if (mHasPoweredOff) {
-        mHasPoweredOff = false;
-    } else {
-        nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
-        size_t numPeriods = static_cast<size_t>(elapsedTime / stats.vsyncPeriod);
-        if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
-            getBE().mFrameBuckets[numPeriods] += elapsedTime;
-        } else {
-            getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] += elapsedTime;
-        }
-        getBE().mTotalTime += elapsedTime;
-    }
-    getBE().mLastSwapTime = currentTime;
-
     // Cleanup any outstanding resources due to rendering a prior frame.
     getRenderEngine().cleanupPostRender();
 
@@ -2583,6 +2515,8 @@
         // getTotalSize returns the total number of buffers that were allocated by SurfaceFlinger
         ATRACE_INT64("Total Buffer Size", GraphicBufferAllocator::get().getTotalSize());
     }
+
+    logFrameStats(presentTime);
 }
 
 FloatRect SurfaceFlinger::getMaxDisplayBounds() {
@@ -2615,16 +2549,6 @@
     }
 }
 
-void SurfaceFlinger::postFrame() {
-    const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
-    if (display && getHwComposer().isConnected(display->getPhysicalId())) {
-        uint32_t flipCount = display->getPageFlipCount();
-        if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
-            logFrameStats();
-        }
-    }
-}
-
 void SurfaceFlinger::commitTransactions() {
     ATRACE_CALL();
 
@@ -2743,7 +2667,7 @@
                 state.isSecure = true; // All physical displays are currently considered secure.
                 state.displayName = std::move(info->name);
 
-                sp<IBinder> token = new BBinder();
+                sp<IBinder> token = sp<BBinder>::make();
                 mCurrentState.displays.add(token, state);
                 mPhysicalDisplayTokens.try_emplace(displayId, std::move(token));
                 mInterceptor->saveDisplayCreation(state);
@@ -2789,7 +2713,8 @@
         const DisplayDeviceState& state,
         const sp<compositionengine::DisplaySurface>& displaySurface,
         const sp<IGraphicBufferProducer>& producer) {
-    DisplayDeviceCreationArgs creationArgs(this, getHwComposer(), displayToken, compositionDisplay);
+    DisplayDeviceCreationArgs creationArgs(sp<SurfaceFlinger>::fromExisting(this), getHwComposer(),
+                                           displayToken, compositionDisplay);
     creationArgs.sequenceId = state.sequenceId;
     creationArgs.isSecure = state.isSecure;
     creationArgs.displaySurface = displaySurface;
@@ -2815,7 +2740,7 @@
     }
 
     if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) {
-        creationArgs.isPrimary = id == getInternalDisplayIdLocked();
+        creationArgs.isPrimary = id == getPrimaryDisplayIdLocked();
 
         if (useColorManagement) {
             std::vector<ColorMode> modes = getHwComposer().getColorModes(*id);
@@ -3069,6 +2994,7 @@
     const KeyedVector<wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
     if (!curr.isIdenticalTo(draw)) {
         mVisibleRegionsDirty = true;
+        mUpdateInputInfo = true;
 
         // find the displays that were removed
         // (ie: in drawing state but not in current state)
@@ -3113,6 +3039,7 @@
     if (mSomeChildrenChanged) {
         mVisibleRegionsDirty = true;
         mSomeChildrenChanged = false;
+        mUpdateInputInfo = true;
     }
 
     // Update transform hint.
@@ -3154,7 +3081,7 @@
                 }
             }
 
-            if (!hintDisplay) {
+            if (!hintDisplay && mDisplays.size() > 0) {
                 // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
                 // redraw after transform hint changes. See bug 8508397.
 
@@ -3164,7 +3091,11 @@
                 hintDisplay = getDefaultDisplayDeviceLocked();
             }
 
-            layer->updateTransformHint(hintDisplay->getTransformHint());
+            if (hintDisplay) {
+                layer->updateTransformHint(hintDisplay->getTransformHint());
+            } else {
+                ALOGW("Ignoring transform hint update for %s", layer->getDebugName());
+            }
         });
     }
 
@@ -3172,6 +3103,7 @@
         mLayersAdded = false;
         // Layers have been added.
         mVisibleRegionsDirty = true;
+        mUpdateInputInfo = true;
     }
 
     // some layers might have been removed, so
@@ -3179,19 +3111,19 @@
     if (mLayersRemoved) {
         mLayersRemoved = false;
         mVisibleRegionsDirty = true;
+        mUpdateInputInfo = true;
         mDrawingState.traverseInZOrder([&](Layer* layer) {
-            if (mLayersPendingRemoval.indexOf(layer) >= 0) {
+            if (mLayersPendingRemoval.indexOf(sp<Layer>::fromExisting(layer)) >= 0) {
                 // this layer is not visible anymore
                 Region visibleReg;
                 visibleReg.set(layer->getScreenBounds());
-                invalidateLayerStack(layer, visibleReg);
+                invalidateLayerStack(sp<Layer>::fromExisting(layer), visibleReg);
             }
         });
     }
 
     doCommitTransactions();
     signalSynchronousTransactions(CountDownLatch::eSyncTransaction);
-    mAnimTransactionPending = false;
 }
 
 void SurfaceFlinger::updateInputFlinger() {
@@ -3203,33 +3135,38 @@
     std::vector<WindowInfo> windowInfos;
     std::vector<DisplayInfo> displayInfos;
     bool updateWindowInfo = false;
-    if (mVisibleRegionsDirty || mInputInfoChanged) {
-        mInputInfoChanged = false;
+    if (mUpdateInputInfo) {
+        mUpdateInputInfo = false;
         updateWindowInfo = true;
         buildWindowInfos(windowInfos, displayInfos);
-    }
-    if (!updateWindowInfo && mInputWindowCommands.empty()) {
+    } else if (mInputWindowCommands.empty()) {
         return;
     }
-    BackgroundExecutor::getInstance().execute([updateWindowInfo,
-                                               windowInfos = std::move(windowInfos),
-                                               displayInfos = std::move(displayInfos),
-                                               inputWindowCommands =
-                                                       std::move(mInputWindowCommands),
-                                               inputFlinger = mInputFlinger, this]() {
+
+    BackgroundExecutor::getInstance().sendCallbacks({[updateWindowInfo,
+                                                      windowInfos = std::move(windowInfos),
+                                                      displayInfos = std::move(displayInfos),
+                                                      inputWindowCommands =
+                                                              std::move(mInputWindowCommands),
+                                                      inputFlinger = mInputFlinger, this]() {
         ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
         if (updateWindowInfo) {
-            mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
-                                                            inputWindowCommands.syncInputWindows);
-        } else if (inputWindowCommands.syncInputWindows) {
-            // If the caller requested to sync input windows, but there are no
-            // changes to input windows, notify immediately.
-            windowInfosReported();
+            mWindowInfosListenerInvoker
+                    ->windowInfosChanged(windowInfos, displayInfos,
+                                         inputWindowCommands.windowInfosReportedListeners);
+        } else {
+            // If there are listeners but no changes to input windows, call the listeners
+            // immediately.
+            for (const auto& listener : inputWindowCommands.windowInfosReportedListeners) {
+                if (IInterface::asBinder(listener)->isBinderAlive()) {
+                    listener->onWindowInfosReported();
+                }
+            }
         }
         for (const auto& focusRequest : inputWindowCommands.focusRequests) {
             inputFlinger->setFocusedWindow(focusRequest);
         }
-    });
+    }});
 
     mInputWindowCommands.clear();
 }
@@ -3295,11 +3232,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();
@@ -3411,12 +3348,13 @@
                                              mInterceptor->saveVSyncEvent(timestamp);
                                          });
 
-    mScheduler->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(),
-                          configs.late.sfWorkDuration);
+    mScheduler->initVsync(mScheduler->getVsyncSchedule().getDispatch(),
+                          *mFrameTimeline->getTokenManager(), configs.late.sfWorkDuration);
 
     mRegionSamplingThread =
-            new RegionSamplingThread(*this, RegionSamplingThread::EnvironmentTimingTunables());
-    mFpsReporter = new FpsReporter(*mFrameTimeline, *this);
+            sp<RegionSamplingThread>::make(*this,
+                                           RegionSamplingThread::EnvironmentTimingTunables());
+    mFpsReporter = sp<FpsReporter>::make(*mFrameTimeline, *this);
     // Dispatch a mode change request for the primary display on scheduler
     // initialization, so that the EventThreads always contain a reference to a
     // prior configuration.
@@ -3455,6 +3393,15 @@
                 l->latchAndReleaseBuffer();
             }
 
+            // If a layer has a parent, we allow it to out-live it's handle
+            // with the idea that the parent holds a reference and will eventually
+            // be cleaned up. However no one cleans up the top-level so we do so
+            // here.
+            if (l->isAtRoot()) {
+                l->setIsAtRoot(false);
+                mCurrentState.layersSortedByZ.remove(l);
+            }
+
             // If the layer has been removed and has no parent, then it will not be reachable
             // when traversing layers on screen. Add the layer to the offscreenLayers set to
             // ensure we can copy its current to drawing state.
@@ -3465,10 +3412,6 @@
         mLayersPendingRemoval.clear();
     }
 
-    // If this transaction is part of a window animation then the next frame
-    // we composite should be considered an animation as well.
-    mAnimCompositionPending = mAnimTransactionPending;
-
     mDrawingState = mCurrentState;
     // clear the "changed" flags in current state
     mCurrentState.colorMatrixChanged = false;
@@ -3514,8 +3457,6 @@
     bool frameQueued = false;
     bool newDataLatched = false;
 
-    const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
-
     // Store the set of layers that need updates. This set must not change as
     // buffers are being latched, as this could result in a deadlock.
     // Example: Two producers share the same command stream and:
@@ -3535,12 +3476,7 @@
 
         if (layer->hasReadyFrame()) {
             frameQueued = true;
-            if (layer->shouldPresentNow(expectedPresentTime)) {
-                mLayersWithQueuedFrames.emplace(layer);
-            } else {
-                ATRACE_NAME("!layer->shouldPresentNow()");
-                layer->useEmptyDamage();
-            }
+            mLayersWithQueuedFrames.emplace(sp<Layer>::fromExisting(layer));
         } else {
             layer->useEmptyDamage();
         }
@@ -3561,7 +3497,7 @@
         Mutex::Autolock lock(mStateLock);
 
         for (const auto& layer : mLayersWithQueuedFrames) {
-            if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) {
+            if (layer->latchBuffer(visibleRegions, latchTime)) {
                 mLayersPendingRefresh.push_back(layer);
                 newDataLatched = true;
             }
@@ -3595,9 +3531,9 @@
 status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
                                         const sp<Layer>& layer, const wp<Layer>& parent,
                                         bool addToRoot, uint32_t* outTransformHint) {
-    if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) {
+    if (mNumLayers >= MAX_LAYERS) {
         ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
-              ISurfaceComposer::MAX_LAYERS);
+              MAX_LAYERS);
         static_cast<void>(mScheduler->schedule([=] {
             ALOGE("Dumping random sampling of on-screen layers: ");
             mDrawingState.traverse([&](Layer *layer) {
@@ -3653,48 +3589,30 @@
     }
 }
 
-bool SurfaceFlinger::stopTransactionProcessing(
-        const std::unordered_set<sp<IBinder>, SpHash<IBinder>>&
-                applyTokensWithUnsignaledTransactions) const {
-    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) {
-        // if we are in LatchUnsignaledConfig::AutoSingleLayer
-        // then we should have only one applyToken for processing.
-        // so we can stop further transactions on this applyToken.
-        return !applyTokensWithUnsignaledTransactions.empty();
-    }
-
-    return false;
-}
-
-int SurfaceFlinger::flushUnsignaledPendingTransactionQueues(
-        std::vector<TransactionState>& transactions,
-        std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
-        std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions) {
-    return flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
-                                         applyTokensWithUnsignaledTransactions,
-                                         /*tryApplyUnsignaled*/ true);
-}
-
 int SurfaceFlinger::flushPendingTransactionQueues(
         std::vector<TransactionState>& transactions,
         std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
-        std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions,
         bool tryApplyUnsignaled) {
+    std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions;
     int transactionsPendingBarrier = 0;
     auto it = mPendingTransactionQueues.begin();
     while (it != mPendingTransactionQueues.end()) {
         auto& [applyToken, transactionQueue] = *it;
         while (!transactionQueue.empty()) {
-            if (stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) {
+            // if we are in LatchUnsignaledConfig::AutoSingleLayer
+            // then we should have only one applyToken for processing.
+            // so we can stop further transactions on this applyToken.
+            if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer &&
+                !applyTokensWithUnsignaledTransactions.empty()) {
                 ATRACE_NAME("stopTransactionProcessing");
                 break;
             }
 
             auto& transaction = transactionQueue.front();
             const auto ready =
-                    transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
+                    transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo,
                                                   transaction.isAutoTimestamp,
-                                                  transaction.desiredPresentTime,
+                                                  TimePoint::fromNs(transaction.desiredPresentTime),
                                                   transaction.originUid, transaction.states,
                                                   bufferLayersReadyToPresent, transactions.size(),
                                                   tryApplyUnsignaled);
@@ -3726,11 +3644,12 @@
 
             transactions.emplace_back(std::move(transaction));
             transactionQueue.pop();
+            mPendingTransactionCount--;
+            ATRACE_INT("TransactionQueue", mPendingTransactionCount.load());
         }
 
         if (transactionQueue.empty()) {
             it = mPendingTransactionQueues.erase(it);
-            mTransactionQueueCV.broadcast();
         } else {
             it = std::next(it, 1);
         }
@@ -3738,73 +3657,23 @@
     return transactionsPendingBarrier;
 }
 
-bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) {
+bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) {
     // to prevent onHandleDestroyed from being called while the lock is held,
     // we must keep a copy of the transactions (specifically the composer
     // states) around outside the scope of the lock
     std::vector<TransactionState> transactions;
     // Layer handles that have transactions with buffers that are ready to be applied.
     std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>> bufferLayersReadyToPresent;
-    std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions;
     {
         Mutex::Autolock _l(mStateLock);
         {
-            Mutex::Autolock _l(mQueueLock);
-
-            int lastTransactionsPendingBarrier = 0;
-            int transactionsPendingBarrier = 0;
-            // First collect transactions from the pending transaction queues.
-            // We are not allowing unsignaled buffers here as we want to
-            // collect all the transactions from applyTokens that are ready first.
-            transactionsPendingBarrier =
-                    flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
-                            applyTokensWithUnsignaledTransactions, /*tryApplyUnsignaled*/ false);
-
-            // Second, collect transactions from the transaction queue.
-            // Here as well we are not allowing unsignaled buffers for the same
-            // reason as above.
-            while (!mTransactionQueue.empty()) {
-                auto& transaction = mTransactionQueue.front();
-                const bool pendingTransactions =
-                        mPendingTransactionQueues.find(transaction.applyToken) !=
-                        mPendingTransactionQueues.end();
-                const auto ready = [&]() REQUIRES(mStateLock) {
-                    if (pendingTransactions) {
-                        ATRACE_NAME("pendingTransactions");
-                        return TransactionReadiness::NotReady;
-                    }
-
-                    return transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
-                                                         transaction.isAutoTimestamp,
-                                                         transaction.desiredPresentTime,
-                                                         transaction.originUid, transaction.states,
-                                                         bufferLayersReadyToPresent,
-                                                         transactions.size(),
-                                                         /*tryApplyUnsignaled*/ false);
-                }();
-                ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
-                if (ready != TransactionReadiness::Ready) {
-                    if (ready == TransactionReadiness::NotReadyBarrier) {
-                        transactionsPendingBarrier++;
-                    }
-                    mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction));
-                } else {
-                    transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
-                        const bool frameNumberChanged = state.bufferData->flags.test(
-                                BufferData::BufferDataChange::frameNumberChanged);
-                        if (frameNumberChanged) {
-                            bufferLayersReadyToPresent[state.surface] = state.bufferData->frameNumber;
-                        } else {
-                            // Barrier function only used for BBQ which always includes a frame number.
-                            // This value only used for barrier logic.
-                            bufferLayersReadyToPresent[state.surface] =
-                                std::numeric_limits<uint64_t>::max();
-                        }
-                    });
-                    transactions.emplace_back(std::move(transaction));
+            while (!mLocklessTransactionQueue.isEmpty()) {
+                auto maybeTransaction = mLocklessTransactionQueue.pop();
+                if (!maybeTransaction.has_value()) {
+                    break;
                 }
-                mTransactionQueue.pop_front();
-                ATRACE_INT("TransactionQueue", mTransactionQueue.size());
+                auto transaction = maybeTransaction.value();
+                mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction));
             }
 
             // Transactions with a buffer pending on a barrier may be on a different applyToken
@@ -3817,20 +3686,21 @@
             // loop through flushPendingTransactionQueues until we perform an iteration
             // where the number of transactionsPendingBarrier doesn't change. This way
             // we can continue to resolve dependency chains of barriers as far as possible.
-            while (lastTransactionsPendingBarrier != transactionsPendingBarrier) {
+            int lastTransactionsPendingBarrier = 0;
+            int transactionsPendingBarrier = 0;
+            do {
                 lastTransactionsPendingBarrier = transactionsPendingBarrier;
                 transactionsPendingBarrier =
-                    flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
-                        applyTokensWithUnsignaledTransactions,
-                        /*tryApplyUnsignaled*/ false);
-            }
+                        flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
+                                                      /*tryApplyUnsignaled*/ false);
+            } while (lastTransactionsPendingBarrier != transactionsPendingBarrier);
 
             // We collected all transactions that could apply without latching unsignaled buffers.
             // If we are allowing latch unsignaled of some form, now it's the time to go over the
             // transactions that were not applied and try to apply them unsignaled.
             if (enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
-                flushUnsignaledPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
-                                                        applyTokensWithUnsignaledTransactions);
+                flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
+                                              /*tryApplyUnsignaled*/ true);
             }
 
             return applyTransactions(transactions, vsyncId);
@@ -3839,7 +3709,7 @@
 }
 
 bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions,
-                                       int64_t vsyncId) {
+                                       VsyncId vsyncId) {
     bool needsTraversal = false;
     // Now apply all transactions.
     for (auto& transaction : transactions) {
@@ -3859,37 +3729,37 @@
     }
 
     if (mTransactionTracing) {
-        mTransactionTracing->addCommittedTransactions(transactions, vsyncId);
+        mTransactionTracing->addCommittedTransactions(transactions, vsyncId.value);
     }
     return needsTraversal;
 }
 
 bool SurfaceFlinger::transactionFlushNeeded() {
-    Mutex::Autolock _l(mQueueLock);
-    return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty();
+    return !mPendingTransactionQueues.empty() || !mLocklessTransactionQueue.isEmpty();
 }
 
-bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const {
-    // The amount of time SF can delay a frame if it is considered early based
-    // on the VsyncModulator::VsyncConfig::appWorkDuration
-    constexpr static std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms;
-
-    const auto currentVsyncPeriod = mScheduler->getDisplayStatInfo(systemTime()).vsyncPeriod;
-    const auto earlyLatchVsyncThreshold = currentVsyncPeriod / 2;
-
-    const auto prediction = mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId);
-    if (!prediction.has_value()) {
+bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId) const {
+    const auto prediction =
+            mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId.value);
+    if (!prediction) {
         return false;
     }
 
-    if (std::abs(prediction->presentTime - expectedPresentTime) >=
-        kEarlyLatchMaxThreshold.count()) {
+    const auto predictedPresentTime = TimePoint::fromNs(prediction->presentTime);
+
+    // The duration for which SF can delay a frame if it is considered early based on the
+    // VsyncModulator::VsyncConfig::appWorkDuration.
+    if (constexpr std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms;
+        std::chrono::abs(predictedPresentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold) {
         return false;
     }
 
-    return prediction->presentTime >= expectedPresentTime &&
-            prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold;
+    const Duration earlyLatchVsyncThreshold = mScheduler->getVsyncSchedule().period() / 2;
+
+    return predictedPresentTime >= expectedPresentTime &&
+            predictedPresentTime - expectedPresentTime >= earlyLatchVsyncThreshold;
 }
+
 bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state,
                                            size_t numStates, size_t totalTXapplied) const {
     if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
@@ -3937,36 +3807,37 @@
 }
 
 auto SurfaceFlinger::transactionIsReadyToBeApplied(
-        const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
-        uid_t originUid, const Vector<ComposerState>& states,
-        const std::unordered_map<
-            sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
+        TransactionState& transaction, const FrameTimelineInfo& info, bool isAutoTimestamp,
+        TimePoint desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states,
+        const std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>&
+                bufferLayersReadyToPresent,
         size_t totalTXapplied, bool tryApplyUnsignaled) const -> TransactionReadiness {
     ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId);
-    const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
     // Do not present if the desiredPresentTime has not passed unless it is more than one second
     // in the future. We ignore timestamps more than 1 second in the future for stability reasons.
-    if (!isAutoTimestamp && desiredPresentTime >= expectedPresentTime &&
-        desiredPresentTime < expectedPresentTime + s2ns(1)) {
+    if (!isAutoTimestamp && desiredPresentTime >= mExpectedPresentTime &&
+        desiredPresentTime < mExpectedPresentTime + 1s) {
         ATRACE_NAME("not current");
         return TransactionReadiness::NotReady;
     }
 
-    if (!mScheduler->isVsyncValid(expectedPresentTime, originUid)) {
+    if (!mScheduler->isVsyncValid(mExpectedPresentTime, originUid)) {
         ATRACE_NAME("!isVsyncValid");
         return TransactionReadiness::NotReady;
     }
 
     // If the client didn't specify desiredPresentTime, use the vsyncId to determine the expected
     // present time of this transaction.
-    if (isAutoTimestamp && frameIsEarly(expectedPresentTime, info.vsyncId)) {
+    if (isAutoTimestamp && frameIsEarly(mExpectedPresentTime, VsyncId{info.vsyncId})) {
         ATRACE_NAME("frameIsEarly");
         return TransactionReadiness::NotReady;
     }
 
     bool fenceUnsignaled = false;
+    auto queueProcessTime = systemTime();
     for (const ComposerState& state : states) {
         const layer_state_t& s = state.state;
+
         sp<Layer> layer = nullptr;
         if (s.surface) {
             layer = fromHandle(s.surface).promote();
@@ -4002,6 +3873,15 @@
                  s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled);
 
         if (fenceUnsignaled && !allowLatchUnsignaled) {
+            if (!transaction.sentFenceTimeoutWarning &&
+                queueProcessTime - transaction.postTime > std::chrono::nanoseconds(4s).count()) {
+                transaction.sentFenceTimeoutWarning = true;
+                auto listener = s.bufferData->releaseBufferListener;
+                if (listener) {
+                    listener->onTransactionQueueStalled();
+                }
+            }
+
             ATRACE_NAME("fence unsignaled");
             return TransactionReadiness::NotReady;
         }
@@ -4021,18 +3901,15 @@
 }
 
 void SurfaceFlinger::queueTransaction(TransactionState& state) {
-    Mutex::Autolock lock(mQueueLock);
-
     // Generate a CountDownLatch pending state if this is a synchronous transaction.
-    if ((state.flags & eSynchronous) || state.inputWindowCommands.syncInputWindows) {
-        state.transactionCommittedSignal = std::make_shared<CountDownLatch>(
-                (state.inputWindowCommands.syncInputWindows
-                         ? (CountDownLatch::eSyncInputWindows | CountDownLatch::eSyncTransaction)
-                         : CountDownLatch::eSyncTransaction));
+    if (state.flags & eSynchronous) {
+        state.transactionCommittedSignal =
+                std::make_shared<CountDownLatch>(CountDownLatch::eSyncTransaction);
     }
 
-    mTransactionQueue.emplace_back(state);
-    ATRACE_INT("TransactionQueue", mTransactionQueue.size());
+    mLocklessTransactionQueue.push(state);
+    mPendingTransactionCount++;
+    ATRACE_INT("TransactionQueue", mPendingTransactionCount.load());
 
     const auto schedule = [](uint32_t flags) {
         if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
@@ -4201,10 +4078,6 @@
         if (transactionFlags) {
             setTransactionFlags(transactionFlags);
         }
-
-        if (flags & eAnimation) {
-            mAnimTransactionPending = true;
-        }
     }
 
     return needsTraversal;
@@ -4313,7 +4186,7 @@
     if (layer == nullptr) {
         for (auto& [listener, callbackIds] : s.listeners) {
             mTransactionCallbackInvoker.registerUnpresentedCallbackHandle(
-                    new CallbackHandle(listener, callbackIds, s.surface));
+                    sp<CallbackHandle>::make(listener, callbackIds, s.surface));
         }
         return 0;
     }
@@ -4410,6 +4283,11 @@
     if (what & layer_state_t::eBlurRegionsChanged) {
         if (layer->setBlurRegions(s.blurRegions)) flags |= eTraversalNeeded;
     }
+    if (what & layer_state_t::eRenderBorderChanged) {
+        if (layer->enableBorder(s.borderEnabled, s.borderWidth, s.borderColor)) {
+            flags |= eTraversalNeeded;
+        }
+    }
     if (what & layer_state_t::eLayerStackChanged) {
         ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
         // We only allow setting layer stacks for top level layers,
@@ -4481,6 +4359,14 @@
     if (what & layer_state_t::eShadowRadiusChanged) {
         if (layer->setShadowRadius(s.shadowRadius)) flags |= eTraversalNeeded;
     }
+    if (what & layer_state_t::eDefaultFrameRateCompatibilityChanged) {
+        const auto compatibility =
+                Layer::FrameRate::convertCompatibility(s.defaultFrameRateCompatibility);
+
+        if (layer->setDefaultFrameRateCompatibility(compatibility)) {
+            flags |= eTraversalNeeded;
+        }
+    }
     if (what & layer_state_t::eFrameRateSelectionPriority) {
         if (layer->setFrameRateSelectionPriority(s.frameRateSelectionPriority)) {
             flags |= eTraversalNeeded;
@@ -4531,7 +4417,7 @@
     if (what & layer_state_t::eDropInputModeChanged) {
         if (layer->setDropInputMode(s.dropInputMode)) {
             flags |= eTraversalNeeded;
-            mInputInfoChanged = true;
+            mUpdateInputInfo = true;
         }
     }
     // This has to happen after we reparent children because when we reparent to null we remove
@@ -4554,7 +4440,8 @@
     std::vector<sp<CallbackHandle>> callbackHandles;
     if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) {
         for (auto& [listener, callbackIds] : filteredListeners) {
-            callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
+            callbackHandles.emplace_back(
+                    sp<CallbackHandle>::make(listener, callbackIds, s.surface));
         }
     }
 
@@ -4595,7 +4482,9 @@
         if (!mirrorFrom) {
             return NAME_NOT_FOUND;
         }
-        status_t result = createContainerLayer(args, outHandle, &mirrorLayer);
+        LayerCreationArgs mirrorArgs = args;
+        mirrorArgs.flags |= ISurfaceComposerClient::eNoColorFill;
+        status_t result = createEffectLayer(mirrorArgs, outHandle, &mirrorLayer);
         if (result != NO_ERROR) {
             return result;
         }
@@ -4612,6 +4501,55 @@
                           false /* addToRoot */, nullptr /* outTransformHint */);
 }
 
+status_t SurfaceFlinger::mirrorDisplay(DisplayId displayId, const LayerCreationArgs& args,
+                                       sp<IBinder>* outHandle, int32_t* outLayerId) {
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int uid = ipc->getCallingUid();
+    if (uid != AID_ROOT && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != AID_SHELL) {
+        ALOGE("Permission denied when trying to mirror display");
+        return PERMISSION_DENIED;
+    }
+
+    ui::LayerStack layerStack;
+    sp<Layer> rootMirrorLayer;
+    status_t result = 0;
+
+    {
+        Mutex::Autolock lock(mStateLock);
+
+        const auto display = getDisplayDeviceLocked(displayId);
+        if (!display) {
+            return NAME_NOT_FOUND;
+        }
+
+        layerStack = display->getLayerStack();
+        LayerCreationArgs mirrorArgs = args;
+        mirrorArgs.flags |= ISurfaceComposerClient::eNoColorFill;
+        result = createEffectLayer(mirrorArgs, outHandle, &rootMirrorLayer);
+        *outLayerId = rootMirrorLayer->sequence;
+        result |= addClientLayer(args.client, *outHandle, rootMirrorLayer /* layer */,
+                                 nullptr /* parent */, true /* addToRoot */,
+                                 nullptr /* outTransformHint */);
+    }
+
+    if (result != NO_ERROR) {
+        return result;
+    }
+
+    if (mTransactionTracing) {
+        mTransactionTracing->onLayerAdded((*outHandle)->localBinder(), *outLayerId, args.name,
+                                          args.flags, -1 /* parentId */);
+    }
+
+    {
+        std::scoped_lock<std::mutex> lock(mMirrorDisplayLock);
+        mMirrorDisplays.emplace_back(layerStack, *outHandle, args.client);
+    }
+
+    setTransactionFlags(eTransactionFlushNeeded);
+    return NO_ERROR;
+}
+
 status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
                                      const sp<IBinder>& parentHandle, int32_t* outLayerId,
                                      const sp<Layer>& parentLayer, uint32_t* outTransformHint) {
@@ -4634,12 +4572,12 @@
                                         pendingBufferCounter);
             }
         } break;
+        case ISurfaceComposerClient::eFXSurfaceContainer:
+            args.flags |= ISurfaceComposerClient::eNoColorFill;
+            FMT_FALLTHROUGH;
         case ISurfaceComposerClient::eFXSurfaceEffect:
             result = createEffectLayer(args, outHandle, &layer);
             break;
-        case ISurfaceComposerClient::eFXSurfaceContainer:
-            result = createContainerLayer(args, outHandle, &layer);
-            break;
         default:
             result = BAD_VALUE;
             break;
@@ -4680,42 +4618,6 @@
     return result;
 }
 
-status_t SurfaceFlinger::createBufferQueueLayer(LayerCreationArgs& args, PixelFormat& format,
-                                                sp<IBinder>* handle,
-                                                sp<IGraphicBufferProducer>* gbp,
-                                                sp<Layer>* outLayer) {
-    // initialize the surfaces
-    switch (format) {
-    case PIXEL_FORMAT_TRANSPARENT:
-    case PIXEL_FORMAT_TRANSLUCENT:
-        format = PIXEL_FORMAT_RGBA_8888;
-        break;
-    case PIXEL_FORMAT_OPAQUE:
-        format = PIXEL_FORMAT_RGBX_8888;
-        break;
-    }
-
-    sp<BufferQueueLayer> layer;
-    args.textureName = getNewTexture();
-    {
-        // Grab the SF state lock during this since it's the only safe way to access
-        // RenderEngine when creating a BufferLayerConsumer
-        // TODO: Check if this lock is still needed here
-        Mutex::Autolock lock(mStateLock);
-        layer = getFactory().createBufferQueueLayer(args);
-    }
-
-    status_t err = layer->setDefaultBufferProperties(0, 0, format);
-    if (err == NO_ERROR) {
-        *handle = layer->getHandle();
-        *gbp = layer->getProducer();
-        *outLayer = layer;
-    }
-
-    ALOGE_IF(err, "createBufferQueueLayer() failed (%s)", strerror(-err));
-    return err;
-}
-
 status_t SurfaceFlinger::createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* handle,
                                                 sp<Layer>* outLayer) {
     args.textureName = getNewTexture();
@@ -4731,13 +4633,6 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::createContainerLayer(const LayerCreationArgs& args, sp<IBinder>* handle,
-                                              sp<Layer>* outLayer) {
-    *outLayer = getFactory().createContainerLayer(args);
-    *handle = (*outLayer)->getHandle();
-    return NO_ERROR;
-}
-
 void SurfaceFlinger::markLayerPendingRemovalLocked(const sp<Layer>& layer) {
     mLayersPendingRemoval.add(layer);
     mLayersRemoved = true;
@@ -4746,14 +4641,6 @@
 
 void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp<Layer>& layer) {
     Mutex::Autolock lock(mStateLock);
-    // If a layer has a parent, we allow it to out-live it's handle
-    // with the idea that the parent holds a reference and will eventually
-    // be cleaned up. However no one cleans up the top-level so we do so
-    // here.
-    if (layer->isAtRoot()) {
-        layer->setIsAtRoot(false);
-        mCurrentState.layersSortedByZ.remove(layer);
-    }
     markLayerPendingRemovalLocked(layer);
     mBufferCountTracker.remove(handle);
     layer.clear();
@@ -4795,13 +4682,8 @@
                           {}, mPid, getuid(), transactionId);
 
     setPowerModeInternal(display, hal::PowerMode::ON);
-    const nsecs_t vsyncPeriod = display->refreshRateConfigs().getActiveMode()->getVsyncPeriod();
-    mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
+
     mActiveDisplayTransformHint = display->getTransformHint();
-    // Use phase of 0 since phase is not known.
-    // Use latency of 0, which will snap to the ideal latency.
-    DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
-    setCompositorTimingSnapped(stats, 0);
 }
 
 void SurfaceFlinger::initializeDisplays() {
@@ -4857,7 +4739,6 @@
         }
 
         mVisibleRegionsDirty = true;
-        mHasPoweredOff = true;
         scheduleComposite(FrameHint::kActive);
     } else if (mode == hal::PowerMode::OFF) {
         // Turn off the display
@@ -4882,6 +4763,9 @@
         // Update display while dozing
         getHwComposer().setPowerMode(displayId, mode);
         if (isDisplayActiveLocked(display) && currentMode == hal::PowerMode::DOZE_SUSPEND) {
+            ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON.");
+            mVisibleRegionsDirty = true;
+            scheduleRepaint();
             mScheduler->onScreenAcquired(mAppConnectionHandle);
             mScheduler->resyncToHardwareVsync(true, refreshRate);
         }
@@ -4900,7 +4784,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());
@@ -4935,19 +4819,20 @@
                       pid, uid);
     } else {
         static const std::unordered_map<std::string, Dumper> dumpers = {
+                {"--comp-displays"s, dumper(&SurfaceFlinger::dumpCompositionDisplays)},
                 {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
+                {"--displays"s, dumper(&SurfaceFlinger::dumpDisplays)},
                 {"--dispsync"s, dumper([this](std::string& s) { mScheduler->dumpVsync(s); })},
                 {"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)},
-                {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
                 {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
                 {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
                 {"--list"s, dumper(&SurfaceFlinger::listLayersLocked)},
                 {"--planner"s, argsDumper(&SurfaceFlinger::dumpPlannerInfo)},
-                {"--static-screen"s, dumper(&SurfaceFlinger::dumpStaticScreenStats)},
                 {"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)},
                 {"--vsync"s, dumper(&SurfaceFlinger::dumpVSync)},
                 {"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)},
                 {"--frametimeline"s, argsDumper(&SurfaceFlinger::dumpFrameTimeline)},
+                {"--hwclayers"s, dumper(&SurfaceFlinger::dumpHwcLayersMinidumpLocked)},
         };
 
         const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
@@ -5008,17 +4893,14 @@
 
 void SurfaceFlinger::dumpStatsLocked(const DumpArgs& args, std::string& result) const {
     StringAppendF(&result, "%" PRId64 "\n", getVsyncPeriodFromHWC());
+    if (args.size() < 2) return;
 
-    if (args.size() > 1) {
-        const auto name = String8(args[1]);
-        mCurrentState.traverseInZOrder([&](Layer* layer) {
-            if (layer->getName() == name.string()) {
-                layer->dumpFrameStats(result);
-            }
-        });
-    } else {
-        mAnimFrameTracker.dumpStats(result);
-    }
+    const auto name = String8(args[1]);
+    mCurrentState.traverseInZOrder([&](Layer* layer) {
+        if (layer->getName() == name.string()) {
+            layer->dumpFrameStats(result);
+        }
+    });
 }
 
 void SurfaceFlinger::clearStatsLocked(const DumpArgs& args, std::string&) {
@@ -5030,8 +4912,6 @@
             layer->clearFrameStats();
         }
     });
-
-    mAnimFrameTracker.clearStats();
 }
 
 void SurfaceFlinger::dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const {
@@ -5042,12 +4922,13 @@
     mFrameTimeline->parseArgs(args, result);
 }
 
-void SurfaceFlinger::logFrameStats() {
-    mDrawingState.traverse([&](Layer* layer) {
-        layer->logFrameStats();
-    });
+void SurfaceFlinger::logFrameStats(TimePoint now) {
+    static TimePoint sTimestamp = now;
+    if (now - sTimestamp < 30min) return;
+    sTimestamp = now;
 
-    mAnimFrameTracker.logAndResetStats("<win-anim>");
+    ATRACE_CALL();
+    mDrawingState.traverse([&](Layer* layer) { layer->logFrameStats(); });
 }
 
 void SurfaceFlinger::appendSfConfigString(std::string& result) const {
@@ -5090,26 +4971,18 @@
     }
 }
 
-void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const {
-    result.append("Static screen stats:\n");
-    for (size_t b = 0; b < SurfaceFlingerBE::NUM_BUCKETS - 1; ++b) {
-        float bucketTimeSec = getBE().mFrameBuckets[b] / 1e9;
-        float percent = 100.0f *
-                static_cast<float>(getBE().mFrameBuckets[b]) / getBE().mTotalTime;
-        StringAppendF(&result, "  < %zd frames: %.3f s (%.1f%%)\n", b + 1, bucketTimeSec, percent);
+void SurfaceFlinger::dumpCompositionDisplays(std::string& result) const {
+    for (const auto& [token, display] : mDisplays) {
+        display->getCompositionDisplay()->dump(result);
+        result += '\n';
     }
-    float bucketTimeSec = getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] / 1e9;
-    float percent = 100.0f *
-            static_cast<float>(getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1]) / getBE().mTotalTime;
-    StringAppendF(&result, "  %zd+ frames: %.3f s (%.1f%%)\n", SurfaceFlingerBE::NUM_BUCKETS - 1,
-                  bucketTimeSec, percent);
 }
 
-void SurfaceFlinger::dumpFrameEventsLocked(std::string& result) {
-    result.append("Layer frame timestamps:\n");
-    // Traverse all layers to dump frame-events for each layer
-    mCurrentState.traverseInZOrder(
-        [&] (Layer* layer) { layer->dumpFrameEvents(result); });
+void SurfaceFlinger::dumpDisplays(std::string& result) const {
+    for (const auto& [token, display] : mDisplays) {
+        display->dump(result);
+        result += '\n';
+    }
 }
 
 void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const {
@@ -5256,6 +5129,23 @@
     result.append(future.get());
 }
 
+void SurfaceFlinger::dumpHwcLayersMinidumpLocked(std::string& result) const {
+    for (const auto& [token, display] : mDisplays) {
+        const auto displayId = HalDisplayId::tryCast(display->getId());
+        if (!displayId) {
+            continue;
+        }
+
+        StringAppendF(&result, "Display %s (%s) HWC layers:\n", to_string(*displayId).c_str(),
+                      (isDisplayActiveLocked(display) ? "active" : "inactive"));
+        Layer::miniDumpHeader(result);
+
+        const DisplayDevice& ref = *display;
+        mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, ref); });
+        result.append("\n");
+    }
+}
+
 void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
     const bool colorize = !args.empty() && args[0] == String16("--color");
     Colorizer colorizer(colorize);
@@ -5293,9 +5183,6 @@
     dumpVSync(result);
     result.append("\n");
 
-    dumpStaticScreenStats(result);
-    result.append("\n");
-
     StringAppendF(&result, "Total missed frame count: %u\n", mFrameMissedCount.load());
     StringAppendF(&result, "HWC missed frame count: %u\n", mHwcFrameMissedCount.load());
     StringAppendF(&result, "GPU missed frame count: %u\n\n", mGpuFrameMissedCount.load());
@@ -5320,21 +5207,12 @@
         });
     }
 
-    /*
-     * Dump Display state
-     */
-
     colorizer.bold(result);
     StringAppendF(&result, "Displays (%zu entries)\n", mDisplays.size());
     colorizer.reset(result);
-    for (const auto& [token, display] : mDisplays) {
-        display->dump(result);
-    }
-    result.append("\n");
-
-    /*
-     * Dump CompositionEngine state
-     */
+    dumpDisplays(result);
+    dumpCompositionDisplays(result);
+    result.push_back('\n');
 
     mCompositionEngine->dump(result);
 
@@ -5399,23 +5277,7 @@
     }
     result.push_back('\n');
 
-    /*
-     * HWC layer minidump
-     */
-    for (const auto& [token, display] : mDisplays) {
-        const auto displayId = HalDisplayId::tryCast(display->getId());
-        if (!displayId) {
-            continue;
-        }
-
-        StringAppendF(&result, "Display %s (%s) HWC layers:\n", to_string(*displayId).c_str(),
-                      (isDisplayActiveLocked(display) ? "active" : "inactive"));
-        Layer::miniDumpHeader(result);
-
-        const DisplayDevice& ref = *display;
-        mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, ref); });
-        result.append("\n");
-    }
+    dumpHwcLayersMinidumpLocked(result);
 
     {
         DumpArgs plannerArgs;
@@ -5480,7 +5342,6 @@
     switch (static_cast<ISurfaceComposerTag>(code)) {
         // These methods should at minimum make sure that the client requested
         // access to SF.
-        case BOOT_FINISHED:
         case GET_HDR_CAPABILITIES:
         case GET_AUTO_LOW_LATENCY_MODE_SUPPORT:
         case GET_GAME_CONTENT_TYPE_SUPPORT:
@@ -5496,8 +5357,6 @@
             }
             return OK;
         }
-        // Used by apps to hook Choreographer to SurfaceFlinger.
-        case CREATE_DISPLAY_EVENT_CONNECTION:
         // The following calls are currently used by clients that do not
         // request necessary permissions. However, they do not expose any secret
         // information, so it is OK to pass them.
@@ -5511,6 +5370,9 @@
             // This is not sensitive information, so should not require permission control.
             return OK;
         }
+        case BOOT_FINISHED:
+        // Used by apps to hook Choreographer to SurfaceFlinger.
+        case CREATE_DISPLAY_EVENT_CONNECTION:
         case CREATE_CONNECTION:
         case CREATE_DISPLAY:
         case DESTROY_DISPLAY:
@@ -5652,15 +5514,8 @@
                 reply->writeInt32(0);
                 reply->writeInt32(mDebugDisableHWC);
                 return NO_ERROR;
-            case 1013: {
-                const auto display = getDefaultDisplayDevice();
-                if (!display) {
-                    return NAME_NOT_FOUND;
-                }
-
-                reply->writeInt32(display->getPageFlipCount());
-                return NO_ERROR;
-            }
+            case 1013: // Unused.
+                return NAME_NOT_FOUND;
             case 1014: {
                 Mutex::Autolock _l(mStateLock);
                 // daltonize
@@ -5782,7 +5637,8 @@
                                 (fixedStartingTime) ? fixedStartingTime : systemTime();
                         mScheduler
                                 ->schedule([&]() FTL_FAKE_GUARD(mStateLock) {
-                                    mLayerTracing.notify("start", startingTime);
+                                    mLayerTracing.notify(true /* visibleRegionDirty */,
+                                                         startingTime, mLastCommittedVsyncId.value);
                                 })
                                 .wait();
                     }
@@ -6334,10 +6190,10 @@
         traverseLayersInLayerStack(layerStack, args.uid, visitor);
     };
 
-    auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers,
-                                                   reqSize, args.pixelFormat, args.allowProtected,
-                                                   args.grayscale, captureListener);
-    return captureResultFuture.get().status;
+    auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
+                                      args.pixelFormat, args.allowProtected, args.grayscale,
+                                      captureListener);
+    return fenceStatus(future.get());
 }
 
 status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
@@ -6376,11 +6232,14 @@
         ALOGE("capture screen must provide a capture listener callback");
         return BAD_VALUE;
     }
-    auto captureResultFuture =
-            captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
-                                ui::PixelFormat::RGBA_8888, false /* allowProtected */,
-                                false /* grayscale */, captureListener);
-    return captureResultFuture.get().status;
+
+    constexpr bool kAllowProtected = false;
+    constexpr bool kGrayscale = false;
+
+    auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
+                                      ui::PixelFormat::RGBA_8888, kAllowProtected, kGrayscale,
+                                      captureListener);
+    return fenceStatus(future.get());
 }
 
 status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
@@ -6475,7 +6334,7 @@
                 return;
             }
 
-            sp<Layer> p = layer;
+            auto p = sp<Layer>::fromExisting(layer);
             while (p != nullptr) {
                 if (excludeLayers.count(p) != 0) {
                     return;
@@ -6492,13 +6351,13 @@
         return BAD_VALUE;
     }
 
-    auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers,
-                                                   reqSize, args.pixelFormat, args.allowProtected,
-                                                   args.grayscale, captureListener);
-    return captureResultFuture.get().status;
+    auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
+                                      args.pixelFormat, args.allowProtected, args.grayscale,
+                                      captureListener);
+    return fenceStatus(future.get());
 }
 
-std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::captureScreenCommon(
+ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
         RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
         ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale,
         const sp<IScreenCaptureListener>& captureListener) {
@@ -6508,7 +6367,7 @@
         ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32
               ") that exceeds render target size limit.",
               bufferSize.getWidth(), bufferSize.getHeight());
-        return ftl::yield<renderengine::RenderEngineResult>({BAD_VALUE, base::unique_fd()}).share();
+        return ftl::yield<FenceResult>(base::unexpected(BAD_VALUE)).share();
     }
 
     // Loop over all visible layers to see whether there's any protected layer. A protected layer is
@@ -6540,8 +6399,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::
@@ -6550,7 +6414,7 @@
                                false /* regionSampling */, grayscale, captureListener);
 }
 
-std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::captureScreenCommon(
+ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
         RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
         const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
         bool grayscale, const sp<IScreenCaptureListener>& captureListener) {
@@ -6558,59 +6422,49 @@
 
     bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
 
-    auto scheduleResultFuture = mScheduler->schedule([=,
-                                                      renderAreaFuture =
-                                                              std::move(renderAreaFuture)]() mutable
-                                                     -> std::shared_future<
-                                                             renderengine::RenderEngineResult> {
+    auto future = mScheduler->schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable
+                                       -> ftl::SharedFuture<FenceResult> {
         ScreenCaptureResults captureResults;
         std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
         if (!renderArea) {
             ALOGW("Skipping screen capture because of invalid render area.");
             captureResults.result = NO_MEMORY;
             captureListener->onScreenCaptureCompleted(captureResults);
-            return ftl::yield<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})
+            return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share();
+        }
+
+        ftl::SharedFuture<FenceResult> renderFuture;
+        renderArea->render([&] {
+            renderFuture =
+                    renderScreenImpl(*renderArea, traverseLayers, buffer, canCaptureBlackoutContent,
+                                     regionSampling, grayscale, captureResults);
+        });
+
+        if (captureListener) {
+            // Defer blocking on renderFuture back to the Binder thread.
+            return ftl::Future(std::move(renderFuture))
+                    .then([captureListener, captureResults = std::move(captureResults)](
+                                  FenceResult fenceResult) mutable -> FenceResult {
+                        // TODO(b/232535621): Change ScreenCaptureResults to store a FenceResult.
+                        captureResults.result = fenceStatus(fenceResult);
+                        captureResults.fence = std::move(fenceResult).value_or(Fence::NO_FENCE);
+                        captureListener->onScreenCaptureCompleted(captureResults);
+                        return base::unexpected(NO_ERROR);
+                    })
                     .share();
         }
-
-        std::shared_future<renderengine::RenderEngineResult> renderEngineResultFuture;
-
-        renderArea->render([&] {
-            renderEngineResultFuture =
-                    renderScreenImpl(*renderArea, traverseLayers, buffer,
-                                           canCaptureBlackoutContent, regionSampling, grayscale,
-                                           captureResults);
-        });
-        // spring up a thread to unblock SF main thread and wait for
-        // RenderEngineResult to be available
-        if (captureListener != nullptr) {
-            std::async([=]() mutable {
-                ATRACE_NAME("captureListener is nonnull!");
-                auto& [status, drawFence] = renderEngineResultFuture.get();
-                captureResults.result = status;
-                captureResults.fence = new Fence(dup(drawFence));
-                captureListener->onScreenCaptureCompleted(captureResults);
-            });
-        }
-        return renderEngineResultFuture;
+        return renderFuture;
     });
 
-    // flatten scheduleResultFuture object to single shared_future object
-    if (captureListener == nullptr) {
-        std::future<renderengine::RenderEngineResult> captureScreenResultFuture =
-                ftl::chain(std::move(scheduleResultFuture))
-                        .then([=](std::shared_future<renderengine::RenderEngineResult> futureObject)
-                                      -> renderengine::RenderEngineResult {
-                            auto& [status, drawFence] = futureObject.get();
-                            return {status, base::unique_fd(dup(drawFence))};
-                        });
-        return captureScreenResultFuture.share();
-    } else {
-        return ftl::yield<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}).share();
-    }
+    // Flatten nested futures.
+    auto chain = ftl::Future(std::move(future)).then([](ftl::SharedFuture<FenceResult> future) {
+        return future;
+    });
+
+    return chain.share();
 }
 
-std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::renderScreenImpl(
+ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
         const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
         const std::shared_ptr<renderengine::ExternalTexture>& buffer,
         bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
@@ -6629,14 +6483,16 @@
     // the impetus on WindowManager to not persist them.
     if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) {
         ALOGW("FB is protected: PERMISSION_DENIED");
-        return ftl::yield<renderengine::RenderEngineResult>({PERMISSION_DENIED, base::unique_fd()})
-                .share();
+        return ftl::yield<FenceResult>(base::unexpected(PERMISSION_DENIED)).share();
     }
 
     captureResults.buffer = buffer->getBuffer();
     auto dataspace = renderArea.getReqDataSpace();
     auto parent = renderArea.getParentLayer();
     auto renderIntent = RenderIntent::TONE_MAP_COLORIMETRIC;
+    auto sdrWhitePointNits = DisplayDevice::sDefaultMaxLumiance;
+    auto displayBrightnessNits = DisplayDevice::sDefaultMaxLumiance;
+
     if ((dataspace == ui::Dataspace::UNKNOWN) && (parent != nullptr)) {
         Mutex::Autolock lock(mStateLock);
         auto display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
@@ -6650,6 +6506,8 @@
         const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode;
         dataspace = pickDataspaceFromColorMode(colorMode);
         renderIntent = display->getCompositionDisplay()->getState().renderIntent;
+        sdrWhitePointNits = display->getCompositionDisplay()->getState().sdrWhitePointNits;
+        displayBrightnessNits = display->getCompositionDisplay()->getState().displayBrightnessNits;
     }
     captureResults.capturedDataspace = dataspace;
 
@@ -6670,6 +6528,7 @@
     clientCompositionDisplay.orientation = rotation;
 
     clientCompositionDisplay.outputDataspace = dataspace;
+    clientCompositionDisplay.currentLuminanceNits = displayBrightnessNits;
     clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance;
     clientCompositionDisplay.renderIntent =
             static_cast<aidl::android::hardware::graphics::composer3::RenderIntent>(renderIntent);
@@ -6708,7 +6567,7 @@
                                        BlurSetting::Disabled
                              : compositionengine::LayerFE::ClientCompositionTargetSettings::
                                        BlurSetting::Enabled,
-                DisplayDevice::sDefaultMaxLumiance,
+                isHdrLayer(layer) ? displayBrightnessNits : sdrWhitePointNits,
 
         };
         std::vector<compositionengine::LayerFE::LayerSettings> results =
@@ -6723,6 +6582,7 @@
                 if (regionSampling) {
                     settings.backgroundBlurRadius = 0;
                 }
+                captureResults.capturedHdrLayers |= isHdrLayer(layer);
             }
 
             clientCompositionLayers.insert(clientCompositionLayers.end(),
@@ -6745,28 +6605,22 @@
     base::unique_fd bufferFence;
     getRenderEngine().useProtectedContext(useProtected);
 
-    const constexpr bool kUseFramebufferCache = false;
-    std::future<renderengine::RenderEngineResult> drawLayersResult =
-            getRenderEngine().drawLayers(clientCompositionDisplay, clientRenderEngineLayers, buffer,
-                                         kUseFramebufferCache, std::move(bufferFence));
+    constexpr bool kUseFramebufferCache = false;
+    auto chain =
+            ftl::Future(getRenderEngine().drawLayers(clientCompositionDisplay,
+                                                     clientRenderEngineLayers, buffer,
+                                                     kUseFramebufferCache, std::move(bufferFence)))
+                    .then(&toFenceResult);
 
-    std::shared_future<renderengine::RenderEngineResult> drawLayersResultFuture =
-            drawLayersResult.share(); // drawLayersResult will be moved to shared one
-
+    const auto future = chain.share();
     for (auto* layer : renderedLayers) {
-        // make a copy of shared_future object for each layer
-        layer->onLayerDisplayed(drawLayersResultFuture);
+        layer->onLayerDisplayed(future);
     }
 
     // Always switch back to unprotected context.
     getRenderEngine().useProtectedContext(false);
 
-    return drawLayersResultFuture;
-}
-
-void SurfaceFlinger::windowInfosReported() {
-    Mutex::Autolock _l(mStateLock);
-    signalSynchronousTransactions(CountDownLatch::eSyncInputWindows);
+    return future;
 }
 
 // ---------------------------------------------------------------------------
@@ -6817,9 +6671,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;
     }
@@ -7085,7 +6937,7 @@
     return calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
 }
 
-void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state) {
+void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state, VsyncId vsyncId) {
     sp<Layer> layer = state.layer.promote();
     if (!layer) {
         ALOGD("Layer was destroyed soon after creation %p", state.layer.unsafe_get());
@@ -7115,7 +6967,9 @@
     }
 
     layer->updateTransformHint(mActiveDisplayTransformHint);
-
+    if (mTransactionTracing) {
+        mTransactionTracing->onLayerAddedToDrawingState(layer->getSequence(), vsyncId.value);
+    }
     mInterceptor->saveSurfaceCreation(layer);
 }
 
@@ -7199,7 +7053,46 @@
     return buffer;
 }
 
-bool SurfaceFlinger::commitCreatedLayers() {
+bool SurfaceFlinger::commitMirrorDisplays(VsyncId vsyncId) {
+    std::vector<MirrorDisplayState> mirrorDisplays;
+    {
+        std::scoped_lock<std::mutex> lock(mMirrorDisplayLock);
+        mirrorDisplays = std::move(mMirrorDisplays);
+        mMirrorDisplays.clear();
+        if (mirrorDisplays.size() == 0) {
+            return false;
+        }
+    }
+
+    sp<IBinder> unused;
+    for (const auto& mirrorDisplay : mirrorDisplays) {
+        // Set mirror layer's default layer stack to -1 so it doesn't end up rendered on a display
+        // accidentally.
+        sp<Layer> rootMirrorLayer = Layer::fromHandle(mirrorDisplay.rootHandle).promote();
+        rootMirrorLayer->setLayerStack(ui::LayerStack::fromValue(-1));
+        for (const auto& layer : mDrawingState.layersSortedByZ) {
+            if (layer->getLayerStack() != mirrorDisplay.layerStack ||
+                layer->isInternalDisplayOverlay()) {
+                continue;
+            }
+
+            LayerCreationArgs mirrorArgs(this, mirrorDisplay.client, "MirrorLayerParent",
+                                         ISurfaceComposerClient::eNoColorFill,
+                                         gui::LayerMetadata());
+            sp<Layer> childMirror;
+            createEffectLayer(mirrorArgs, &unused, &childMirror);
+            childMirror->setClonedChild(layer->createClone());
+            if (mTransactionTracing) {
+                mTransactionTracing->onLayerAddedToDrawingState(childMirror->getSequence(),
+                                                                vsyncId.value);
+            }
+            childMirror->reparent(mirrorDisplay.rootHandle);
+        }
+    }
+    return true;
+}
+
+bool SurfaceFlinger::commitCreatedLayers(VsyncId vsyncId) {
     std::vector<LayerCreatedState> createdLayers;
     {
         std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
@@ -7212,7 +7105,7 @@
 
     Mutex::Autolock _l(mStateLock);
     for (const auto& createdLayer : createdLayers) {
-        handleLayerCreatedLocked(createdLayer);
+        handleLayerCreatedLocked(createdLayer, vsyncId);
     }
     createdLayers.clear();
     mLayersAdded = true;
@@ -7221,8 +7114,31 @@
 
 // gui::ISurfaceComposer
 
+binder::Status SurfaceComposerAIDL::bootFinished() {
+    status_t status = checkAccessPermission();
+    if (status != OK) {
+        return binderStatusFromStatusT(status);
+    }
+    mFlinger->bootFinished();
+    return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::createDisplayEventConnection(
+        VsyncSource vsyncSource, EventRegistration eventRegistration,
+        sp<IDisplayEventConnection>* outConnection) {
+    sp<IDisplayEventConnection> conn =
+            mFlinger->createDisplayEventConnection(vsyncSource, eventRegistration);
+    if (conn == nullptr) {
+        *outConnection = nullptr;
+        return binderStatusFromStatusT(BAD_VALUE);
+    } else {
+        *outConnection = conn;
+        return binder::Status::ok();
+    }
+}
+
 binder::Status SurfaceComposerAIDL::createConnection(sp<gui::ISurfaceComposerClient>* outClient) {
-    const sp<Client> client = new Client(mFlinger);
+    const sp<Client> client = sp<Client>::make(mFlinger);
     if (client->initCheck() == NO_ERROR) {
         *outClient = client;
         return binder::Status::ok();
@@ -7263,20 +7179,6 @@
     return binder::Status::ok();
 }
 
-binder::Status SurfaceComposerAIDL::getPrimaryPhysicalDisplayId(int64_t* outDisplayId) {
-    status_t status = checkAccessPermission();
-    if (status != OK) {
-        return binderStatusFromStatusT(status);
-    }
-
-    PhysicalDisplayId id;
-    status = mFlinger->getPrimaryPhysicalDisplayId(&id);
-    if (status == NO_ERROR) {
-        *outDisplayId = id.value;
-    }
-    return binderStatusFromStatusT(status);
-}
-
 binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId,
                                                             sp<IBinder>* outDisplay) {
     const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
@@ -7347,6 +7249,8 @@
         dinfo.manufacturerPnpId =
                 std::vector<uint8_t>(dpi->manufacturerPnpId.begin(), dpi->manufacturerPnpId.end());
         dinfo.productId = dpi->productId;
+        dinfo.relativeAddress =
+                std::vector<uint8_t>(dpi->relativeAddress.begin(), dpi->relativeAddress.end());
         if (const auto* model =
                     std::get_if<DeviceProductInfo::ModelYear>(&dpi->manufactureOrModelDate)) {
             gui::DeviceProductInfo::ModelYear modelYear;
@@ -7523,40 +7427,6 @@
     return binderStatusFromStatusT(status);
 }
 
-binder::Status SurfaceComposerAIDL::clearAnimationFrameStats() {
-    status_t status = checkAccessPermission();
-    if (status == OK) {
-        status = mFlinger->clearAnimationFrameStats();
-    }
-    return binderStatusFromStatusT(status);
-}
-
-binder::Status SurfaceComposerAIDL::getAnimationFrameStats(gui::FrameStats* outStats) {
-    status_t status = checkAccessPermission();
-    if (status != OK) {
-        return binderStatusFromStatusT(status);
-    }
-
-    FrameStats stats;
-    status = mFlinger->getAnimationFrameStats(&stats);
-    if (status == NO_ERROR) {
-        outStats->refreshPeriodNano = stats.refreshPeriodNano;
-        outStats->desiredPresentTimesNano.reserve(stats.desiredPresentTimesNano.size());
-        for (const auto& t : stats.desiredPresentTimesNano) {
-            outStats->desiredPresentTimesNano.push_back(t);
-        }
-        outStats->actualPresentTimesNano.reserve(stats.actualPresentTimesNano.size());
-        for (const auto& t : stats.actualPresentTimesNano) {
-            outStats->actualPresentTimesNano.push_back(t);
-        }
-        outStats->frameReadyTimesNano.reserve(stats.frameReadyTimesNano.size());
-        for (const auto& t : stats.frameReadyTimesNano) {
-            outStats->frameReadyTimesNano.push_back(t);
-        }
-    }
-    return binderStatusFromStatusT(status);
-}
-
 binder::Status SurfaceComposerAIDL::overrideHdrTypes(const sp<IBinder>& display,
                                                      const std::vector<int32_t>& hdrTypes) {
     // overrideHdrTypes is used by CTS tests, which acquire the necessary
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ccf67cf..4d4d263 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -28,8 +28,10 @@
 #include <android/gui/ISurfaceComposerClient.h>
 #include <cutils/atomic.h>
 #include <cutils/compiler.h>
+#include <ftl/future.h>
 #include <ftl/small_map.h>
 #include <gui/BufferQueue.h>
+#include <gui/CompositorTiming.h>
 #include <gui/FrameTimestamps.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ITransactionCompletedListener.h>
@@ -50,8 +52,11 @@
 #include <utils/Trace.h>
 #include <utils/threads.h>
 
+#include <compositionengine/FenceResult.h>
 #include <compositionengine/OutputColorSetting.h>
 #include <scheduler/Fps.h>
+#include <scheduler/PresentLatencyTracker.h>
+#include <scheduler/Time.h>
 
 #include "ClientCache.h"
 #include "DisplayDevice.h"
@@ -62,6 +67,7 @@
 #include "FlagManager.h"
 #include "FrameTracker.h"
 #include "LayerVector.h"
+#include "LocklessQueue.h"
 #include "Scheduler/RefreshRateConfigs.h"
 #include "Scheduler/RefreshRateStats.h"
 #include "Scheduler/Scheduler.h"
@@ -77,7 +83,6 @@
 #include <atomic>
 #include <cstdint>
 #include <functional>
-#include <future>
 #include <map>
 #include <memory>
 #include <mutex>
@@ -92,12 +97,12 @@
 #include <utility>
 
 #include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+#include "Client.h"
 
 using namespace android::surfaceflinger;
 
 namespace android {
 
-class Client;
 class EventThread;
 class FlagManager;
 class FpsReporter;
@@ -166,27 +171,6 @@
 
 using DisplayColorSetting = compositionengine::OutputColorSetting;
 
-struct SurfaceFlingerBE {
-    FenceTimeline mGlCompositionDoneTimeline;
-    FenceTimeline mDisplayTimeline;
-
-    // protected by mCompositorTimingLock;
-    mutable std::mutex mCompositorTimingLock;
-    CompositorTiming mCompositorTiming;
-
-    // Only accessed from the main thread.
-    struct CompositePresentTime {
-        nsecs_t composite = -1;
-        std::shared_ptr<FenceTime> display = FenceTime::NO_FENCE;
-    };
-    std::queue<CompositePresentTime> mCompositePresentTimes;
-
-    static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
-    nsecs_t mFrameBuckets[NUM_BUCKETS] = {};
-    nsecs_t mTotalTime = 0;
-    std::atomic<nsecs_t> mLastSwapTime = 0;
-};
-
 class SurfaceFlinger : public BnSurfaceComposer,
                        public PriorityDumper,
                        private IBinder::DeathRecipient,
@@ -207,29 +191,6 @@
 
     static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; }
 
-    // This is the phase offset in nanoseconds of the software vsync event
-    // relative to the vsync event reported by HWComposer.  The software vsync
-    // event is when SurfaceFlinger and Choreographer-based applications run each
-    // frame.
-    //
-    // This phase offset allows adjustment of the minimum latency from application
-    // wake-up time (by Choreographer) to the time at which the resulting window
-    // image is displayed.  This value may be either positive (after the HW vsync)
-    // or negative (before the HW vsync). Setting it to 0 will result in a lower
-    // latency bound of two vsync periods because the app and SurfaceFlinger
-    // will run just after the HW vsync.  Setting it to a positive number will
-    // result in the minimum latency being:
-    //
-    //     (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD))
-    //
-    // Note that reducing this latency makes it more likely for the applications
-    // to not have their window content image ready in time.  When this happens
-    // the latency will end up being an additional vsync period, and animations
-    // will hiccup.  Therefore, this latency should be tuned somewhat
-    // conservatively (or at least with awareness of the trade-off being made).
-    static int64_t vsyncPhaseOffsetNs;
-    static int64_t sfVsyncPhaseOffsetNs;
-
     // If fences from sync Framework are supported.
     static bool hasSyncFramework;
 
@@ -283,9 +244,6 @@
     // starts SurfaceFlinger main loop in the current thread
     void run() ANDROID_API;
 
-    SurfaceFlingerBE& getBE() { return mBE; }
-    const SurfaceFlingerBE& getBE() const { return mBE; }
-
     // Indicates frame activity, i.e. whether commit and/or composite is taking place.
     enum class FrameHint { kNone, kActive };
 
@@ -335,7 +293,6 @@
     // If set, disables reusing client composition buffers. This can be set by
     // debug.sf.disable_client_composition_cache
     bool mDisableClientCompositionCache = false;
-    void windowInfosReported();
 
     // Disables expensive rendering for all displays
     // This is scheduled on the main thread
@@ -347,6 +304,12 @@
     // run parallel to the hwc validateDisplay call and re-run if the predition is incorrect.
     bool mPredictCompositionStrategy = false;
 
+    // If true, then any layer with a SMPTE 170M transfer function is decoded using the sRGB
+    // transfer instead. This is mainly to preserve legacy behavior, where implementations treated
+    // SMPTE 170M as sRGB prior to color management being implemented, and now implementations rely
+    // on this behavior to increase contrast for some media sources.
+    bool mTreat170mAsSrgb = false;
+
 protected:
     // We're reference counted, never destroy SurfaceFlinger directly
     virtual ~SurfaceFlinger();
@@ -369,13 +332,11 @@
 
 private:
     friend class BufferLayer;
-    friend class BufferQueueLayer;
     friend class BufferStateLayer;
     friend class Client;
     friend class FpsReporter;
     friend class TunnelModeEnabledReporter;
     friend class Layer;
-    friend class MonitoredProducer;
     friend class RefreshRateOverlay;
     friend class RegionSamplingThread;
     friend class LayerRenderArea;
@@ -389,14 +350,10 @@
     using VsyncModulator = scheduler::VsyncModulator;
     using TransactionSchedule = scheduler::TransactionSchedule;
     using TraverseLayersFunction = std::function<void(const LayerVector::Visitor&)>;
-    using RenderAreaFuture = std::future<std::unique_ptr<RenderArea>>;
+    using RenderAreaFuture = ftl::Future<std::unique_ptr<RenderArea>>;
     using DumpArgs = Vector<String16>;
     using Dumper = std::function<void(const DumpArgs&, bool asProto, std::string&)>;
 
-    // This value is specified in number of frames.  Log frame stats at most
-    // every half hour.
-    enum { LOG_FRAME_STATS_PERIOD =  30*60*60 };
-
     class State {
     public:
         explicit State(LayerVector::StateSet set) : stateSet(set), layersSortedByZ(set) {}
@@ -513,29 +470,17 @@
         }
     }
 
-    static const int MAX_TRACING_MEMORY = 100 * 1024 * 1024; // 100MB
     // Maximum allowed number of display frames that can be set through backdoor
     static const int MAX_ALLOWED_DISPLAY_FRAMES = 2048;
 
+    static const size_t MAX_LAYERS = 4096;
+
     // Implements IBinder.
     status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
     status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); }
     bool callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache = true)
             EXCLUDES(mStateLock);
 
-    // the following two methods are moved from ISurfaceComposer.h
-    // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
-    std::optional<PhysicalDisplayId> getInternalDisplayId() const {
-        const auto displayIds = getPhysicalDisplayIds();
-        return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
-    }
-
-    // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
-    sp<IBinder> getInternalDisplayToken() const {
-        const auto displayId = getInternalDisplayId();
-        return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
-    }
-
     // Implements ISurfaceComposer
     sp<IBinder> createDisplay(const String8& displayName, bool secure);
     void destroyDisplay(const sp<IBinder>& displayToken);
@@ -543,7 +488,6 @@
         Mutex::Autolock lock(mStateLock);
         return getPhysicalDisplayIdsLocked();
     }
-    status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const EXCLUDES(mStateLock);
 
     sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const;
     status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
@@ -555,11 +499,12 @@
                                  const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
                                  const std::vector<ListenerCallbacks>& listenerCallbacks,
                                  uint64_t transactionId) override;
-    void bootFinished() override;
+    void bootFinished();
     virtual status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const;
     sp<IDisplayEventConnection> createDisplayEventConnection(
-            ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp,
-            ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) override;
+            gui::ISurfaceComposer::VsyncSource vsyncSource =
+                    gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp,
+            EventRegistrationFlags eventRegistration = {});
 
     status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&);
     status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&);
@@ -580,8 +525,6 @@
     void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on);
     void setGameContentType(const sp<IBinder>& displayToken, bool on);
     void setPowerMode(const sp<IBinder>& displayToken, int mode);
-    status_t clearAnimationFrameStats();
-    status_t getAnimationFrameStats(FrameStats* outStats) const;
     status_t overrideHdrTypes(const sp<IBinder>& displayToken,
                               const std::vector<ui::Hdr>& hdrTypes);
     status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success);
@@ -670,11 +613,11 @@
 
     // Commits transactions for layers and displays. Returns whether any state has been invalidated,
     // i.e. whether a frame should be composited for each display.
-    bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) override;
+    bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) override;
 
     // Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition
     // via RenderEngine and the Composer HAL, respectively.
-    void composite(nsecs_t frameTime, int64_t vsyncId) override;
+    void composite(TimePoint frameTime, VsyncId) override;
 
     // Samples the composited frame via RegionSamplingThread.
     void sample() override;
@@ -766,22 +709,15 @@
                                const std::vector<ListenerCallbacks>& listenerCallbacks,
                                int originPid, int originUid, uint64_t transactionId)
             REQUIRES(mStateLock);
-    // flush pending transaction that was presented after desiredPresentTime.
-    bool flushTransactionQueues(int64_t vsyncId);
+    // Flush pending transactions that were presented after desiredPresentTime.
+    bool flushTransactionQueues(VsyncId) REQUIRES(kMainThreadContext);
     // Returns true if there is at least one transaction that needs to be flushed
     bool transactionFlushNeeded();
 
     int flushPendingTransactionQueues(
             std::vector<TransactionState>& transactions,
             std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
-            std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions,
-            bool tryApplyUnsignaled) REQUIRES(mStateLock, mQueueLock);
-
-    int flushUnsignaledPendingTransactionQueues(
-            std::vector<TransactionState>& transactions,
-            std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
-            std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions)
-            REQUIRES(mStateLock, mQueueLock);
+            bool tryApplyUnsignaled) REQUIRES(mStateLock) REQUIRES(kMainThreadContext);
 
     uint32_t setClientStateLocked(const FrameTimelineInfo&, ComposerState&,
                                   int64_t desiredPresentTime, bool isAutoTimestamp,
@@ -806,22 +742,23 @@
         ReadyUnsignaled,
     };
     TransactionReadiness transactionIsReadyToBeApplied(
-            const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
-            uid_t originUid, const Vector<ComposerState>& states,
-            const std::unordered_map<
-                sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
-            size_t totalTXapplied, bool tryApplyUnsignaled) const REQUIRES(mStateLock);
+            TransactionState&, const FrameTimelineInfo&, bool isAutoTimestamp,
+            TimePoint desiredPresentTime, uid_t originUid, const Vector<ComposerState>&,
+            const std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>&
+                    bufferLayersReadyToPresent,
+            size_t totalTXapplied, bool tryApplyUnsignaled) const REQUIRES(mStateLock)
+            REQUIRES(kMainThreadContext);
+
     static LatchUnsignaledConfig getLatchUnsignaledConfig();
     bool shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t&, size_t numStates,
                                size_t totalTXapplied) const;
-    bool stopTransactionProcessing(const std::unordered_set<sp<IBinder>, SpHash<IBinder>>&
-                                           applyTokensWithUnsignaledTransactions) const;
-    bool applyTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId)
+    bool applyTransactions(std::vector<TransactionState>& transactions, VsyncId)
             REQUIRES(mStateLock);
     uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
     uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
             REQUIRES(mStateLock);
-    bool frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const;
+    bool frameIsEarly(TimePoint expectedPresentTime, VsyncId) const;
+
     /*
      * Layer management
      */
@@ -830,22 +767,18 @@
                          const sp<Layer>& parentLayer = nullptr,
                          uint32_t* outTransformHint = nullptr);
 
-    status_t createBufferQueueLayer(LayerCreationArgs& args, PixelFormat& format,
-                                    sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp,
-                                    sp<Layer>* outLayer);
-
     status_t createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
                                     sp<Layer>* outLayer);
 
     status_t createEffectLayer(const LayerCreationArgs& args, sp<IBinder>* outHandle,
                                sp<Layer>* outLayer);
 
-    status_t createContainerLayer(const LayerCreationArgs& args, sp<IBinder>* outHandle,
-                                  sp<Layer>* outLayer);
-
     status_t mirrorLayer(const LayerCreationArgs& args, const sp<IBinder>& mirrorFromHandle,
                          sp<IBinder>* outHandle, int32_t* outLayerId);
 
+    status_t mirrorDisplay(DisplayId displayId, const LayerCreationArgs& args,
+                           sp<IBinder>* outHandle, int32_t* outLayerId);
+
     // called when all clients have released all their references to
     // this layer meaning it is entirely safe to destroy all
     // resources associated to this layer.
@@ -863,14 +796,15 @@
     // Boot animation, on/off animations and screen capture
     void startBootAnim();
 
-    std::shared_future<renderengine::RenderEngineResult> captureScreenCommon(
-            RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, ui::PixelFormat,
-            bool allowProtected, bool grayscale, const sp<IScreenCaptureListener>&);
-    std::shared_future<renderengine::RenderEngineResult> captureScreenCommon(
+    ftl::SharedFuture<FenceResult> captureScreenCommon(RenderAreaFuture, TraverseLayersFunction,
+                                                       ui::Size bufferSize, ui::PixelFormat,
+                                                       bool allowProtected, bool grayscale,
+                                                       const sp<IScreenCaptureListener>&);
+    ftl::SharedFuture<FenceResult> captureScreenCommon(
             RenderAreaFuture, TraverseLayersFunction,
             const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
             bool grayscale, const sp<IScreenCaptureListener>&);
-    std::shared_future<renderengine::RenderEngineResult> renderScreenImpl(
+    ftl::SharedFuture<FenceResult> renderScreenImpl(
             const RenderArea&, TraverseLayersFunction,
             const std::shared_ptr<renderengine::ExternalTexture>&, bool canCaptureBlackoutContent,
             bool regionSampling, bool grayscale, ScreenCaptureResults&) EXCLUDES(mStateLock);
@@ -911,6 +845,13 @@
         return nullptr;
     }
 
+    sp<const DisplayDevice> getDisplayDeviceLocked(DisplayId id) const REQUIRES(mStateLock) {
+        // TODO(b/182939859): Replace tokens with IDs for display lookup.
+        return findDisplay([id](const auto& display) { return display.getId() == id; });
+    }
+
+    // Returns the primary display or (for foldables) the active display, assuming that the inner
+    // and outer displays have mutually exclusive power states.
     sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const REQUIRES(mStateLock) {
         return const_cast<SurfaceFlinger*>(this)->getDefaultDisplayDeviceLocked();
     }
@@ -919,12 +860,9 @@
         if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) {
             return display;
         }
-        // The active display is outdated, fall back to the internal display
+        // The active display is outdated, so fall back to the primary display.
         mActiveDisplayToken.clear();
-        if (const auto token = getInternalDisplayTokenLocked()) {
-            return getDisplayDeviceLocked(token);
-        }
-        return nullptr;
+        return getDisplayDeviceLocked(getPrimaryDisplayTokenLocked());
     }
 
     sp<const DisplayDevice> getDefaultDisplayDevice() const EXCLUDES(mStateLock) {
@@ -941,11 +879,6 @@
         return it == mDisplays.end() ? nullptr : it->second;
     }
 
-    sp<const DisplayDevice> getDisplayDeviceLocked(DisplayId id) const REQUIRES(mStateLock) {
-        // TODO(b/182939859): Replace tokens with IDs for display lookup.
-        return findDisplay([id](const auto& display) { return display.getId() == id; });
-    }
-
     std::vector<PhysicalDisplayId> getPhysicalDisplayIdsLocked() const REQUIRES(mStateLock);
 
     // mark a region of a layer stack dirty. this updates the dirty
@@ -970,14 +903,7 @@
     /*
      * Compositing
      */
-    void postComposition();
-    void getCompositorTiming(CompositorTiming* compositorTiming);
-    void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
-                                std::shared_ptr<FenceTime>& presentFenceTime);
-    void setCompositorTimingSnapped(const DisplayStatInfo& stats,
-                                    nsecs_t compositeToPresentLatency);
-
-    void postFrame() REQUIRES(kMainThreadContext);
+    void postComposition() REQUIRES(kMainThreadContext);
 
     /*
      * Display management
@@ -1010,31 +936,17 @@
         getHwComposer().setVsyncEnabled(id, enabled);
     }
 
-    struct FenceWithFenceTime {
-        sp<Fence> fence = Fence::NO_FENCE;
-        std::shared_ptr<FenceTime> fenceTime = FenceTime::NO_FENCE;
-    };
+    using FenceTimePtr = std::shared_ptr<FenceTime>;
 
-    // Gets the fence for the previous frame.
-    // Must be called on the main thread.
-    FenceWithFenceTime previousFrameFence();
+    const FenceTimePtr& getPreviousPresentFence(TimePoint frameTime, Period)
+            REQUIRES(kMainThreadContext);
 
-    // Whether the previous frame has not yet been presented to the display.
-    // If graceTimeMs is positive, this method waits for at most the provided
-    // grace period before reporting if the frame missed.
-    // Must be called on the main thread.
-    bool previousFramePending(int graceTimeMs = 0);
-
-    // Returns the previous time that the frame was presented. If the frame has
-    // not been presented yet, then returns Fence::SIGNAL_TIME_PENDING. If there
-    // is no pending frame, then returns Fence::SIGNAL_TIME_INVALID.
-    // Must be called on the main thread.
-    nsecs_t previousFramePresentTime();
+    // Blocks the thread waiting for up to graceTimeMs in case the fence is about to signal.
+    static bool isFencePending(const FenceTimePtr&, int graceTimeMs);
 
     // Calculates the expected present time for this frame. For negative offsets, performs a
     // correction using the predicted vsync for the next frame instead.
-
-    nsecs_t calculateExpectedPresentTime(DisplayStatInfo) const;
+    TimePoint calculateExpectedPresentTime(TimePoint frameTime) const;
 
     /*
      * Display identification
@@ -1055,18 +967,17 @@
         return {};
     }
 
-    // TODO(b/182939859): SF conflates the primary (a.k.a. default) display with the first display
-    // connected at boot, which is typically internal. (Theoretically, it must be internal because
-    // SF does not support disconnecting it, though in practice HWC may circumvent this limitation.)
+    // Returns the first display connected at boot.
     //
-    // SF inherits getInternalDisplayToken and getInternalDisplayId from ISurfaceComposer, so these
-    // locked counterparts are named consistently. Once SF supports headless mode and can designate
-    // any display as primary, the "internal" misnomer will be phased out.
-    sp<IBinder> getInternalDisplayTokenLocked() const REQUIRES(mStateLock) {
-        return getPhysicalDisplayTokenLocked(getInternalDisplayIdLocked());
+    // TODO(b/229851933): SF conflates the primary display with the first display connected at boot,
+    // which typically has DisplayConnectionType::Internal. (Theoretically, it must be an internal
+    // display because SF does not support disconnecting it, though in practice HWC may circumvent
+    // this limitation.)
+    sp<IBinder> getPrimaryDisplayTokenLocked() const REQUIRES(mStateLock) {
+        return getPhysicalDisplayTokenLocked(getPrimaryDisplayIdLocked());
     }
 
-    PhysicalDisplayId getInternalDisplayIdLocked() const REQUIRES(mStateLock) {
+    PhysicalDisplayId getPrimaryDisplayIdLocked() const REQUIRES(mStateLock) {
         return getHwComposer().getPrimaryDisplayId();
     }
 
@@ -1085,6 +996,7 @@
      * Debugging & dumpsys
      */
     void dumpAllLocked(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock);
+    void dumpHwcLayersMinidumpLocked(std::string& result) const REQUIRES(mStateLock);
 
     void appendSfConfigString(std::string& result) const;
     void listLayersLocked(std::string& result) const;
@@ -1092,15 +1004,16 @@
     void clearStatsLocked(const DumpArgs& args, std::string& result);
     void dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const;
     void dumpFrameTimeline(const DumpArgs& args, std::string& result) const;
-    void logFrameStats() REQUIRES(kMainThreadContext);
+    void logFrameStats(TimePoint now) REQUIRES(kMainThreadContext);
 
     void dumpVSync(std::string& result) const REQUIRES(mStateLock);
-    void dumpStaticScreenStats(std::string& result) const;
-    // Not const because each Layer needs to query Fences and cache timestamps.
-    void dumpFrameEventsLocked(std::string& result);
+
+    void dumpCompositionDisplays(std::string& result) const REQUIRES(mStateLock);
+    void dumpDisplays(std::string& result) const REQUIRES(mStateLock);
     void dumpDisplayIdentificationData(std::string& result) const REQUIRES(mStateLock);
     void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const;
     void dumpWideColorInfo(std::string& result) const REQUIRES(mStateLock);
+
     LayersProto dumpDrawingStateProto(uint32_t traceFlags) const;
     void dumpOffscreenLayersProto(LayersProto& layersProto,
                                   uint32_t traceFlags = LayerTracing::TRACE_ALL) const;
@@ -1130,7 +1043,7 @@
     status_t CheckTransactCodeCredentials(uint32_t code);
 
     // Add transaction to the Transaction Queue
-    void queueTransaction(TransactionState& state) EXCLUDES(mQueueLock);
+    void queueTransaction(TransactionState& state);
     void waitForSynchronousTransaction(const CountDownLatch& transactionCommittedSignal);
     void signalSynchronousTransactions(const uint32_t flag);
 
@@ -1166,7 +1079,6 @@
     State mCurrentState{LayerVector::StateSet::Current};
     std::atomic<int32_t> mTransactionFlags = 0;
     std::vector<std::shared_ptr<CountDownLatch>> mTransactionCommittedSignals;
-    bool mAnimTransactionPending = false;
     std::atomic<uint32_t> mUniqueTransactionId = 1;
     SortedVector<sp<Layer>> mLayersPendingRemoval;
 
@@ -1175,7 +1087,7 @@
     float mGlobalSaturationFactor = 1.0f;
     mat4 mClientColorMatrix;
 
-    size_t mMaxGraphicBufferProducerListSize = ISurfaceComposer::MAX_LAYERS;
+    size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS;
     // If there are more GraphicBufferProducers tracked by SurfaceFlinger than
     // this threshold, then begin logging.
     size_t mGraphicBufferProducerListSizeLogThreshold =
@@ -1209,19 +1121,17 @@
     // Set during transaction application stage to track if the input info or children
     // for a layer has changed.
     // TODO: Also move visibleRegions over to a boolean system.
-    bool mInputInfoChanged = false;
+    bool mUpdateInputInfo = false;
     bool mSomeChildrenChanged;
     bool mSomeDataspaceChanged = false;
     bool mForceTransactionDisplayChange = false;
 
-    bool mAnimCompositionPending = false;
-
     // Tracks layers that have pending frames which are candidates for being
     // latched.
     std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithQueuedFrames;
     // Tracks layers that need to update a display's dirty region.
     std::vector<sp<Layer>> mLayersPendingRefresh;
-    std::array<FenceWithFenceTime, 2> mPreviousPresentFences;
+
     // True if in the previous frame at least one layer was composed via the GPU.
     bool mHadClientComposition = false;
     // True if in the previous frame at least one layer was composed via HW Composer.
@@ -1272,6 +1182,8 @@
     const std::unique_ptr<FrameTracer> mFrameTracer;
     const std::unique_ptr<frametimeline::FrameTimeline> mFrameTimeline;
 
+    VsyncId mLastCommittedVsyncId;
+
     // If blurs should be enabled on this device.
     bool mSupportsBlur = false;
     // If blurs are considered expensive and should require high GPU frequency.
@@ -1282,9 +1194,6 @@
 
     TransactionCallbackInvoker mTransactionCallbackInvoker;
 
-    // Thread-safe.
-    FrameTracker mAnimFrameTracker;
-
     // We maintain a pool of pre-generated texture names to hand out to avoid
     // layer creation needing to run on the main thread (which it would
     // otherwise need to do to access RenderEngine).
@@ -1292,18 +1201,10 @@
     uint32_t mTexturePoolSize = 0;
     std::vector<uint32_t> mTexturePool;
 
-    mutable Mutex mQueueLock;
-    Condition mTransactionQueueCV;
     std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash>
-            mPendingTransactionQueues GUARDED_BY(mQueueLock);
-    std::deque<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock);
-    /*
-     * Feature prototyping
-     */
-
-    // Static screen stats
-    bool mHasPoweredOff = false;
-
+            mPendingTransactionQueues;
+    LocklessQueue<TransactionState> mLocklessTransactionQueue;
+    std::atomic<size_t> mPendingTransactionCount = 0;
     std::atomic<size_t> mNumLayers = 0;
 
     // to linkToDeath
@@ -1331,7 +1232,6 @@
     ui::Dataspace mColorSpaceAgnosticDataspace;
     float mDimmingRatio = -1.f;
 
-    SurfaceFlingerBE mBE;
     std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
     // mMaxRenderTargetSize is only set once in init() so it doesn't need to be protected by
     // any mutex.
@@ -1355,9 +1255,17 @@
     sp<VsyncModulator> mVsyncModulator;
 
     std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
+    scheduler::PresentLatencyTracker mPresentLatencyTracker GUARDED_BY(kMainThreadContext);
 
-    std::atomic<nsecs_t> mExpectedPresentTime = 0;
-    nsecs_t mScheduledPresentTime = 0;
+    struct FenceWithFenceTime {
+        sp<Fence> fence = Fence::NO_FENCE;
+        FenceTimePtr fenceTime = FenceTime::NO_FENCE;
+    };
+    std::array<FenceWithFenceTime, 2> mPreviousPresentFences;
+
+    TimePoint mScheduledPresentTime GUARDED_BY(kMainThreadContext);
+    TimePoint mExpectedPresentTime GUARDED_BY(kMainThreadContext);
+
     hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
     hal::Vsync mLastHWCVsyncState = hal::Vsync::DISABLE;
 
@@ -1411,8 +1319,21 @@
     // A temporay pool that store the created layers and will be added to current state in main
     // thread.
     std::vector<LayerCreatedState> mCreatedLayers GUARDED_BY(mCreatedLayersLock);
-    bool commitCreatedLayers();
-    void handleLayerCreatedLocked(const LayerCreatedState& state) REQUIRES(mStateLock);
+    bool commitCreatedLayers(VsyncId);
+    void handleLayerCreatedLocked(const LayerCreatedState&, VsyncId) REQUIRES(mStateLock);
+
+    mutable std::mutex mMirrorDisplayLock;
+    struct MirrorDisplayState {
+        MirrorDisplayState(ui::LayerStack layerStack, sp<IBinder>& rootHandle,
+                           const sp<Client>& client)
+              : layerStack(layerStack), rootHandle(rootHandle), client(client) {}
+
+        ui::LayerStack layerStack;
+        sp<IBinder> rootHandle;
+        const sp<Client> client;
+    };
+    std::vector<MirrorDisplayState> mMirrorDisplays GUARDED_BY(mMirrorDisplayLock);
+    bool commitMirrorDisplays(VsyncId);
 
     std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint;
 
@@ -1432,12 +1353,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);
 
@@ -1448,12 +1369,15 @@
 public:
     SurfaceComposerAIDL(sp<SurfaceFlinger> sf) : mFlinger(std::move(sf)) {}
 
+    binder::Status bootFinished() override;
+    binder::Status createDisplayEventConnection(
+            VsyncSource vsyncSource, EventRegistration eventRegistration,
+            sp<gui::IDisplayEventConnection>* outConnection) override;
     binder::Status createConnection(sp<gui::ISurfaceComposerClient>* outClient) override;
     binder::Status createDisplay(const std::string& displayName, bool secure,
                                  sp<IBinder>* outDisplay) override;
     binder::Status destroyDisplay(const sp<IBinder>& display) override;
     binder::Status getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) override;
-    binder::Status getPrimaryPhysicalDisplayId(int64_t* outDisplayId) override;
     binder::Status getPhysicalDisplayToken(int64_t displayId, sp<IBinder>* outDisplay) override;
     binder::Status setPowerMode(const sp<IBinder>& display, int mode) override;
     binder::Status getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) override;
@@ -1478,8 +1402,15 @@
     binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override;
     binder::Status captureLayers(const LayerCaptureArgs&,
                                  const sp<IScreenCaptureListener>&) override;
-    binder::Status clearAnimationFrameStats() override;
-    binder::Status getAnimationFrameStats(gui::FrameStats* outStats) override;
+
+    // TODO(b/239076119): Remove deprecated AIDL.
+    [[deprecated]] binder::Status clearAnimationFrameStats() override {
+        return binder::Status::ok();
+    }
+    [[deprecated]] binder::Status getAnimationFrameStats(gui::FrameStats*) override {
+        return binder::Status::ok();
+    }
+
     binder::Status overrideHdrTypes(const sp<IBinder>& display,
                                     const std::vector<int32_t>& hdrTypes) override;
     binder::Status onPullAtom(int32_t atomId, gui::PullAtomData* outPullData) override;
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index b81b445..5c96f35 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -22,15 +22,11 @@
 #include <cutils/properties.h>
 #include <ui/GraphicBuffer.h>
 
-#include "BufferLayerConsumer.h"
-#include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
-#include "ContainerLayer.h"
 #include "DisplayDevice.h"
 #include "EffectLayer.h"
 #include "FrameTracer/FrameTracer.h"
 #include "Layer.h"
-#include "MonitoredProducer.h"
 #include "NativeWindowSurface.h"
 #include "StartPropertySetThread.h"
 #include "SurfaceFlingerDefaultFactory.h"
@@ -60,22 +56,22 @@
 }
 
 sp<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor() {
-    return new android::impl::SurfaceInterceptor();
+    return sp<android::impl::SurfaceInterceptor>::make();
 }
 
 sp<StartPropertySetThread> DefaultFactory::createStartPropertySetThread(
         bool timestampPropertyValue) {
-    return new StartPropertySetThread(timestampPropertyValue);
+    return sp<StartPropertySetThread>::make(timestampPropertyValue);
 }
 
 sp<DisplayDevice> DefaultFactory::createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) {
-    return new DisplayDevice(creationArgs);
+    return sp<DisplayDevice>::make(creationArgs);
 }
 
 sp<GraphicBuffer> DefaultFactory::createGraphicBuffer(uint32_t width, uint32_t height,
                                                       PixelFormat format, uint32_t layerCount,
                                                       uint64_t usage, std::string requestorName) {
-    return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
+    return sp<GraphicBuffer>::make(width, height, format, layerCount, usage, requestorName);
 }
 
 void DefaultFactory::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
@@ -84,18 +80,6 @@
     BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
 }
 
-sp<IGraphicBufferProducer> DefaultFactory::createMonitoredProducer(
-        const sp<IGraphicBufferProducer>& producer, const sp<SurfaceFlinger>& flinger,
-        const wp<Layer>& layer) {
-    return new MonitoredProducer(producer, flinger, layer);
-}
-
-sp<BufferLayerConsumer> DefaultFactory::createBufferLayerConsumer(
-        const sp<IGraphicBufferConsumer>& consumer, renderengine::RenderEngine& renderEngine,
-        uint32_t textureName, Layer* layer) {
-    return new BufferLayerConsumer(consumer, renderEngine, textureName, layer);
-}
-
 std::unique_ptr<surfaceflinger::NativeWindowSurface> DefaultFactory::createNativeWindowSurface(
         const sp<IGraphicBufferProducer>& producer) {
     return surfaceflinger::impl::createNativeWindowSurface(producer);
@@ -105,20 +89,12 @@
     return compositionengine::impl::createCompositionEngine();
 }
 
-sp<ContainerLayer> DefaultFactory::createContainerLayer(const LayerCreationArgs& args) {
-    return new ContainerLayer(args);
-}
-
-sp<BufferQueueLayer> DefaultFactory::createBufferQueueLayer(const LayerCreationArgs& args) {
-    return new BufferQueueLayer(args);
-}
-
 sp<BufferStateLayer> DefaultFactory::createBufferStateLayer(const LayerCreationArgs& args) {
-    return new BufferStateLayer(args);
+    return sp<BufferStateLayer>::make(args);
 }
 
 sp<EffectLayer> DefaultFactory::createEffectLayer(const LayerCreationArgs& args) {
-    return new EffectLayer(args);
+    return sp<EffectLayer>::make(args);
 }
 
 std::unique_ptr<FrameTracer> DefaultFactory::createFrameTracer() {
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 501629d..8d00379 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -38,19 +38,11 @@
     void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
                            sp<IGraphicBufferConsumer>* outConsumer,
                            bool consumerIsSurfaceFlinger) override;
-    sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>&,
-                                                       const sp<SurfaceFlinger>&,
-                                                       const wp<Layer>&) override;
-    sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>&,
-                                                      renderengine::RenderEngine&, uint32_t tex,
-                                                      Layer*) override;
     std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
             const sp<IGraphicBufferProducer>&) override;
     std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override;
-    sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) override;
     sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override;
     sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) override;
-    sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override;
     std::unique_ptr<FrameTracer> createFrameTracer() override;
     std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
             std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) override;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index 3997b04..7bd6cf6 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -26,7 +26,7 @@
 sp<SurfaceFlinger> createSurfaceFlinger() {
     static DefaultFactory factory;
 
-    return new SurfaceFlinger(factory);
+    return sp<SurfaceFlinger>::make(factory);
 }
 
 } // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 6153e8e..291838f 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -30,10 +30,8 @@
 
 typedef int32_t PixelFormat;
 
-class BufferQueueLayer;
 class BufferLayerConsumer;
 class BufferStateLayer;
-class ContainerLayer;
 class DisplayDevice;
 class EffectLayer;
 class FrameTracer;
@@ -86,22 +84,14 @@
     virtual void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
                                    sp<IGraphicBufferConsumer>* outConsumer,
                                    bool consumerIsSurfaceFlinger) = 0;
-    virtual sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>&,
-                                                               const sp<SurfaceFlinger>&,
-                                                               const wp<Layer>&) = 0;
-    virtual sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>&,
-                                                              renderengine::RenderEngine&,
-                                                              uint32_t tex, Layer*) = 0;
 
     virtual std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
             const sp<IGraphicBufferProducer>&) = 0;
 
     virtual std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() = 0;
 
-    virtual sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) = 0;
     virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0;
     virtual sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) = 0;
-    virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
     virtual std::unique_ptr<FrameTracer> createFrameTracer() = 0;
     virtual std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
             std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) = 0;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 0782fef..66691c2 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -46,7 +46,7 @@
 
     std::scoped_lock lock(mListenersMutex);
 
-    asBinder->linkToDeath(this);
+    asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
 
     listener->onToggled(mEnabled); // notifies of current state
 
@@ -115,8 +115,9 @@
     ATRACE_CALL();
     for (const auto& l : layers) {
         l->traverseInZOrder(LayerVector::StateSet::Drawing, [this](Layer* layer) {
-            addSurfaceCreationLocked(createTraceIncrementLocked(), layer);
-            addInitialSurfaceStateLocked(createTraceIncrementLocked(), layer);
+            addSurfaceCreationLocked(createTraceIncrementLocked(), sp<Layer>::fromExisting(layer));
+            addInitialSurfaceStateLocked(createTraceIncrementLocked(),
+                                         sp<Layer>::fromExisting(layer));
         });
     }
 }
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index 49554c7..566d553 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -89,6 +89,9 @@
     LayersTraceFileProto fileProto;
     fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
                                LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
+    auto timeOffsetNs = static_cast<std::uint64_t>(systemTime(SYSTEM_TIME_REALTIME) -
+                                                   systemTime(SYSTEM_TIME_MONOTONIC));
+    fileProto.set_real_to_elapsed_time_offset_nanos(timeOffsetNs);
     return fileProto;
 }
 
@@ -98,7 +101,7 @@
     mBuffer->dump(result);
 }
 
-void LayerTracing::notify(bool visibleRegionDirty, int64_t time) {
+void LayerTracing::notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId) {
     std::scoped_lock lock(mTraceLock);
     if (!mEnabled) {
         return;
@@ -129,6 +132,7 @@
         entry.set_excludes_composition_state(true);
     }
     mFlinger.dumpDisplayProto(entry);
+    entry.set_vsync_id(vsyncId);
     mBuffer->emplace(std::move(entry));
 }
 
diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h
index 88a19ec..e73dac6 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.h
+++ b/services/surfaceflinger/Tracing/LayerTracing.h
@@ -47,7 +47,7 @@
     bool isEnabled() const;
     status_t writeToFile();
     LayersTraceFileProto createTraceFileProto() const;
-    void notify(bool visibleRegionDirty, int64_t time);
+    void notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId);
 
     enum : uint32_t {
         TRACE_INPUT = 1 << 1,
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 8ec6c99..77dec6f 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -457,9 +457,9 @@
             layer.parentSurfaceControlForChild = nullptr;
         } else {
             layer.parentSurfaceControlForChild =
-                    new SurfaceControl(SurfaceComposerClient::getDefault(),
-                                       mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
-                                       static_cast<int32_t>(layerId));
+                    sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(),
+                                             mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
+                                             static_cast<int32_t>(layerId));
         }
     }
     if (proto.what() & layer_state_t::eRelativeLayerChanged) {
@@ -468,9 +468,9 @@
             layer.relativeLayerSurfaceControl = nullptr;
         } else {
             layer.relativeLayerSurfaceControl =
-                    new SurfaceControl(SurfaceComposerClient::getDefault(),
-                                       mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
-                                       static_cast<int32_t>(layerId));
+                    sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(),
+                                             mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
+                                             static_cast<int32_t>(layerId));
         }
         layer.z = proto.z();
     }
@@ -498,8 +498,13 @@
         inputInfo.replaceTouchableRegionWithCrop =
                 windowInfoProto.replace_touchable_region_with_crop();
         int64_t layerId = windowInfoProto.crop_layer_id();
-        inputInfo.touchableRegionCropHandle =
-                mMapper->getLayerHandle(static_cast<int32_t>(layerId));
+        if (layerId != -1) {
+            inputInfo.touchableRegionCropHandle =
+                    mMapper->getLayerHandle(static_cast<int32_t>(layerId));
+        } else {
+            inputInfo.touchableRegionCropHandle = wp<IBinder>();
+        }
+
         layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
     }
     if (proto.what() & layer_state_t::eBackgroundColorChanged) {
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index 6381758..cb5320b 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -134,6 +134,9 @@
     proto::TransactionTraceFile proto;
     proto.set_magic_number(uint64_t(proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_H) << 32 |
                            proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_L);
+    auto timeOffsetNs = static_cast<std::uint64_t>(systemTime(SYSTEM_TIME_REALTIME) -
+                                                   systemTime(SYSTEM_TIME_MONOTONIC));
+    proto.set_real_to_elapsed_time_offset_nanos(timeOffsetNs);
     return proto;
 }
 
@@ -152,17 +155,33 @@
     mTransactionQueue.push(state);
 }
 
-void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
-                                                  int64_t vsyncId) {
+TransactionTracing::CommittedTransactions&
+TransactionTracing::findOrCreateCommittedTransactionRecord(int64_t vsyncId) {
+    for (auto& pendingTransaction : mPendingTransactions) {
+        if (pendingTransaction.vsyncId == vsyncId) {
+            return pendingTransaction;
+        }
+    }
+
     CommittedTransactions committedTransactions;
     committedTransactions.vsyncId = vsyncId;
     committedTransactions.timestamp = systemTime();
+    mPendingTransactions.emplace_back(committedTransactions);
+    return mPendingTransactions.back();
+}
+
+void TransactionTracing::onLayerAddedToDrawingState(int layerId, int64_t vsyncId) {
+    CommittedTransactions& committedTransactions = findOrCreateCommittedTransactionRecord(vsyncId);
+    committedTransactions.createdLayerIds.emplace_back(layerId);
+}
+
+void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
+                                                  int64_t vsyncId) {
+    CommittedTransactions& committedTransactions = findOrCreateCommittedTransactionRecord(vsyncId);
     committedTransactions.transactionIds.reserve(transactions.size());
     for (const auto& transaction : transactions) {
         committedTransactions.transactionIds.emplace_back(transaction.id);
     }
-
-    mPendingTransactions.emplace_back(committedTransactions);
     tryPushToTracingThread();
 }
 
@@ -235,15 +254,24 @@
     for (const CommittedTransactions& entry : committedTransactions) {
         entryProto.set_elapsed_realtime_nanos(entry.timestamp);
         entryProto.set_vsync_id(entry.vsyncId);
-        entryProto.mutable_added_layers()->Reserve(static_cast<int32_t>(mCreatedLayers.size()));
-        for (auto& newLayer : mCreatedLayers) {
-            entryProto.mutable_added_layers()->Add(std::move(newLayer));
+        entryProto.mutable_added_layers()->Reserve(
+                static_cast<int32_t>(entry.createdLayerIds.size()));
+
+        for (const int32_t& id : entry.createdLayerIds) {
+            auto it = mCreatedLayers.find(id);
+            if (it != mCreatedLayers.end()) {
+                entryProto.mutable_added_layers()->Add(std::move(it->second));
+                mCreatedLayers.erase(it);
+            } else {
+                ALOGW("Could not created layer with id %d", id);
+            }
         }
+
         entryProto.mutable_removed_layers()->Reserve(static_cast<int32_t>(removedLayers.size()));
         for (auto& removedLayer : removedLayers) {
             entryProto.mutable_removed_layers()->Add(removedLayer);
+            mCreatedLayers.erase(removedLayer);
         }
-        mCreatedLayers.clear();
         entryProto.mutable_transactions()->Reserve(
                 static_cast<int32_t>(entry.transactionIds.size()));
         for (const uint64_t& id : entry.transactionIds) {
@@ -256,6 +284,14 @@
             }
         }
 
+        entryProto.mutable_removed_layer_handles()->Reserve(
+                static_cast<int32_t>(mRemovedLayerHandles.size()));
+        for (auto& [handle, layerId] : mRemovedLayerHandles) {
+            entryProto.mutable_removed_layer_handles()->Add(layerId);
+            mLayerHandles.erase(handle);
+        }
+        mRemovedLayerHandles.clear();
+
         std::string serializedProto;
         entryProto.SerializeToString(&serializedProto);
         entryProto.Clear();
@@ -263,13 +299,6 @@
         removedEntries.reserve(removedEntries.size() + entries.size());
         removedEntries.insert(removedEntries.end(), std::make_move_iterator(entries.begin()),
                               std::make_move_iterator(entries.end()));
-
-        entryProto.mutable_removed_layer_handles()->Reserve(
-                static_cast<int32_t>(mRemovedLayerHandles.size()));
-        for (auto& handle : mRemovedLayerHandles) {
-            entryProto.mutable_removed_layer_handles()->Add(handle);
-        }
-        mRemovedLayerHandles.clear();
     }
 
     proto::TransactionTraceEntry removedEntryProto;
@@ -304,7 +333,7 @@
         ALOGW("Duplicate handles found. %p", layerHandle);
     }
     mLayerHandles[layerHandle] = layerId;
-    mCreatedLayers.push_back(mProtoParser.toProto(args));
+    mCreatedLayers[layerId] = mProtoParser.toProto(args);
 }
 
 void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId,
@@ -315,7 +344,7 @@
         ALOGW("Duplicate handles found. %p", layerHandle);
     }
     mLayerHandles[layerHandle] = layerId;
-    mCreatedLayers.emplace_back(mProtoParser.toProto(args));
+    mCreatedLayers[layerId] = mProtoParser.toProto(args);
 }
 
 void TransactionTracing::onLayerRemoved(int32_t layerId) {
@@ -330,9 +359,7 @@
         ALOGW("handle not found. %p", layerHandle);
         return;
     }
-
-    mRemovedLayerHandles.push_back(it->second);
-    mLayerHandles.erase(it);
+    mRemovedLayerHandles.emplace_back(layerHandle, it->second);
 }
 
 void TransactionTracing::tryPushToTracingThread() {
@@ -376,10 +403,15 @@
         }
     }
 
+    for (const int32_t removedLayerHandleId : removedEntry.removed_layer_handles()) {
+        mRemovedLayerHandlesAtStart.insert(removedLayerHandleId);
+    }
+
     // Clean up stale starting states since the layer has been removed and the buffer does not
     // contain any references to the layer.
     for (const int32_t removedLayerId : removedEntry.removed_layers()) {
         mStartingStates.erase(removedLayerId);
+        mRemovedLayerHandlesAtStart.erase(removedLayerId);
     }
 }
 
@@ -401,6 +433,12 @@
     transactionProto.set_vsync_id(0);
     transactionProto.set_post_time(mStartingTimestamp);
     entryProto->mutable_transactions()->Add(std::move(transactionProto));
+
+    entryProto->mutable_removed_layer_handles()->Reserve(
+            static_cast<int32_t>(mRemovedLayerHandlesAtStart.size()));
+    for (const int32_t removedLayerHandleId : mRemovedLayerHandlesAtStart) {
+        entryProto->mutable_removed_layer_handles()->Add(removedLayerHandleId);
+    }
 }
 
 proto::TransactionTraceFile TransactionTracing::writeToProto() {
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
index 4c291f9..ae01d3c 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.h
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -64,6 +64,7 @@
                             int mirrorFromId);
     void onLayerRemoved(int layerId);
     void onHandleRemoved(BBinder* layerHandle);
+    void onLayerAddedToDrawingState(int layerId, int64_t vsyncId);
     void dump(std::string&) const;
     static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024;
     static constexpr auto ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024;
@@ -81,11 +82,13 @@
             GUARDED_BY(mTraceLock);
     LocklessStack<proto::TransactionState> mTransactionQueue;
     nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock);
-    std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock);
+    std::unordered_map<int, proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock);
     std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles
             GUARDED_BY(mTraceLock);
-    std::vector<int32_t /* layerId */> mRemovedLayerHandles GUARDED_BY(mTraceLock);
+    std::vector<std::pair<BBinder* /* layerHandle */, int32_t /* layerId */>> mRemovedLayerHandles
+            GUARDED_BY(mTraceLock);
     std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock);
+    std::set<int32_t /* layerId */> mRemovedLayerHandlesAtStart GUARDED_BY(mTraceLock);
     TransactionProtoParser mProtoParser GUARDED_BY(mTraceLock);
     // Parses the transaction to proto without holding any tracing locks so we can generate proto
     // in the binder thread without any contention.
@@ -100,6 +103,7 @@
     std::condition_variable mTransactionsAddedToBufferCv;
     struct CommittedTransactions {
         std::vector<uint64_t> transactionIds;
+        std::vector<int32_t> createdLayerIds;
         int64_t vsyncId;
         int64_t timestamp;
     };
@@ -117,7 +121,7 @@
     void tryPushToTracingThread() EXCLUDES(mMainThreadLock);
     void addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) REQUIRES(mTraceLock);
     void updateStartingStateLocked(const proto::TransactionTraceEntry& entry) REQUIRES(mTraceLock);
-
+    CommittedTransactions& findOrCreateCommittedTransactionRecord(int64_t vsyncId);
     // TEST
     // Wait until all the committed transactions for the specified vsync id are added to the buffer.
     void flush(int64_t vsyncId) EXCLUDES(mMainThreadLock);
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index eebb7cd..312d4ab 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -16,6 +16,7 @@
 
 #undef LOG_TAG
 #define LOG_TAG "LayerTraceGenerator"
+//#define LOG_NDEBUG 0
 
 #include <TestableSurfaceFlinger.h>
 #include <Tracing/TransactionProtoParser.h>
@@ -47,42 +48,29 @@
     }
 
     sp<SurfaceInterceptor> createSurfaceInterceptor() override {
-        return new android::impl::SurfaceInterceptor();
+        return sp<android::impl::SurfaceInterceptor>::make();
     }
 
     sp<StartPropertySetThread> createStartPropertySetThread(
             bool /* timestampPropertyValue */) override {
-        return nullptr;
+        return sp<StartPropertySetThread>();
     }
 
     sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& /* creationArgs */) override {
-        return nullptr;
+        return sp<DisplayDevice>();
     }
 
     sp<GraphicBuffer> createGraphicBuffer(uint32_t /* width */, uint32_t /* height */,
                                           PixelFormat /* format */, uint32_t /* layerCount */,
                                           uint64_t /* usage */,
                                           std::string /* requestorName */) override {
-        return nullptr;
+        return sp<GraphicBuffer>();
     }
 
     void createBufferQueue(sp<IGraphicBufferProducer>* /* outProducer */,
                            sp<IGraphicBufferConsumer>* /* outConsumer */,
                            bool /* consumerIsSurfaceFlinger */) override {}
 
-    sp<IGraphicBufferProducer> createMonitoredProducer(
-            const sp<IGraphicBufferProducer>& /* producer */,
-            const sp<SurfaceFlinger>& /* flinger */, const wp<Layer>& /* layer */) override {
-        return nullptr;
-    }
-
-    sp<BufferLayerConsumer> createBufferLayerConsumer(
-            const sp<IGraphicBufferConsumer>& /* consumer */,
-            renderengine::RenderEngine& /* renderEngine */, uint32_t /* textureName */,
-            Layer* /* layer */) override {
-        return nullptr;
-    }
-
     std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
             const sp<IGraphicBufferProducer>& /* producer */) override {
         return nullptr;
@@ -92,20 +80,12 @@
         return compositionengine::impl::createCompositionEngine();
     }
 
-    sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) {
-        return sp<ContainerLayer>::make(args);
-    }
-
     sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) {
-        return new BufferStateLayer(args);
+        return sp<BufferStateLayer>::make(args);
     }
 
     sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) {
-        return new EffectLayer(args);
-    }
-
-    sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
-        return nullptr;
+        return sp<EffectLayer>::make(args);
     }
 
     std::unique_ptr<FrameTracer> createFrameTracer() override {
@@ -142,6 +122,14 @@
         transact(1033, data, &reply, 0 /* flags */);
     }
 
+    void setLayerTraceSize(int32_t sizeInKb) {
+        Parcel data;
+        Parcel reply;
+        data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
+        data.writeInt32(sizeInKb);
+        transact(1029, data, &reply, 0 /* flags */);
+    }
+
     void startLayerTracing(int64_t traceStartTime) {
         Parcel data;
         Parcel reply;
@@ -186,7 +174,7 @@
     }
 
     Factory mFactory;
-    sp<MockSurfaceFlinger> flinger = new MockSurfaceFlinger(mFactory);
+    sp<MockSurfaceFlinger> flinger = sp<MockSurfaceFlinger>::make(mFactory);
     TestableSurfaceFlinger mFlinger(flinger);
     mFlinger.setupRenderEngine(
             std::make_unique<testing::NiceMock<renderengine::mock::RenderEngine>>());
@@ -206,21 +194,21 @@
     mFlinger.mutableMaxRenderTargetSize() = 16384;
 
     flinger->setLayerTracingFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS);
+    flinger->setLayerTraceSize(512 * 1024); // 512MB buffer size
     flinger->startLayerTracing(traceFile.entry(0).elapsed_realtime_nanos());
     std::unique_ptr<TraceGenFlingerDataMapper> mapper =
             std::make_unique<TraceGenFlingerDataMapper>();
     TraceGenFlingerDataMapper* dataMapper = mapper.get();
     TransactionProtoParser parser(std::move(mapper));
 
-    nsecs_t frameTime;
-    int64_t vsyncId;
     ALOGD("Generating %d transactions...", traceFile.entry_size());
     for (int i = 0; i < traceFile.entry_size(); i++) {
         proto::TransactionTraceEntry entry = traceFile.entry(i);
         ALOGV("    Entry %04d/%04d for time=%" PRId64 " vsyncid=%" PRId64
-              " layers +%d -%d transactions=%d",
+              " layers +%d -%d handles -%d transactions=%d",
               i, traceFile.entry_size(), entry.elapsed_realtime_nanos(), entry.vsync_id(),
-              entry.added_layers_size(), entry.removed_layers_size(), entry.transactions_size());
+              entry.added_layers_size(), entry.removed_layers_size(),
+              entry.removed_layer_handles_size(), entry.transactions_size());
 
         for (int j = 0; j < entry.added_layers_size(); j++) {
             // create layers
@@ -239,7 +227,7 @@
                     (dataMapper->mLayerHandles.find(tracingArgs.parentId) ==
                      dataMapper->mLayerHandles.end())) {
                     args.addToRoot = false;
-                } else {
+                } else if (tracingArgs.parentId != -1) {
                     parentHandle = dataMapper->getLayerHandle(tracingArgs.parentId);
                 }
                 mFlinger.createLayer(args, &outHandle, parentHandle, &outLayerId,
@@ -266,13 +254,13 @@
                                          transaction.listenerCallbacks, transaction.id);
         }
 
+        const auto frameTime = TimePoint::fromNs(entry.elapsed_realtime_nanos());
+        const auto vsyncId = VsyncId{entry.vsync_id()};
+        mFlinger.commit(frameTime, vsyncId);
+
         for (int j = 0; j < entry.removed_layer_handles_size(); j++) {
             dataMapper->mLayerHandles.erase(entry.removed_layer_handles(j));
         }
-
-        frameTime = entry.elapsed_realtime_nanos();
-        vsyncId = entry.vsync_id();
-        mFlinger.commit(frameTime, vsyncId);
     }
 
     flinger->stopLayerTracing(outputLayersTracePath);
@@ -281,4 +269,4 @@
     return true;
 }
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index e1f348f..e5de759 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -133,10 +133,10 @@
     if (surfaceControl) {
         sp<Fence> prevFence = nullptr;
 
-        for (const auto& futureStruct : handle->previousReleaseFences) {
-            sp<Fence> currentFence = sp<Fence>::make(dup(futureStruct.get().drawFence));
+        for (const auto& future : handle->previousReleaseFences) {
+            sp<Fence> currentFence = future.get().value_or(Fence::NO_FENCE);
             if (prevFence == nullptr && currentFence->getStatus() != Fence::Status::Invalid) {
-                prevFence = currentFence;
+                prevFence = std::move(currentFence);
                 handle->previousReleaseFence = prevFence;
             } else if (prevFence != nullptr) {
                 // If both fences are signaled or both are unsignaled, we need to merge
@@ -147,7 +147,7 @@
                     snprintf(fenceName, 32, "%.28s", handle->name.c_str());
                     sp<Fence> mergedFence = Fence::merge(fenceName, prevFence, currentFence);
                     if (mergedFence->isValid()) {
-                        handle->previousReleaseFence = mergedFence;
+                        handle->previousReleaseFence = std::move(mergedFence);
                         prevFence = handle->previousReleaseFence;
                     }
                 } else if (currentFence->getStatus() == Fence::Status::Unsignaled) {
@@ -158,11 +158,12 @@
                     // by this point, they will have both signaled and only the timestamp
                     // will be slightly off; any dependencies after this point will
                     // already have been met.
-                    handle->previousReleaseFence = currentFence;
+                    handle->previousReleaseFence = std::move(currentFence);
                 }
             }
         }
-        handle->previousReleaseFences = {};
+        handle->previousReleaseFences.clear();
+
         FrameEventHistoryStats eventStats(handle->frameNumber,
                                           handle->gpuCompositionDoneFence->getSnapshot().fence,
                                           handle->compositorTiming, handle->refreshStartTime,
@@ -177,13 +178,14 @@
     return NO_ERROR;
 }
 
-void TransactionCallbackInvoker::addPresentFence(const sp<Fence>& presentFence) {
-    mPresentFence = presentFence;
+void TransactionCallbackInvoker::addPresentFence(sp<Fence> presentFence) {
+    mPresentFence = std::move(presentFence);
 }
 
 void TransactionCallbackInvoker::sendCallbacks(bool onCommitOnly) {
     // For each listener
     auto completedTransactionsItr = mCompletedTransactions.begin();
+    BackgroundExecutor::Callbacks callbacks;
     while (completedTransactionsItr != mCompletedTransactions.end()) {
         auto& [listener, transactionStatsDeque] = *completedTransactionsItr;
         ListenerStats listenerStats;
@@ -218,7 +220,7 @@
                 // keep it as an IBinder due to consistency reasons: if we
                 // interface_cast at the IPC boundary when reading a Parcel,
                 // we get pointers that compare unequal in the SF process.
-                BackgroundExecutor::getInstance().execute([stats = std::move(listenerStats)]() {
+                callbacks.emplace_back([stats = std::move(listenerStats)]() {
                     interface_cast<ITransactionCompletedListener>(stats.listener)
                             ->onTransactionCompleted(stats);
                 });
@@ -230,6 +232,8 @@
     if (mPresentFence) {
         mPresentFence.clear();
     }
+
+    BackgroundExecutor::getInstance().sendCallbacks(std::move(callbacks));
 }
 
 // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index a68cd87..59abe33 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -18,7 +18,6 @@
 
 #include <condition_variable>
 #include <deque>
-#include <future>
 #include <mutex>
 #include <queue>
 #include <thread>
@@ -26,10 +25,10 @@
 #include <unordered_set>
 
 #include <android-base/thread_annotations.h>
-
 #include <binder/IBinder.h>
+#include <compositionengine/FenceResult.h>
+#include <ftl/future.h>
 #include <gui/ITransactionCompletedListener.h>
-#include <renderengine/RenderEngine.h>
 #include <ui/Fence.h>
 
 namespace android {
@@ -46,7 +45,7 @@
     bool releasePreviousBuffer = false;
     std::string name;
     sp<Fence> previousReleaseFence;
-    std::vector<std::shared_future<renderengine::RenderEngineResult>> previousReleaseFences;
+    std::vector<ftl::SharedFuture<FenceResult>> previousReleaseFences;
     std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence = -1;
     nsecs_t latchTime = -1;
     uint32_t transformHint = 0;
@@ -71,7 +70,7 @@
     status_t registerUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
     void addEmptyTransaction(const ListenerCallbacks& listenerCallbacks);
 
-    void addPresentFence(const sp<Fence>& presentFence);
+    void addPresentFence(sp<Fence>);
 
     void sendCallbacks(bool onCommitOnly);
     void clearCompletedTransactions() {
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index bab5326..61f0fa6 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -98,13 +98,13 @@
     int originUid;
     uint64_t id;
     std::shared_ptr<CountDownLatch> transactionCommittedSignal;
+    bool sentFenceTimeoutWarning = false;
 };
 
 class CountDownLatch {
 public:
     enum {
         eSyncTransaction = 1 << 0,
-        eSyncInputWindows = 1 << 1,
     };
     explicit CountDownLatch(uint32_t flags) : mFlags(flags) {}
 
diff --git a/services/surfaceflinger/TunnelModeEnabledReporter.cpp b/services/surfaceflinger/TunnelModeEnabledReporter.cpp
index 4497caf..bc9b870 100644
--- a/services/surfaceflinger/TunnelModeEnabledReporter.cpp
+++ b/services/surfaceflinger/TunnelModeEnabledReporter.cpp
@@ -59,7 +59,7 @@
 
 void TunnelModeEnabledReporter::addListener(const sp<gui::ITunnelModeEnabledListener>& listener) {
     sp<IBinder> asBinder = IInterface::asBinder(listener);
-    asBinder->linkToDeath(this);
+    asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
     bool tunnelModeEnabled = false;
     {
         std::scoped_lock lock(mMutex);
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index 30b9d8f..a1313e3 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -26,25 +26,43 @@
 using gui::IWindowInfosListener;
 using gui::WindowInfo;
 
-struct WindowInfosListenerInvoker::WindowInfosReportedListener
-      : gui::BnWindowInfosReportedListener {
-    explicit WindowInfosReportedListener(WindowInfosListenerInvoker& invoker) : mInvoker(invoker) {}
+struct WindowInfosListenerInvoker::WindowInfosReportedListener : gui::BnWindowInfosReportedListener,
+                                                                 DeathRecipient {
+    explicit WindowInfosReportedListener(
+            size_t callbackCount,
+            const std::unordered_set<sp<gui::IWindowInfosReportedListener>,
+                                     SpHash<gui::IWindowInfosReportedListener>>&
+                    windowInfosReportedListeners)
+          : mCallbacksPending(callbackCount),
+            mWindowInfosReportedListeners(windowInfosReportedListeners) {}
 
     binder::Status onWindowInfosReported() override {
-        mInvoker.windowInfosReported();
+        // TODO(b/222421815) There could potentially be callbacks that we don't need to wait for
+        // before calling the WindowInfosReportedListeners coming from InputWindowCommands. Filter
+        // the list of callbacks down to those from system server.
+        if (--mCallbacksPending == 0) {
+            for (const auto& listener : mWindowInfosReportedListeners) {
+                sp<IBinder> asBinder = IInterface::asBinder(listener);
+                if (asBinder->isBinderAlive()) {
+                    listener->onWindowInfosReported();
+                }
+            }
+        }
         return binder::Status::ok();
     }
 
-    WindowInfosListenerInvoker& mInvoker;
-};
+    void binderDied(const wp<IBinder>&) { onWindowInfosReported(); }
 
-WindowInfosListenerInvoker::WindowInfosListenerInvoker(SurfaceFlinger& flinger)
-      : mFlinger(flinger),
-        mWindowInfosReportedListener(sp<WindowInfosReportedListener>::make(*this)) {}
+private:
+    std::atomic<size_t> mCallbacksPending;
+    std::unordered_set<sp<gui::IWindowInfosReportedListener>,
+                       SpHash<gui::IWindowInfosReportedListener>>
+            mWindowInfosReportedListeners;
+};
 
 void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) {
     sp<IBinder> asBinder = IInterface::asBinder(listener);
-    asBinder->linkToDeath(this);
+    asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
 
     std::scoped_lock lock(mListenersMutex);
     mWindowInfosListeners.try_emplace(asBinder, std::move(listener));
@@ -55,7 +73,7 @@
     sp<IBinder> asBinder = IInterface::asBinder(listener);
 
     std::scoped_lock lock(mListenersMutex);
-    asBinder->unlinkToDeath(this);
+    asBinder->unlinkToDeath(sp<DeathRecipient>::fromExisting(this));
     mWindowInfosListeners.erase(asBinder);
 }
 
@@ -64,9 +82,11 @@
     mWindowInfosListeners.erase(who);
 }
 
-void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
-                                                    const std::vector<DisplayInfo>& displayInfos,
-                                                    bool shouldSync) {
+void WindowInfosListenerInvoker::windowInfosChanged(
+        const std::vector<WindowInfo>& windowInfos, const std::vector<DisplayInfo>& displayInfos,
+        const std::unordered_set<sp<gui::IWindowInfosReportedListener>,
+                                 SpHash<gui::IWindowInfosReportedListener>>&
+                windowInfosReportedListeners) {
     ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;
     {
         std::scoped_lock lock(mListenersMutex);
@@ -75,18 +95,25 @@
         }
     }
 
-    mCallbacksPending = windowInfosListeners.size();
-
+    auto windowInfosReportedListener = windowInfosReportedListeners.empty()
+            ? nullptr
+            : sp<WindowInfosReportedListener>::make(windowInfosListeners.size(),
+                                                    windowInfosReportedListeners);
     for (const auto& listener : windowInfosListeners) {
-        listener->onWindowInfosChanged(windowInfos, displayInfos,
-                                       shouldSync ? mWindowInfosReportedListener : nullptr);
-    }
-}
+        sp<IBinder> asBinder = IInterface::asBinder(listener);
 
-void WindowInfosListenerInvoker::windowInfosReported() {
-    mCallbacksPending--;
-    if (mCallbacksPending == 0) {
-        mFlinger.windowInfosReported();
+        // linkToDeath is used here to ensure that the windowInfosReportedListeners
+        // are called even if one of the windowInfosListeners dies before
+        // calling onWindowInfosReported.
+        if (windowInfosReportedListener) {
+            asBinder->linkToDeath(windowInfosReportedListener);
+        }
+
+        auto status = listener->onWindowInfosChanged(windowInfos, displayInfos,
+                                                     windowInfosReportedListener);
+        if (windowInfosReportedListener && !status.isOk()) {
+            windowInfosReportedListener->onWindowInfosReported();
+        }
     }
 }
 
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index d8d8d0f..a1d66a1 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -29,22 +29,21 @@
 
 class WindowInfosListenerInvoker : public IBinder::DeathRecipient {
 public:
-    explicit WindowInfosListenerInvoker(SurfaceFlinger&);
-
     void addWindowInfosListener(sp<gui::IWindowInfosListener>);
     void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
 
     void windowInfosChanged(const std::vector<gui::WindowInfo>&,
-                            const std::vector<gui::DisplayInfo>&, bool shouldSync);
+                            const std::vector<gui::DisplayInfo>&,
+                            const std::unordered_set<sp<gui::IWindowInfosReportedListener>,
+                                                     SpHash<gui::IWindowInfosReportedListener>>&
+                                    windowInfosReportedListeners);
 
 protected:
     void binderDied(const wp<IBinder>& who) override;
 
 private:
     struct WindowInfosReportedListener;
-    void windowInfosReported();
 
-    SurfaceFlinger& mFlinger;
     std::mutex mListenersMutex;
 
     static constexpr size_t kStaticCapacity = 3;
@@ -52,7 +51,6 @@
             mWindowInfosListeners GUARDED_BY(mListenersMutex);
 
     sp<gui::IWindowInfosReportedListener> mWindowInfosReportedListener;
-    std::atomic<size_t> mCallbacksPending{0};
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
index a605a2f..fae9165 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -116,7 +116,8 @@
 class DisplayHardwareFuzzer {
 public:
     DisplayHardwareFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) {
-        mPhysicalDisplayId = SurfaceComposerClient::getInternalDisplayId().value();
+        mPhysicalDisplayId = SurfaceComposerClient::getInternalDisplayId().value_or(
+                PhysicalDisplayId::fromPort(mFdp.ConsumeIntegral<uint8_t>()));
     };
     void process();
 
@@ -480,8 +481,8 @@
     BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
 
     sp<FramebufferSurface> surface =
-            new FramebufferSurface(mHwc, mPhysicalDisplayId, bqConsumer, getFuzzedSize() /*size*/,
-                                   getFuzzedSize() /*maxSize*/);
+            sp<FramebufferSurface>::make(mHwc, mPhysicalDisplayId, bqConsumer,
+                                         getFuzzedSize() /*size*/, getFuzzedSize() /*maxSize*/);
     surface->beginFrame(mFdp.ConsumeBool());
 
     surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes));
@@ -497,15 +498,15 @@
     DisplayIdGenerator<HalVirtualDisplayId> mGenerator;
     VirtualDisplayId VirtualDisplayId = mGenerator.generateId().value();
 
-    sp<SurfaceComposerClient> mClient = new SurfaceComposerClient();
+    sp<SurfaceComposerClient> mClient = sp<SurfaceComposerClient>::make();
     sp<SurfaceControl> mSurfaceControl =
             mClient->createSurface(String8("TestSurface"), 100, 100, PIXEL_FORMAT_RGBA_8888,
                                    ISurfaceComposerClient::eFXSurfaceBufferState,
                                    /*parent*/ nullptr);
 
-    sp<BLASTBufferQueue> mBlastBufferQueueAdapter =
-            new BLASTBufferQueue("TestBLASTBufferQueue", mSurfaceControl, 100, 100,
-                                 PIXEL_FORMAT_RGBA_8888);
+    auto mBlastBufferQueueAdapter =
+            sp<BLASTBufferQueue>::make("TestBLASTBufferQueue", mSurfaceControl, 100, 100,
+                                       PIXEL_FORMAT_RGBA_8888);
 
     sp<IGraphicBufferProducer> sink = mBlastBufferQueueAdapter->getIGraphicBufferProducer();
     sp<IGraphicBufferProducer> bqProducer = mBlastBufferQueueAdapter->getIGraphicBufferProducer();
@@ -513,9 +514,9 @@
     BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
     BufferQueue::createBufferQueue(&sink, &bqConsumer);
 
-    sp<VirtualDisplaySurface> surface =
-            new VirtualDisplaySurface(mHwc, VirtualDisplayId, sink, bqProducer, bqConsumer,
-                                      mFdp.ConsumeRandomLengthString().c_str() /*name*/);
+    auto surface =
+            sp<VirtualDisplaySurface>::make(mHwc, VirtualDisplayId, sink, bqProducer, bqConsumer,
+                                            mFdp.ConsumeRandomLengthString().c_str() /*name*/);
 
     surface->beginFrame(mFdp.ConsumeBool());
     surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes));
@@ -565,7 +566,7 @@
 
     mHwc.getLayerReleaseFence(halDisplayID, layer);
 
-    mHwc.setOutputBuffer(halVirtualDisplayId, sp<Fence>::make().get(), sp<GraphicBuffer>::make());
+    mHwc.setOutputBuffer(halVirtualDisplayId, sp<Fence>::make(), sp<GraphicBuffer>::make());
 
     mHwc.clearReleaseFences(halDisplayID);
 
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index f25043c..28b875a 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -103,7 +103,7 @@
 class SurfaceFlingerFuzzer {
 public:
     SurfaceFlingerFuzzer(const uint8_t *data, size_t size) : mFdp(data, size) {
-        mFlinger = mTestableFlinger.flinger();
+        mFlinger = sp<SurfaceFlinger>::fromExisting(mTestableFlinger.flinger());
     };
     void process(const uint8_t *data, size_t size);
 
@@ -151,7 +151,6 @@
     sp<IBinder> handle = defaultServiceManager()->checkService(
             String16(mFdp.ConsumeRandomLengthString().c_str()));
     mFlinger->fromHandle(handle);
-    mFlinger->windowInfosReported();
     mFlinger->disableExpensiveRendering();
 }
 
@@ -245,7 +244,6 @@
     setDisplayStateLocked();
 
     setTransactionState();
-    mTestableFlinger.flushTransactionQueues();
 
     onTransact(data, size);
 }
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index c4cd089..4c649f3 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -30,9 +30,7 @@
 #include <ui/DisplayStatInfo.h>
 #include <ui/DynamicDisplayInfo.h>
 
-#include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
-#include "ContainerLayer.h"
 #include "DisplayDevice.h"
 #include "DisplayHardware/ComposerHal.h"
 #include "EffectLayer.h"
@@ -155,14 +153,22 @@
                                                     ui::PixelFormat::YCBCR_P010,
                                                     ui::PixelFormat::HSV_888};
 
-FloatRect getFuzzedFloatRect(FuzzedDataProvider *fdp) {
+inline VsyncId getFuzzedVsyncId(FuzzedDataProvider& fdp) {
+    return VsyncId{fdp.ConsumeIntegral<int64_t>()};
+}
+
+inline TimePoint getFuzzedTimePoint(FuzzedDataProvider& fdp) {
+    return TimePoint::fromNs(fdp.ConsumeIntegral<nsecs_t>());
+}
+
+inline FloatRect getFuzzedFloatRect(FuzzedDataProvider* fdp) {
     return FloatRect(fdp->ConsumeFloatingPoint<float>() /*left*/,
                      fdp->ConsumeFloatingPoint<float>() /*right*/,
                      fdp->ConsumeFloatingPoint<float>() /*top*/,
                      fdp->ConsumeFloatingPoint<float>() /*bottom*/);
 }
 
-HdrMetadata getFuzzedHdrMetadata(FuzzedDataProvider *fdp) {
+inline HdrMetadata getFuzzedHdrMetadata(FuzzedDataProvider* fdp) {
     HdrMetadata hdrMetadata;
     if (fdp->ConsumeBool()) {
         hdrMetadata.cta8613.maxContentLightLevel = fdp->ConsumeFloatingPoint<float>();
@@ -272,8 +278,8 @@
 
 private:
     // ICompositor overrides:
-    bool commit(nsecs_t, int64_t, nsecs_t) override { return false; }
-    void composite(nsecs_t, int64_t) override {}
+    bool commit(TimePoint, VsyncId, TimePoint) override { return false; }
+    void composite(TimePoint, VsyncId) override {}
     void sample() override {}
 
     // MessageQueue overrides:
@@ -286,13 +292,18 @@
 namespace surfaceflinger::test {
 
 class Factory final : public surfaceflinger::Factory {
+    struct NoOpMessageQueue : android::impl::MessageQueue {
+        using android::impl::MessageQueue::MessageQueue;
+        void onFrameSignal(ICompositor&, VsyncId, TimePoint) override {}
+    };
+
 public:
     ~Factory() = default;
 
-    std::unique_ptr<HWComposer> createHWComposer(const std::string &) override { return nullptr; }
+    std::unique_ptr<HWComposer> createHWComposer(const std::string&) override { return nullptr; }
 
-    std::unique_ptr<MessageQueue> createMessageQueue(ICompositor &compositor) {
-        return std::make_unique<android::impl::MessageQueue>(compositor);
+    std::unique_ptr<MessageQueue> createMessageQueue(ICompositor& compositor) {
+        return std::make_unique<NoOpMessageQueue>(compositor);
     }
 
     std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
@@ -307,21 +318,21 @@
     }
 
     sp<SurfaceInterceptor> createSurfaceInterceptor() override {
-        return new android::impl::SurfaceInterceptor();
+        return sp<android::impl::SurfaceInterceptor>::make();
     }
 
     sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
-        return new StartPropertySetThread(timestampPropertyValue);
+        return sp<StartPropertySetThread>::make(timestampPropertyValue);
     }
 
     sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs &creationArgs) override {
-        return new DisplayDevice(creationArgs);
+        return sp<DisplayDevice>::make(creationArgs);
     }
 
     sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
                                           uint32_t layerCount, uint64_t usage,
                                           std::string requestorName) override {
-        return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
+        return sp<GraphicBuffer>::make(width, height, format, layerCount, usage, requestorName);
     }
 
     void createBufferQueue(sp<IGraphicBufferProducer> *outProducer,
@@ -334,18 +345,6 @@
         mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
     }
 
-    sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer> &producer,
-                                                       const sp<SurfaceFlinger> &flinger,
-                                                       const wp<Layer> &layer) override {
-        return new MonitoredProducer(producer, flinger, layer);
-    }
-
-    sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer> &consumer,
-                                                      renderengine::RenderEngine &renderEngine,
-                                                      uint32_t textureName, Layer *layer) override {
-        return new BufferLayerConsumer(consumer, renderEngine, textureName, layer);
-    }
-
     std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
             const sp<IGraphicBufferProducer> &producer) override {
         if (!mCreateNativeWindowSurface) return nullptr;
@@ -356,20 +355,12 @@
         return compositionengine::impl::createCompositionEngine();
     }
 
-    sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs &) override {
-        return nullptr;
-    }
-
     sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs &) override {
         return nullptr;
     }
 
     sp<EffectLayer> createEffectLayer(const LayerCreationArgs &args) override {
-        return new EffectLayer(args);
-    }
-
-    sp<ContainerLayer> createContainerLayer(const LayerCreationArgs &args) override {
-        return new ContainerLayer(args);
+        return sp<EffectLayer>::make(args);
     }
 
     std::unique_ptr<FrameTracer> createFrameTracer() override {
@@ -447,18 +438,13 @@
         mFlinger->clearStatsLocked(dumpArgs, result);
 
         mFlinger->dumpTimeStats(dumpArgs, fdp->ConsumeBool(), result);
-        FTL_FAKE_GUARD(kMainThreadContext, mFlinger->logFrameStats());
+        FTL_FAKE_GUARD(kMainThreadContext,
+                       mFlinger->logFrameStats(TimePoint::fromNs(fdp->ConsumeIntegral<nsecs_t>())));
 
         result = fdp->ConsumeRandomLengthString().c_str();
         mFlinger->dumpFrameTimeline(dumpArgs, result);
 
         result = fdp->ConsumeRandomLengthString().c_str();
-        mFlinger->dumpStaticScreenStats(result);
-
-        result = fdp->ConsumeRandomLengthString().c_str();
-        mFlinger->dumpFrameEventsLocked(result);
-
-        result = fdp->ConsumeRandomLengthString().c_str();
         mFlinger->dumpRawDisplayIdentificationData(dumpArgs, result);
 
         LayersProto layersProto = mFlinger->dumpDrawingStateProto(fdp->ConsumeIntegral<uint32_t>());
@@ -543,19 +529,9 @@
         mFlinger->setVsyncConfig(vsyncConfig, fdp->ConsumeIntegral<nsecs_t>());
     }
 
-    void updateCompositorTiming(FuzzedDataProvider *fdp) {
-        std::shared_ptr<FenceTime> presentFenceTime = FenceTime::NO_FENCE;
-        mFlinger->updateCompositorTiming({}, fdp->ConsumeIntegral<nsecs_t>(), presentFenceTime);
-    }
-
-    void getCompositorTiming() {
-        CompositorTiming compositorTiming;
-        mFlinger->getCompositorTiming(&compositorTiming);
-    }
-
     sp<IBinder> fuzzBoot(FuzzedDataProvider *fdp) {
         mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(fdp->ConsumeBool());
-        const sp<Client> client = new Client(mFlinger);
+        const sp<Client> client = sp<Client>::make(mFlinger);
 
         DisplayIdGenerator<HalVirtualDisplayId> kGenerator;
         HalVirtualDisplayId halVirtualDisplayId = kGenerator.generateId().value();
@@ -564,7 +540,9 @@
         ui::PixelFormat pixelFormat{};
         mFlinger->getHwComposer().allocateVirtualDisplay(halVirtualDisplayId, uiSize, &pixelFormat);
 
-        PhysicalDisplayId physicalDisplayId = SurfaceComposerClient::getInternalDisplayId().value();
+        PhysicalDisplayId physicalDisplayId =
+                SurfaceComposerClient::getInternalDisplayId().value_or(
+                        PhysicalDisplayId::fromPort(fdp->ConsumeIntegral<uint8_t>()));
         mFlinger->getHwComposer().allocatePhysicalDisplay(kHwDisplayId, physicalDisplayId);
 
         sp<IBinder> display =
@@ -600,7 +578,6 @@
         mFlinger->setAutoLowLatencyMode(display, mFdp.ConsumeBool());
         mFlinger->setGameContentType(display, mFdp.ConsumeBool());
         mFlinger->setPowerMode(display, mFdp.ConsumeIntegral<int>());
-        mFlinger->clearAnimationFrameStats();
 
         overrideHdrTypes(display, &mFdp);
 
@@ -628,13 +605,14 @@
 
         setVsyncConfig(&mFdp);
 
-        mFlinger->flushTransactionQueues(0);
+        FTL_FAKE_GUARD(kMainThreadContext,
+                       mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp)));
 
         mFlinger->setTransactionFlags(mFdp.ConsumeIntegral<uint32_t>());
         mFlinger->clearTransactionFlags(mFdp.ConsumeIntegral<uint32_t>());
         mFlinger->commitOffscreenLayers();
 
-        mFlinger->frameIsEarly(mFdp.ConsumeIntegral<nsecs_t>(), mFdp.ConsumeIntegral<int64_t>());
+        mFlinger->frameIsEarly(getFuzzedTimePoint(mFdp), getFuzzedVsyncId(mFdp));
         mFlinger->computeLayerBounds();
         mFlinger->startBootAnim();
 
@@ -645,14 +623,8 @@
 
         mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mFdp.ConsumeIntegral<uid_t>());
 
-        mFlinger->postComposition();
+        FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postComposition());
 
-        getCompositorTiming();
-
-        updateCompositorTiming(&mFdp);
-
-        mFlinger->setCompositorTimingSnapped({}, mFdp.ConsumeIntegral<nsecs_t>());
-        FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postFrame());
         mFlinger->calculateExpectedPresentTime({});
 
         mFlinger->enableHalVirtualDisplays(mFdp.ConsumeBool());
@@ -760,7 +732,7 @@
         return mFlinger->setPowerModeInternal(display, mode);
     }
 
-    auto &getTransactionQueue() { return mFlinger->mTransactionQueue; }
+    auto &getTransactionQueue() { return mFlinger->mLocklessTransactionQueue; }
     auto &getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
 
     auto setTransactionState(
@@ -775,8 +747,6 @@
                                              listenerCallbacks, transactionId);
     }
 
-    auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(0); };
-
     auto onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
         return mFlinger->onTransact(code, data, reply, flags);
     }
@@ -817,7 +787,8 @@
     void triggerOnFrameRateOverridesChanged() override {}
 
     surfaceflinger::test::Factory mFactory;
-    sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
+    sp<SurfaceFlinger> mFlinger =
+            sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization);
     scheduler::TestableScheduler *mScheduler = nullptr;
     std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
 };
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index 685b44a..aeccc52 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -18,9 +18,8 @@
 #include <Client.h>
 #include <DisplayDevice.h>
 #include <EffectLayer.h>
-#include <LayerRejecter.h>
 #include <LayerRenderArea.h>
-#include <MonitoredProducer.h>
+#include <ftl/future.h>
 #include <fuzzer/FuzzedDataProvider.h>
 #include <gui/IProducerListener.h>
 #include <gui/LayerDebugInfo.h>
@@ -78,7 +77,7 @@
 
 void LayerFuzzer::invokeEffectLayer() {
     TestableSurfaceFlinger flinger;
-    sp<Client> client = sp<Client>::make(flinger.flinger());
+    sp<Client> client = sp<Client>::make(sp<SurfaceFlinger>::fromExisting(flinger.flinger()));
     const LayerCreationArgs layerCreationArgs = createLayerCreationArgs(&flinger, client);
     sp<EffectLayer> effectLayer = sp<EffectLayer>::make(layerCreationArgs);
 
@@ -110,24 +109,23 @@
 
 void LayerFuzzer::invokeBufferStateLayer() {
     TestableSurfaceFlinger flinger;
-    sp<Client> client = sp<Client>::make(flinger.flinger());
+    sp<Client> client = sp<Client>::make(sp<SurfaceFlinger>::fromExisting(flinger.flinger()));
     sp<BufferStateLayer> layer =
             sp<BufferStateLayer>::make(createLayerCreationArgs(&flinger, client));
     sp<Fence> fence = sp<Fence>::make();
     const std::shared_ptr<FenceTime> fenceTime = std::make_shared<FenceTime>(fence);
 
-    const CompositorTiming compositor = {mFdp.ConsumeIntegral<int64_t>(),
-                                         mFdp.ConsumeIntegral<int64_t>(),
-                                         mFdp.ConsumeIntegral<int64_t>()};
-    std::packaged_task<renderengine::RenderEngineResult()> renderResult([&] {
-        return renderengine::RenderEngineResult{mFdp.ConsumeIntegral<int32_t>(),
-                                                base::unique_fd(fence->get())};
-    });
-    layer->onLayerDisplayed(renderResult.get_future());
+    const CompositorTiming compositorTiming(mFdp.ConsumeIntegral<int64_t>(),
+                                            mFdp.ConsumeIntegral<int64_t>(),
+                                            mFdp.ConsumeIntegral<int64_t>(),
+                                            mFdp.ConsumeIntegral<int64_t>());
+
+    layer->onLayerDisplayed(ftl::yield<FenceResult>(fence).share());
+    layer->onLayerDisplayed(
+            ftl::yield<FenceResult>(base::unexpected(mFdp.ConsumeIntegral<status_t>())).share());
+
     layer->releasePendingBuffer(mFdp.ConsumeIntegral<int64_t>());
-    layer->finalizeFrameEventHistory(fenceTime, compositor);
-    layer->onPostComposition(nullptr, fenceTime, fenceTime, compositor);
-    layer->isBufferDue(mFdp.ConsumeIntegral<int64_t>());
+    layer->onPostComposition(nullptr, fenceTime, fenceTime, compositorTiming);
 
     layer->setTransform(mFdp.ConsumeIntegral<uint32_t>());
     layer->setTransformToDisplayInverse(mFdp.ConsumeBool());
@@ -148,12 +146,9 @@
     const bool ownsHandle = mFdp.ConsumeBool();
     sp<NativeHandle> nativeHandle = sp<NativeHandle>::make(testHandle, ownsHandle);
     layer->setSidebandStream(nativeHandle);
-    layer->addFrameEvent(fence, mFdp.ConsumeIntegral<int64_t>() /*postedTime*/,
-                         mFdp.ConsumeIntegral<int64_t>() /*requestedTime*/);
     layer->computeSourceBounds(getFuzzedFloatRect(&mFdp));
 
     layer->fenceHasSignaled();
-    layer->framePresentTimeIsCurrent(mFdp.ConsumeIntegral<int64_t>());
     layer->onPreComposition(mFdp.ConsumeIntegral<int64_t>());
     const std::vector<sp<CallbackHandle>> callbacks;
     layer->setTransactionCompletedListeners(callbacks);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index da60a69..f507ef0 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -19,6 +19,8 @@
 #include <fuzzer/FuzzedDataProvider.h>
 #include <processgroup/sched_policy.h>
 
+#include <scheduler/PresentLatencyTracker.h>
+
 #include "Scheduler/DispSyncSource.h"
 #include "Scheduler/OneShotTimer.h"
 #include "Scheduler/VSyncDispatchTimerQueue.h"
@@ -58,6 +60,7 @@
 private:
     void fuzzRefreshRateSelection();
     void fuzzRefreshRateConfigs();
+    void fuzzPresentLatencyTracker();
     void fuzzVSyncModulator();
     void fuzzVSyncPredictor();
     void fuzzVSyncReactor();
@@ -93,8 +96,8 @@
 
     thread->onHotplugReceived(getPhysicalDisplayId(), mFdp.ConsumeBool());
     sp<EventThreadConnection> connection =
-            new EventThreadConnection(thread.get(), mFdp.ConsumeIntegral<uint16_t>(), nullptr,
-                                      {} /*eventRegistration*/);
+            sp<EventThreadConnection>::make(thread.get(), mFdp.ConsumeIntegral<uint16_t>(),
+                                            nullptr);
     thread->requestNextVsync(connection);
     thread->setVsyncRate(mFdp.ConsumeIntegral<uint32_t>() /*rate*/, connection);
 
@@ -224,8 +227,8 @@
     nsecs_t time2 = time1;
     uint8_t historySize = mFdp.ConsumeIntegral<uint8_t>();
 
-    sp<FuzzImplLayer> layer1 = new FuzzImplLayer(flinger.flinger());
-    sp<FuzzImplLayer> layer2 = new FuzzImplLayer(flinger.flinger());
+    sp<FuzzImplLayer> layer1 = sp<FuzzImplLayer>::make(flinger.flinger());
+    sp<FuzzImplLayer> layer2 = sp<FuzzImplLayer>::make(flinger.flinger());
 
     for (int i = 0; i < historySize; ++i) {
         historyV1.record(layer1.get(), time1, time1,
@@ -260,7 +263,7 @@
     reactor.addHwVsyncTimestamp(0, std::nullopt, &periodFlushed);
     reactor.addHwVsyncTimestamp(mFdp.ConsumeIntegral<nsecs_t>() /*newPeriod*/, std::nullopt,
                                 &periodFlushed);
-    sp<Fence> fence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
+    sp<Fence> fence = sp<Fence>::make(memfd_create("fd", MFD_ALLOW_SEALING));
     std::shared_ptr<FenceTime> ft = std::make_shared<FenceTime>(fence);
     vSyncTracker->addVsyncTimestamp(mFdp.ConsumeIntegral<nsecs_t>());
     FenceTime::Snapshot snap(mFdp.ConsumeIntegral<nsecs_t>());
@@ -319,7 +322,7 @@
     LayerCreationArgs args(flinger.flinger(), client,
                            mFdp.ConsumeRandomLengthString(kRandomStringLength) /*name*/,
                            mFdp.ConsumeIntegral<uint16_t>() /*layerFlags*/, LayerMetadata());
-    sp<Layer> layer = new BufferQueueLayer(args);
+    sp<Layer> layer = sp<BufferStateLayer>::make(args);
 
     layer->setFrameRateSelectionPriority(mFdp.ConsumeIntegral<int16_t>());
 }
@@ -382,9 +385,16 @@
     refreshRateStats.setPowerMode(mFdp.PickValueInArray(kPowerModes));
 }
 
+void SchedulerFuzzer::fuzzPresentLatencyTracker() {
+    scheduler::PresentLatencyTracker tracker;
+    tracker.trackPendingFrame(TimePoint::fromNs(mFdp.ConsumeIntegral<nsecs_t>()),
+                              FenceTime::NO_FENCE);
+}
+
 void SchedulerFuzzer::process() {
     fuzzRefreshRateSelection();
     fuzzRefreshRateConfigs();
+    fuzzPresentLatencyTracker();
     fuzzVSyncModulator();
     fuzzVSyncPredictor();
     fuzzVSyncReactor();
diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto
index 13647b6..804a499 100644
--- a/services/surfaceflinger/layerproto/layerstrace.proto
+++ b/services/surfaceflinger/layerproto/layerstrace.proto
@@ -38,9 +38,13 @@
 
     optional fixed64 magic_number = 1;  /* Must be the first field, set to value in MagicNumber */
     repeated LayersTraceProto entry = 2;
+
+    /* offset between real-time clock and elapsed time clock in nanoseconds.
+       Calculated as: systemTime(SYSTEM_TIME_REALTIME) - systemTime(SYSTEM_TIME_MONOTONIC) */
+    optional fixed64 real_to_elapsed_time_offset_nanos = 3;
 }
 
-/* one window manager trace entry. */
+/* one layers trace entry. */
 message LayersTraceProto {
     /* required: elapsed realtime in nanos since boot of when this entry was logged */
     optional sfixed64 elapsed_realtime_nanos = 1;
@@ -60,4 +64,6 @@
     optional uint32 missed_entries = 6;
 
     repeated DisplayProto displays = 7;
+
+    optional int64 vsync_id = 8;
 }
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index 4f99b19..49487ee 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -36,6 +36,10 @@
 
     fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */
     repeated TransactionTraceEntry entry = 2;
+
+    /* offset between real-time clock and elapsed time clock in nanoseconds.
+       Calculated as: systemTime(SYSTEM_TIME_REALTIME) - systemTime(SYSTEM_TIME_MONOTONIC) */
+    fixed64 real_to_elapsed_time_offset_nanos = 3;
 }
 
 message TransactionTraceEntry {
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index ec18054..fedd71e 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -67,7 +67,7 @@
     using android::frameworks::displayservice::V1_0::implementation::DisplayService;
     using android::frameworks::displayservice::V1_0::IDisplayService;
 
-    sp<IDisplayService> displayservice = new DisplayService();
+    sp<IDisplayService> displayservice = sp<DisplayService>::make();
     status_t err = displayservice->registerAsService();
 
     // b/141930622
@@ -153,7 +153,7 @@
                    IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
 
     // publish gui::ISurfaceComposer, the new AIDL interface
-    sp<SurfaceComposerAIDL> composerAIDL = new SurfaceComposerAIDL(flinger);
+    sp<SurfaceComposerAIDL> composerAIDL = sp<SurfaceComposerAIDL>::make(flinger);
     sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false,
                    IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
 
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index ceddf27..276431e 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -34,6 +34,7 @@
         "DisplayConfigs_test.cpp",
         "DisplayEventReceiver_test.cpp",
         "EffectLayer_test.cpp",
+        "LayerBorder_test.cpp",
         "InvalidHandles_test.cpp",
         "LayerCallback_test.cpp",
         "LayerRenderTypeTransaction_test.cpp",
diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp
index 47a150d..d74bd55 100644
--- a/services/surfaceflinger/tests/BufferGenerator.cpp
+++ b/services/surfaceflinger/tests/BufferGenerator.cpp
@@ -70,12 +70,13 @@
         consumer->setDefaultBufferSize(width, height);
         consumer->setDefaultBufferFormat(format);
 
-        mBufferItemConsumer = new BufferItemConsumer(consumer, GraphicBuffer::USAGE_HW_TEXTURE);
+        mBufferItemConsumer =
+                sp<BufferItemConsumer>::make(consumer, GraphicBuffer::USAGE_HW_TEXTURE);
 
-        mListener = new BufferListener(consumer, callback);
+        mListener = sp<BufferListener>::make(consumer, callback);
         mBufferItemConsumer->setFrameAvailableListener(mListener);
 
-        mSurface = new Surface(producer, true);
+        mSurface = sp<Surface>::make(producer, true);
     }
 
     /* Used by Egl manager. The surface is never displayed. */
@@ -364,7 +365,7 @@
         *outBuffer = mGraphicBuffer;
     }
     if (outFence) {
-        *outFence = new Fence(mFence);
+        *outFence = sp<Fence>::make(mFence);
     } else {
         close(mFence);
     }
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 8a443b8..353b813 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -77,7 +77,7 @@
     sp<SurfaceControl> mVirtualSurfaceControl;
 
     void initClient() {
-        mComposerClient = new SurfaceComposerClient;
+        mComposerClient = sp<SurfaceComposerClient>::make();
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
     }
 
@@ -169,7 +169,7 @@
 
     // Anyone else can init the client.
     setBinUID();
-    mComposerClient = new SurfaceComposerClient;
+    mComposerClient = sp<SurfaceComposerClient>::make();
     ASSERT_NO_FATAL_FAILURE(initClient());
 }
 
diff --git a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
index 0e54664..0df7e2f 100644
--- a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
+++ b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
@@ -36,7 +36,8 @@
     EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now)
             << "Deadline timestamp should be greater than frame time";
     for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
-        EXPECT_NE(FrameTimelineInfo::INVALID_VSYNC_ID, vsyncEventData.frameTimelines[i].vsyncId);
+        EXPECT_NE(gui::FrameTimelineInfo::INVALID_VSYNC_ID,
+                  vsyncEventData.frameTimelines[i].vsyncId);
         EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime,
                   vsyncEventData.frameTimelines[i].deadlineTimestamp)
                 << "Expected vsync timestamp should be greater than deadline";
@@ -51,4 +52,4 @@
     }
 }
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
index ce94dab..c63d251 100644
--- a/services/surfaceflinger/tests/IPC_test.cpp
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -136,7 +136,7 @@
     }
 
     status_t initClient() override {
-        mClient = new SurfaceComposerClient;
+        mClient = sp<SurfaceComposerClient>::make();
         auto err = mClient->initCheck();
         return err;
     }
@@ -221,7 +221,7 @@
         ProcessState::self()->startThreadPool();
     }
     void SetUp() {
-        mClient = new SurfaceComposerClient;
+        mClient = sp<SurfaceComposerClient>::make();
         ASSERT_EQ(NO_ERROR, mClient->initCheck());
 
         mPrimaryDisplay = mClient->getInternalDisplayToken();
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index 023133f..741b6f7 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -42,13 +42,13 @@
     sp<SurfaceComposerClient> mScc;
     sp<SurfaceControl> mNotSc;
     void SetUp() override {
-        mScc = new SurfaceComposerClient;
+        mScc = sp<SurfaceComposerClient>::make();
         ASSERT_EQ(NO_ERROR, mScc->initCheck());
         mNotSc = makeNotSurfaceControl();
     }
 
     sp<SurfaceControl> makeNotSurfaceControl() {
-        return new SurfaceControl(mScc, new NotALayer(), 1);
+        return sp<SurfaceControl>::make(mScc, sp<NotALayer>::make(), 1);
     }
 };
 
diff --git a/services/surfaceflinger/tests/LayerBorder_test.cpp b/services/surfaceflinger/tests/LayerBorder_test.cpp
new file mode 100644
index 0000000..0d55ec1
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerBorder_test.cpp
@@ -0,0 +1,285 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+// TODO: Amend all tests when screenshots become fully reworked for borders
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <chrono> // std::chrono::seconds
+#include <thread> // std::this_thread::sleep_for
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class LayerBorderTest : public LayerTransactionTest {
+protected:
+    virtual void SetUp() {
+        LayerTransactionTest::SetUp();
+        ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+        toHalf3 = ColorTransformHelper::toHalf3;
+        toHalf4 = ColorTransformHelper::toHalf4;
+
+        const auto display = SurfaceComposerClient::getInternalDisplayToken();
+        ASSERT_FALSE(display == nullptr);
+        mColorOrange = toHalf4({255, 140, 0, 255});
+        mParentLayer = createColorLayer("Parent layer", Color::RED);
+
+        mContainerLayer = mClient->createSurface(String8("Container Layer"), 0 /* width */,
+                                                 0 /* height */, PIXEL_FORMAT_RGBA_8888,
+                                                 ISurfaceComposerClient::eFXSurfaceContainer |
+                                                         ISurfaceComposerClient::eNoColorFill,
+                                                 mParentLayer->getHandle());
+        EXPECT_NE(nullptr, mContainerLayer.get()) << "failed to create container layer";
+
+        mEffectLayer1 = mClient->createSurface(String8("Effect Layer"), 0 /* width */,
+                                               0 /* height */, PIXEL_FORMAT_RGBA_8888,
+                                               ISurfaceComposerClient::eFXSurfaceEffect |
+                                                       ISurfaceComposerClient::eNoColorFill,
+                                               mContainerLayer->getHandle());
+        EXPECT_NE(nullptr, mEffectLayer1.get()) << "failed to create effect layer 1";
+
+        mEffectLayer2 = mClient->createSurface(String8("Effect Layer"), 0 /* width */,
+                                               0 /* height */, PIXEL_FORMAT_RGBA_8888,
+                                               ISurfaceComposerClient::eFXSurfaceEffect |
+                                                       ISurfaceComposerClient::eNoColorFill,
+                                               mContainerLayer->getHandle());
+
+        EXPECT_NE(nullptr, mEffectLayer2.get()) << "failed to create effect layer 2";
+
+        asTransaction([&](Transaction& t) {
+            t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
+            t.setLayer(mParentLayer, INT32_MAX - 20).show(mParentLayer);
+            t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+
+            t.setColor(mEffectLayer1, toHalf3(Color::BLUE));
+
+            t.setColor(mEffectLayer2, toHalf3(Color::GREEN));
+        });
+    }
+
+    virtual void TearDown() {
+        // Uncomment the line right below when running any of the tests
+        // std::this_thread::sleep_for (std::chrono::seconds(30));
+        LayerTransactionTest::TearDown();
+        mParentLayer = 0;
+    }
+
+    std::function<half3(Color)> toHalf3;
+    std::function<half4(Color)> toHalf4;
+    sp<SurfaceControl> mParentLayer, mContainerLayer, mEffectLayer1, mEffectLayer2;
+    half4 mColorOrange;
+};
+
+TEST_F(LayerBorderTest, OverlappingVisibleRegions) {
+    asTransaction([&](Transaction& t) {
+        t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400));
+        t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600));
+
+        t.enableBorder(mContainerLayer, true, 20, mColorOrange);
+        t.show(mEffectLayer1);
+        t.show(mEffectLayer2);
+        t.show(mContainerLayer);
+    });
+}
+
+TEST_F(LayerBorderTest, PartiallyCoveredVisibleRegion) {
+    asTransaction([&](Transaction& t) {
+        t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400));
+        t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600));
+
+        t.enableBorder(mEffectLayer1, true, 20, mColorOrange);
+        t.show(mEffectLayer1);
+        t.show(mEffectLayer2);
+        t.show(mContainerLayer);
+    });
+}
+
+TEST_F(LayerBorderTest, NonOverlappingVisibleRegion) {
+    asTransaction([&](Transaction& t) {
+        t.setCrop(mEffectLayer1, Rect(0, 0, 200, 200));
+        t.setCrop(mEffectLayer2, Rect(400, 400, 600, 600));
+
+        t.enableBorder(mContainerLayer, true, 20, mColorOrange);
+        t.show(mEffectLayer1);
+        t.show(mEffectLayer2);
+        t.show(mContainerLayer);
+    });
+}
+
+TEST_F(LayerBorderTest, EmptyVisibleRegion) {
+    asTransaction([&](Transaction& t) {
+        t.setCrop(mEffectLayer1, Rect(200, 200, 400, 400));
+        t.setCrop(mEffectLayer2, Rect(0, 0, 600, 600));
+
+        t.enableBorder(mEffectLayer1, true, 20, mColorOrange);
+        t.show(mEffectLayer1);
+        t.show(mEffectLayer2);
+        t.show(mContainerLayer);
+    });
+}
+
+TEST_F(LayerBorderTest, ZOrderAdjustment) {
+    asTransaction([&](Transaction& t) {
+        t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400));
+        t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600));
+        t.setLayer(mParentLayer, 10);
+        t.setLayer(mEffectLayer1, 30);
+        t.setLayer(mEffectLayer2, 20);
+
+        t.enableBorder(mEffectLayer1, true, 20, mColorOrange);
+        t.show(mEffectLayer1);
+        t.show(mEffectLayer2);
+        t.show(mContainerLayer);
+    });
+}
+
+TEST_F(LayerBorderTest, GrandChildHierarchy) {
+    sp<SurfaceControl> containerLayer2 =
+            mClient->createSurface(String8("Container Layer"), 0 /* width */, 0 /* height */,
+                                   PIXEL_FORMAT_RGBA_8888,
+                                   ISurfaceComposerClient::eFXSurfaceContainer |
+                                           ISurfaceComposerClient::eNoColorFill,
+                                   mContainerLayer->getHandle());
+    EXPECT_NE(nullptr, containerLayer2.get()) << "failed to create container layer 2";
+
+    sp<SurfaceControl> effectLayer3 =
+            mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */,
+                                   PIXEL_FORMAT_RGBA_8888,
+                                   ISurfaceComposerClient::eFXSurfaceEffect |
+                                           ISurfaceComposerClient::eNoColorFill,
+                                   containerLayer2->getHandle());
+
+    asTransaction([&](Transaction& t) {
+        t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400));
+        t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600));
+        t.setCrop(effectLayer3, Rect(400, 400, 800, 800));
+        t.setColor(effectLayer3, toHalf3(Color::BLUE));
+
+        t.enableBorder(mContainerLayer, true, 20, mColorOrange);
+        t.show(mEffectLayer1);
+        t.show(mEffectLayer2);
+        t.show(effectLayer3);
+        t.show(mContainerLayer);
+    });
+}
+
+TEST_F(LayerBorderTest, TransparentAlpha) {
+    asTransaction([&](Transaction& t) {
+        t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400));
+        t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600));
+        t.setAlpha(mEffectLayer1, 0.0f);
+
+        t.enableBorder(mContainerLayer, true, 20, mColorOrange);
+        t.show(mEffectLayer1);
+        t.show(mEffectLayer2);
+        t.show(mContainerLayer);
+    });
+}
+
+TEST_F(LayerBorderTest, SemiTransparentAlpha) {
+    asTransaction([&](Transaction& t) {
+        t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400));
+        t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600));
+        t.setAlpha(mEffectLayer2, 0.5f);
+
+        t.enableBorder(mEffectLayer2, true, 20, mColorOrange);
+        t.show(mEffectLayer1);
+        t.show(mEffectLayer2);
+        t.show(mContainerLayer);
+    });
+}
+
+TEST_F(LayerBorderTest, InvisibleLayers) {
+    asTransaction([&](Transaction& t) {
+        t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400));
+        t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600));
+
+        t.enableBorder(mContainerLayer, true, 20, mColorOrange);
+        t.hide(mEffectLayer2);
+        t.show(mContainerLayer);
+    });
+}
+
+TEST_F(LayerBorderTest, BufferStateLayer) {
+    asTransaction([&](Transaction& t) {
+        t.hide(mEffectLayer1);
+        t.hide(mEffectLayer2);
+        t.show(mContainerLayer);
+
+        sp<SurfaceControl> bufferStateLayer =
+                mClient->createSurface(String8("BufferState"), 0 /* width */, 0 /* height */,
+                                       PIXEL_FORMAT_RGBA_8888,
+                                       ISurfaceComposerClient::eFXSurfaceBufferState,
+                                       mContainerLayer->getHandle());
+
+        sp<GraphicBuffer> buffer =
+                sp<GraphicBuffer>::make(400u, 400u, PIXEL_FORMAT_RGBA_8888, 1u,
+                                        BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                                BufferUsage::COMPOSER_OVERLAY |
+                                                BufferUsage::GPU_TEXTURE,
+                                        "test");
+        TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 200, 200), Color::GREEN);
+        TransactionUtils::fillGraphicBufferColor(buffer, Rect(200, 200, 400, 400), Color::BLUE);
+
+        t.setBuffer(bufferStateLayer, buffer);
+        t.setPosition(bufferStateLayer, 100, 100);
+        t.show(bufferStateLayer);
+        t.enableBorder(mContainerLayer, true, 20, mColorOrange);
+    });
+}
+
+TEST_F(LayerBorderTest, CustomWidth) {
+    asTransaction([&](Transaction& t) {
+        t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400));
+        t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600));
+
+        t.enableBorder(mContainerLayer, true, 50, mColorOrange);
+        t.show(mEffectLayer1);
+        t.show(mEffectLayer2);
+        t.show(mContainerLayer);
+    });
+}
+
+TEST_F(LayerBorderTest, CustomColor) {
+    asTransaction([&](Transaction& t) {
+        t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400));
+        t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600));
+
+        t.enableBorder(mContainerLayer, true, 20, toHalf4({255, 0, 255, 255}));
+        t.show(mEffectLayer1);
+        t.show(mEffectLayer2);
+        t.show(mContainerLayer);
+    });
+}
+
+TEST_F(LayerBorderTest, CustomWidthAndColorAndOpacity) {
+    asTransaction([&](Transaction& t) {
+        t.setCrop(mEffectLayer1, Rect(0, 0, 200, 200));
+        t.setCrop(mEffectLayer2, Rect(400, 400, 600, 600));
+
+        t.enableBorder(mContainerLayer, true, 40, toHalf4({255, 255, 0, 128}));
+        t.show(mEffectLayer1);
+        t.show(mEffectLayer2);
+        t.show(mContainerLayer);
+    });
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 9c0c788..1460fe1 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -55,24 +55,34 @@
         return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState);
     }
 
+    static int fillBuffer(Transaction& transaction, const sp<SurfaceControl>& layer,
+                          bool setBuffer = true, bool setBackgroundColor = false) {
+        sp<GraphicBuffer> buffer;
+        sp<Fence> fence;
+        if (setBuffer) {
+            int err = getBuffer(&buffer, &fence);
+            if (err != NO_ERROR) {
+                return err;
+            }
+
+            transaction.setBuffer(layer, buffer, fence);
+        }
+
+        if (setBackgroundColor) {
+            transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
+                                           ui::Dataspace::UNKNOWN);
+        }
+
+        return NO_ERROR;
+    }
+
     static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
                                const sp<SurfaceControl>& layer = nullptr, bool setBuffer = true,
                                bool setBackgroundColor = false) {
         if (layer) {
-            sp<GraphicBuffer> buffer;
-            sp<Fence> fence;
-            if (setBuffer) {
-                int err = getBuffer(&buffer, &fence);
-                if (err != NO_ERROR) {
-                    return err;
-                }
-
-                transaction.setBuffer(layer, buffer, fence);
-            }
-
-            if (setBackgroundColor) {
-                transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
-                                               ui::Dataspace::UNKNOWN);
+            int err = fillBuffer(transaction, layer, setBuffer, setBackgroundColor);
+            if (err != NO_ERROR) {
+                return err;
             }
         }
 
@@ -432,8 +442,8 @@
 }
 
 TEST_F(LayerCallbackTest, Merge_DifferentClients) {
-    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
-            client2(new SurfaceComposerClient);
+    sp<SurfaceComposerClient> client1(sp<SurfaceComposerClient>::make()),
+            client2(sp<SurfaceComposerClient>::make());
 
     ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
     ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
@@ -610,8 +620,8 @@
 }
 
 TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) {
-    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
-            client2(new SurfaceComposerClient);
+    sp<SurfaceComposerClient> client1(sp<SurfaceComposerClient>::make()),
+            client2(sp<SurfaceComposerClient>::make());
     ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
     ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
 
@@ -659,8 +669,8 @@
 }
 
 TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateChange) {
-    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
-            client2(new SurfaceComposerClient);
+    sp<SurfaceComposerClient> client1(sp<SurfaceComposerClient>::make()),
+            client2(sp<SurfaceComposerClient>::make());
     ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
     ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
 
@@ -720,8 +730,8 @@
 }
 
 TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateChange) {
-    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
-            client2(new SurfaceComposerClient);
+    sp<SurfaceComposerClient> client1(sp<SurfaceComposerClient>::make()),
+            client2(sp<SurfaceComposerClient>::make());
 
     ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
     ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
@@ -1118,7 +1128,7 @@
     Transaction transaction;
     CallbackHelper callback;
     int err = fillTransaction(transaction, &callback, layer, true);
-    err |= fillTransaction(transaction, &callback, offscreenLayer, true);
+    err |= fillBuffer(transaction, offscreenLayer);
     if (err) {
         GTEST_SUCCEED() << "test not supported";
         return;
@@ -1132,5 +1142,86 @@
     committedSc.insert(layer);
     committedSc.insert(offscreenLayer);
     EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, offscreenLayer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
 }
+
+TEST_F(LayerCallbackTest, TransactionCommittedCallback_BSL) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer, true);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply();
+    std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+    committedSc.insert(layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, TransactionCommittedCallback_EffectLayer) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createColorLayer("ColorLayer", Color::RED));
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply();
+    std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+    EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+
+    ExpectedResult expected;
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, TransactionCommittedCallback_ContainerLayer) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer(mClient, "Container Layer", 0, 0,
+                                                ISurfaceComposerClient::eFXSurfaceContainer));
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply();
+    std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+    EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+
+    ExpectedResult expected;
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, TransactionCommittedCallback_NoLayer) {
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply();
+    std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+    EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+
+    ExpectedResult expected;
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 0e2bc3d..bbe7ae8 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -328,7 +328,7 @@
             layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
 
     sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+            sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
 
     ASSERT_NO_FATAL_FAILURE(
             TransactionUtils::fillGraphicBufferColor(buffer, top, Color::TRANSPARENT));
@@ -352,7 +352,7 @@
         shot->expectColor(bottom, Color::BLACK);
     }
 
-    buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+    buffer = sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
 
     ASSERT_NO_FATAL_FAILURE(TransactionUtils::fillGraphicBufferColor(buffer, top, Color::RED));
     ASSERT_NO_FATAL_FAILURE(
@@ -894,7 +894,7 @@
     ASSERT_NO_FATAL_FAILURE(
             layer = createLayer("test", 32, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
     sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 64, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+            sp<GraphicBuffer>::make(32, 64, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
     TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE);
     TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED);
 
@@ -1197,7 +1197,7 @@
 
     size_t idx = 0;
     for (auto& buffer : buffers) {
-        buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+        buffer = sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
         Color color = colors[idx % colors.size()];
         TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
         idx++;
@@ -1230,7 +1230,7 @@
 
     size_t idx = 0;
     for (auto& buffer : buffers) {
-        buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+        buffer = sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
         Color color = colors[idx % colors.size()];
         TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
         idx++;
@@ -1263,7 +1263,7 @@
 
     size_t idx = 0;
     for (auto& buffer : buffers) {
-        buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+        buffer = sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
         Color color = colors[idx % colors.size()];
         TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
         idx++;
@@ -1344,7 +1344,7 @@
             layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
 
     sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+            sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
     TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
 
     sp<Fence> fence;
@@ -1370,7 +1370,7 @@
             layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
 
     sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+            sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
     TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
 
     sp<Fence> fence = Fence::NO_FENCE;
@@ -1388,7 +1388,7 @@
             layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
 
     sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+            sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
     TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
 
     Transaction().setBuffer(layer, buffer).setDataspace(layer, ui::Dataspace::UNKNOWN).apply();
@@ -1404,7 +1404,7 @@
             layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
 
     sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+            sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
     TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
 
     HdrMetadata hdrMetadata;
@@ -1422,7 +1422,7 @@
             layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
 
     sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+            sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
     TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
 
     Region region;
@@ -1440,7 +1440,7 @@
             layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
 
     sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+            sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
     TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
 
     Transaction().setBuffer(layer, buffer).setApi(layer, NATIVE_WINDOW_API_CPU).apply();
diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp
index 094b0ff..fbbf322 100644
--- a/services/surfaceflinger/tests/LayerState_test.cpp
+++ b/services/surfaceflinger/tests/LayerState_test.cpp
@@ -35,7 +35,7 @@
     args.frameScaleX = 2;
     args.frameScaleY = 4;
     args.captureSecureLayers = true;
-    args.displayToken = new BBinder();
+    args.displayToken = sp<BBinder>::make();
     args.width = 10;
     args.height = 20;
     args.useIdentityTransform = true;
@@ -67,8 +67,8 @@
     args.frameScaleX = 2;
     args.frameScaleY = 4;
     args.captureSecureLayers = true;
-    args.layerHandle = new BBinder();
-    args.excludeHandles = {new BBinder(), new BBinder()};
+    args.layerHandle = sp<BBinder>::make();
+    args.excludeHandles = {sp<BBinder>::make(), sp<BBinder>::make()};
     args.childrenOnly = false;
     args.grayscale = true;
 
@@ -92,8 +92,8 @@
 
 TEST(LayerStateTest, ParcellingScreenCaptureResults) {
     ScreenCaptureResults results;
-    results.buffer = new GraphicBuffer(100, 200, PIXEL_FORMAT_RGBA_8888, 1, 0);
-    results.fence = new Fence(dup(fileno(tmpfile())));
+    results.buffer = sp<GraphicBuffer>::make(100u, 200u, PIXEL_FORMAT_RGBA_8888, 1u, 0u);
+    results.fence = sp<Fence>::make(dup(fileno(tmpfile())));
     results.capturedSecureLayers = true;
     results.capturedDataspace = ui::Dataspace::DISPLAY_P3;
     results.result = BAD_VALUE;
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index b46db65..4b91605 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -41,7 +41,7 @@
 class LayerTransactionTest : public ::testing::Test {
 protected:
     void SetUp() override {
-        mClient = new SurfaceComposerClient;
+        mClient = sp<SurfaceComposerClient>::make();
         ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
 
         ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
@@ -140,10 +140,13 @@
     virtual void fillBufferStateLayerColor(const sp<SurfaceControl>& layer, const Color& color,
                                            int32_t bufferWidth, int32_t bufferHeight) {
         sp<GraphicBuffer> buffer =
-                new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
-                                  BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                          BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE,
-                                  "test");
+                sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth),
+                                        static_cast<uint32_t>(bufferHeight), PIXEL_FORMAT_RGBA_8888,
+                                        1u,
+                                        BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                                BufferUsage::COMPOSER_OVERLAY |
+                                                BufferUsage::GPU_TEXTURE,
+                                        "test");
         TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight),
                                                  color);
         Transaction().setBuffer(layer, buffer).apply();
@@ -209,10 +212,13 @@
                                               const Color& topRight, const Color& bottomLeft,
                                               const Color& bottomRight) {
         sp<GraphicBuffer> buffer =
-                new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
-                                  BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                          BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE,
-                                  "test");
+                sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth),
+                                        static_cast<uint32_t>(bufferHeight), PIXEL_FORMAT_RGBA_8888,
+                                        1u,
+                                        BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                                BufferUsage::COMPOSER_OVERLAY |
+                                                BufferUsage::GPU_TEXTURE,
+                                        "test");
 
         ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
 
diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp
index ef992d6..513fdc3 100644
--- a/services/surfaceflinger/tests/LayerTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp
@@ -80,7 +80,7 @@
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
     const auto producer = layer->getIGraphicBufferProducer();
-    const sp<IProducerListener> stubListener(new StubProducerListener);
+    const sp<IProducerListener> stubListener(sp<StubProducerListener>::make());
     IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
     ASSERT_EQ(OK, producer->connect(stubListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput));
 
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index 9cb617a..f247c9f 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -799,7 +799,7 @@
     sp<Surface> surface = layer->getSurface();
 
     sp<GraphicBuffer> buffer =
-            new GraphicBuffer(width, height, PIXEL_FORMAT_RGBX_8888, 1, kUsageFlags, "test");
+            sp<GraphicBuffer>::make(width, height, PIXEL_FORMAT_RGBX_8888, 1, kUsageFlags, "test");
     ASSERT_NO_FATAL_FAILURE(
             TransactionUtils::fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
 
@@ -815,7 +815,7 @@
         shot->expectColor(crop, Color::BLACK);
     }
 
-    buffer = new GraphicBuffer(width, height, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+    buffer = sp<GraphicBuffer>::make(width, height, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
     ASSERT_NO_FATAL_FAILURE(
             TransactionUtils::fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
 
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index 027a15e..16076ea 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -110,10 +110,10 @@
     }
 
     static sp<GraphicBuffer> getBuffer() {
-        return new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                                 BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                         BufferUsage::COMPOSER_OVERLAY,
-                                 "test");
+        return sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u,
+                                       BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                               BufferUsage::COMPOSER_OVERLAY,
+                                       "test");
     }
     static uint64_t generateFrameNumber() {
         static uint64_t sFrameNumber = 0;
@@ -332,8 +332,10 @@
 }
 
 TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Different_Processes) {
-    sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener();
-    sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener();
+    sp<TransactionCompletedListener> firstCompletedListener =
+            sp<TransactionCompletedListener>::make();
+    sp<TransactionCompletedListener> secondCompletedListener =
+            sp<TransactionCompletedListener>::make();
 
     CallbackHelper callback1, callback2;
 
@@ -433,8 +435,10 @@
 }
 
 TEST_F(ReleaseBufferCallbackTest, DISABLED_MergeBuffers_Different_Processes) {
-    sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener();
-    sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener();
+    sp<TransactionCompletedListener> firstCompletedListener =
+            sp<TransactionCompletedListener>::make();
+    sp<TransactionCompletedListener> secondCompletedListener =
+            sp<TransactionCompletedListener>::make();
 
     TransactionCompletedListener::setInstance(firstCompletedListener);
 
@@ -465,4 +469,22 @@
     ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
 }
 
+TEST_F(ReleaseBufferCallbackTest, SetBuffer_OverwriteBuffersWithNull) {
+    sp<SurfaceControl> layer = createBufferStateLayer();
+    ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+    sp<GraphicBuffer> firstBuffer = getBuffer();
+    ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+    // Create transaction with a buffer.
+    Transaction transaction;
+    transaction.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
+                          releaseCallback->getCallback());
+
+    // Call setBuffer on the same transaction with a null buffer.
+    transaction.setBuffer(layer, nullptr, std::nullopt, 0, releaseCallback->getCallback());
+
+    ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index f9b3185..d78c8a9 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -112,7 +112,7 @@
     args.captureSecureLayers = true;
     ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(args, mCaptureResults));
     ASSERT_TRUE(mCaptureResults.capturedSecureLayers);
-    ScreenCapture sc(mCaptureResults.buffer);
+    ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers);
     sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
 }
 
@@ -147,7 +147,7 @@
     args.captureSecureLayers = true;
     ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(args, mCaptureResults));
     ASSERT_TRUE(mCaptureResults.capturedSecureLayers);
-    ScreenCapture sc(mCaptureResults.buffer);
+    ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers);
     sc.expectColor(Rect(0, 0, 10, 10), Color::BLUE);
 }
 
@@ -374,7 +374,7 @@
     ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::RED, 32, 32));
     SurfaceComposerClient::Transaction().apply(true);
     ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(args, captureResults));
-    ScreenCapture sc(captureResults.buffer);
+    ScreenCapture sc(captureResults.buffer, captureResults.capturedHdrLayers);
     sc.expectColor(Rect(0, 0, 9, 9), Color::RED);
 }
 
@@ -519,7 +519,7 @@
 
 TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
     LayerCaptureArgs args;
-    args.layerHandle = new BBinder();
+    args.layerHandle = sp<BBinder>::make();
 
     ScreenCaptureResults captureResults;
     // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
@@ -860,6 +860,46 @@
     mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED);
 }
 
+TEST_F(ScreenCaptureTest, CaptureNonHdrLayer) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32,
+                                                ISurfaceComposerClient::eFXSurfaceBufferState,
+                                                mBGSurfaceControl.get()));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLACK, 32, 32));
+    Transaction()
+            .show(layer)
+            .setLayer(layer, INT32_MAX)
+            .setDataspace(layer, ui::Dataspace::V0_SRGB)
+            .apply();
+
+    LayerCaptureArgs captureArgs;
+    captureArgs.layerHandle = layer->getHandle();
+
+    ScreenCapture::captureLayers(&mCapture, captureArgs);
+    mCapture->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    ASSERT_FALSE(mCapture->capturedHdrLayers());
+}
+
+TEST_F(ScreenCaptureTest, CaptureHdrLayer) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32,
+                                                ISurfaceComposerClient::eFXSurfaceBufferState,
+                                                mBGSurfaceControl.get()));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLACK, 32, 32));
+    Transaction()
+            .show(layer)
+            .setLayer(layer, INT32_MAX)
+            .setDataspace(layer, ui::Dataspace::BT2020_ITU_PQ)
+            .apply();
+
+    LayerCaptureArgs captureArgs;
+    captureArgs.layerHandle = layer->getHandle();
+
+    ScreenCapture::captureLayers(&mCapture, captureArgs);
+    mCapture->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    ASSERT_TRUE(mCapture->capturedHdrLayers());
+}
+
 // In the following tests we verify successful skipping of a parent layer,
 // so we use the same verification logic and only change how we mutate
 // the parent layer to verify that various properties are ignored.
diff --git a/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp b/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp
index 4efec77..e43ef95 100644
--- a/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp
+++ b/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
+#include <android/gui/ISurfaceComposer.h>
 #include <gtest/gtest.h>
 #include <gui/DisplayEventReceiver.h>
-#include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 #include <sys/epoll.h>
 #include <algorithm>
@@ -24,12 +24,14 @@
 namespace android {
 namespace {
 using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
+using gui::ISurfaceComposer;
 
 class SetFrameRateOverrideTest : public ::testing::Test {
 protected:
     void SetUp() override {
-        const ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp;
-        const ISurfaceComposer::EventRegistrationFlags eventRegistration = {
+        const ISurfaceComposer::VsyncSource vsyncSource =
+                ISurfaceComposer::VsyncSource::eVsyncSourceApp;
+        const EventRegistrationFlags eventRegistration = {
                 ISurfaceComposer::EventRegistration::frameRateOverride};
 
         mDisplayEventReceiver =
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
index e9b6ba0..03201f7 100644
--- a/services/surfaceflinger/tests/Stress_test.cpp
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -32,7 +32,7 @@
 
 TEST(SurfaceFlingerStress, create_and_destroy) {
     auto do_stress = []() {
-        sp<SurfaceComposerClient> client = new SurfaceComposerClient;
+        sp<SurfaceComposerClient> client = sp<SurfaceComposerClient>::make();
         ASSERT_EQ(NO_ERROR, client->initCheck());
         for (int j = 0; j < 1000; j++) {
             auto surf = client->createSurface(String8("t"), 100, 100,
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 28e8b8c..8dcd013 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -138,7 +138,7 @@
         // Allow SurfaceInterceptor write to /data
         system("setenforce 0");
 
-        mComposerClient = new SurfaceComposerClient;
+        mComposerClient = sp<SurfaceComposerClient>::make();
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
     }
 
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index 60cffb1..ad03ed3 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -53,11 +53,11 @@
                 consumer->setConsumerName(String8("Virtual disp consumer"));
                 consumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight());
 
-                itemConsumer = new BufferItemConsumer(consumer,
-                                                      // Sample usage bits from screenrecord
-                                                      GRALLOC_USAGE_HW_VIDEO_ENCODER |
-                                                              GRALLOC_USAGE_SW_READ_OFTEN);
-                sp<BufferListener> listener = new BufferListener(this);
+                itemConsumer = sp<BufferItemConsumer>::make(consumer,
+                                                            // Sample usage bits from screenrecord
+                                                            GRALLOC_USAGE_HW_VIDEO_ENCODER |
+                                                                    GRALLOC_USAGE_SW_READ_OFTEN);
+                sp<BufferListener> listener = sp<BufferListener>::make(this);
                 itemConsumer->setFrameAvailableListener(listener);
 
                 vDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"),
@@ -79,7 +79,8 @@
 
                 BufferItem item;
                 itemConsumer->acquireBuffer(&item, 0, true);
-                auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
+                constexpr bool kContainsHdr = false;
+                auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer, kContainsHdr);
                 itemConsumer->releaseBuffer(item);
                 SurfaceComposerClient::destroyDisplay(vDisplay);
                 return sc;
diff --git a/services/surfaceflinger/tests/VirtualDisplay_test.cpp b/services/surfaceflinger/tests/VirtualDisplay_test.cpp
index 18e0806..f31f582 100644
--- a/services/surfaceflinger/tests/VirtualDisplay_test.cpp
+++ b/services/surfaceflinger/tests/VirtualDisplay_test.cpp
@@ -33,7 +33,7 @@
         consumer->setConsumerName(String8("Virtual disp consumer"));
         consumer->setDefaultBufferSize(100, 100);
 
-        mGLConsumer = new GLConsumer(consumer, GLConsumer::TEXTURE_EXTERNAL, true, false);
+        mGLConsumer = sp<GLConsumer>::make(consumer, GLConsumer::TEXTURE_EXTERNAL, true, false);
     }
 
     sp<IGraphicBufferProducer> mProducer;
@@ -55,7 +55,7 @@
     // add another sync since we are deferring the display destruction
     t.apply(true);
 
-    sp<Surface> surface = new Surface(mProducer);
+    sp<Surface> surface = sp<Surface>::make(mProducer);
     sp<ANativeWindow> window(surface);
 
     ASSERT_EQ(NO_ERROR, native_window_api_connect(window.get(), NATIVE_WINDOW_API_EGL));
diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
index bb52245..53c3c39 100644
--- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp
+++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
@@ -29,8 +29,8 @@
 protected:
     void SetUp() override {
         seteuid(AID_SYSTEM);
-        mClient = new SurfaceComposerClient;
-        mWindowInfosListener = new SyncWindowInfosListener();
+        mClient = sp<SurfaceComposerClient>::make();
+        mWindowInfosListener = sp<SyncWindowInfosListener>::make();
         mClient->addWindowInfosListener(mWindowInfosListener);
     }
 
@@ -77,7 +77,7 @@
 
 TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) {
     std::string name = "Test Layer";
-    sp<IBinder> token = new BBinder();
+    sp<IBinder> token = sp<BBinder>::make();
     WindowInfo windowInfo;
     windowInfo.name = name;
     windowInfo.token = token;
@@ -105,7 +105,7 @@
 
 TEST_F(WindowInfosListenerTest, WindowInfoChanged) {
     std::string name = "Test Layer";
-    sp<IBinder> token = new BBinder();
+    sp<IBinder> token = sp<BBinder>::make();
     WindowInfo windowInfo;
     windowInfo.name = name;
     windowInfo.token = token;
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index b38032d..a5cca35 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -86,7 +86,9 @@
 class DelayedEventGenerator {
 public:
     explicit DelayedEventGenerator(std::function<void()> onTimerExpired)
-          : mOnTimerExpired(onTimerExpired), mThread([this]() { loop(); }) {}
+          : mOnTimerExpired(onTimerExpired) {
+        mThread = std::thread([this]() { loop(); });
+    }
 
     ~DelayedEventGenerator() {
         ALOGI("DelayedEventGenerator exiting.");
@@ -894,7 +896,7 @@
 void FakeComposerClient::onSurfaceFlingerStart() {
     mSurfaceComposer = nullptr;
     do {
-        mSurfaceComposer = new android::SurfaceComposerClient;
+        mSurfaceComposer = android::sp<android::SurfaceComposerClient>::make();
         android::status_t initResult = mSurfaceComposer->initCheck();
         if (initResult != android::NO_ERROR) {
             ALOGD("Init result: %d", initResult);
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 67df8b8..1d3401a 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -220,8 +220,8 @@
         mFakeComposerClient = new FakeComposerClient();
         mFakeComposerClient->setMockHal(mMockComposer.get());
 
-        sp<V2_4::hal::ComposerClient> client = new V2_4::hal::ComposerClient(mFakeComposerClient);
-        mFakeService = new FakeComposerService(client);
+        auto client = sp<V2_4::hal::ComposerClient>::make(mFakeComposerClient);
+        mFakeService = sp<FakeComposerService>::make(client);
         ASSERT_EQ(android::OK, mFakeService->registerAsService("mock"));
 
         android::hardware::ProcessState::self()->startThreadPool();
@@ -242,12 +242,13 @@
         // Fake composer wants to enable VSync injection
         mFakeComposerClient->onSurfaceFlingerStart();
 
-        mComposerClient = new SurfaceComposerClient;
+        mComposerClient = sp<SurfaceComposerClient>::make();
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
 
-        mReceiver.reset(new DisplayEventReceiver(ISurfaceComposer::eVsyncSourceApp,
-                                                 ISurfaceComposer::EventRegistration::modeChanged));
-        mLooper = new Looper(false);
+        mReceiver.reset(
+                new DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp,
+                                         gui::ISurfaceComposer::EventRegistration::modeChanged));
+        mLooper = sp<Looper>::make(false);
         mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this);
     }
 
@@ -1142,8 +1143,8 @@
         // TODO: See TODO comment at DisplayTest::SetUp for background on
         // the lifetime of the FakeComposerClient.
         sFakeComposer = new FakeComposerClient;
-        sp<V2_4::hal::ComposerClient> client = new V2_4::hal::ComposerClient(sFakeComposer);
-        sp<V2_1::IComposer> fakeService = new FakeComposerService(client);
+        auto client = sp<V2_4::hal::ComposerClient>::make(sFakeComposer);
+        sp<V2_1::IComposer> fakeService = sp<FakeComposerService>::make(client);
         (void)fakeService->registerAsService("mock");
 
         android::hardware::ProcessState::self()->startThreadPool();
@@ -1166,7 +1167,7 @@
 
     void SetUp() override {
         ALOGI("TransactionTest::SetUp");
-        mComposerClient = new SurfaceComposerClient;
+        mComposerClient = sp<SurfaceComposerClient>::make();
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
 
         ALOGI("TransactionTest::SetUp - display");
diff --git a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp
index ac4354c..0e214af 100644
--- a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp
+++ b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp
@@ -83,6 +83,37 @@
 
 std::vector<std::filesystem::path> TransactionTraceTestSuite::sTransactionTraces{};
 
+struct LayerInfo {
+    int id;
+    std::string name;
+    int parent;
+    int z;
+    uint64_t curr_frame;
+    float x;
+    float y;
+};
+
+bool operator==(const LayerInfo& lh, const LayerInfo& rh) {
+    return std::make_tuple(lh.id, lh.name, lh.parent, lh.z, lh.curr_frame) ==
+            std::make_tuple(rh.id, rh.name, rh.parent, rh.z, rh.curr_frame);
+}
+
+bool compareById(const LayerInfo& a, const LayerInfo& b) {
+    return a.id < b.id;
+}
+
+inline void PrintTo(const LayerInfo& info, ::std::ostream* os) {
+    *os << "Layer [" << info.id << "] name=" << info.name << " parent=" << info.parent
+        << " z=" << info.z << " curr_frame=" << info.curr_frame << " x=" << info.x
+        << " y=" << info.y;
+}
+
+struct find_id : std::unary_function<LayerInfo, bool> {
+    int id;
+    find_id(int id) : id(id) {}
+    bool operator()(LayerInfo const& m) const { return m.id == id; }
+};
+
 TEST_P(TransactionTraceTestSuite, validateEndState) {
     ASSERT_GT(mActualLayersTraceProto.entry_size(), 0);
     ASSERT_GT(mExpectedLayersTraceProto.entry_size(), 0);
@@ -92,19 +123,64 @@
     auto actualLastEntry = mActualLayersTraceProto.entry(mActualLayersTraceProto.entry_size() - 1);
 
     EXPECT_EQ(expectedLastEntry.layers().layers_size(), actualLastEntry.layers().layers_size());
-    for (int i = 0;
-         i < expectedLastEntry.layers().layers_size() && i < actualLastEntry.layers().layers_size();
-         i++) {
-        auto expectedLayer = expectedLastEntry.layers().layers(i);
-        auto actualLayer = actualLastEntry.layers().layers(i);
-        EXPECT_EQ(expectedLayer.id(), actualLayer.id());
-        EXPECT_EQ(expectedLayer.name(), actualLayer.name());
-        EXPECT_EQ(expectedLayer.parent(), actualLayer.parent());
-        EXPECT_EQ(expectedLayer.z(), actualLayer.z());
-        EXPECT_EQ(expectedLayer.curr_frame(), actualLayer.curr_frame());
-        ALOGV("Validating %s[%d] parent=%d z=%d frame=%" PRIu64, expectedLayer.name().c_str(),
-              expectedLayer.id(), expectedLayer.parent(), expectedLayer.z(),
-              expectedLayer.curr_frame());
+
+    std::vector<LayerInfo> expectedLayers;
+    expectedLayers.reserve(static_cast<size_t>(expectedLastEntry.layers().layers_size()));
+    for (int i = 0; i < expectedLastEntry.layers().layers_size(); i++) {
+        auto layer = expectedLastEntry.layers().layers(i);
+        expectedLayers.push_back({layer.id(), layer.name(), layer.parent(), layer.z(),
+                                  layer.curr_frame(),
+                                  layer.has_position() ? layer.position().x() : -1,
+                                  layer.has_position() ? layer.position().y() : -1});
+    }
+    std::sort(expectedLayers.begin(), expectedLayers.end(), compareById);
+
+    std::vector<LayerInfo> actualLayers;
+    actualLayers.reserve(static_cast<size_t>(actualLastEntry.layers().layers_size()));
+    for (int i = 0; i < actualLastEntry.layers().layers_size(); i++) {
+        auto layer = actualLastEntry.layers().layers(i);
+        actualLayers.push_back({layer.id(), layer.name(), layer.parent(), layer.z(),
+                                layer.curr_frame(),
+                                layer.has_position() ? layer.position().x() : -1,
+                                layer.has_position() ? layer.position().y() : -1});
+    }
+    std::sort(actualLayers.begin(), actualLayers.end(), compareById);
+
+    size_t i = 0;
+    for (; i < actualLayers.size() && i < expectedLayers.size(); i++) {
+        auto it = std::find_if(actualLayers.begin(), actualLayers.end(),
+                               find_id(expectedLayers[i].id));
+        EXPECT_NE(it, actualLayers.end());
+        EXPECT_EQ(expectedLayers[i], *it);
+        ALOGV("Validating %s[%d] parent=%d z=%d frame=%" PRIu64, expectedLayers[i].name.c_str(),
+              expectedLayers[i].id, expectedLayers[i].parent, expectedLayers[i].z,
+              expectedLayers[i].curr_frame);
+    }
+
+    EXPECT_EQ(expectedLayers.size(), actualLayers.size());
+
+    if (i < actualLayers.size()) {
+        for (size_t j = 0; j < actualLayers.size(); j++) {
+            if (std::find_if(expectedLayers.begin(), expectedLayers.end(),
+                             find_id(actualLayers[j].id)) == expectedLayers.end()) {
+                ALOGD("actualLayers [%d]:%s parent=%d z=%d frame=%" PRIu64, actualLayers[j].id,
+                      actualLayers[j].name.c_str(), actualLayers[j].parent, actualLayers[j].z,
+                      actualLayers[j].curr_frame);
+            }
+        }
+        FAIL();
+    }
+
+    if (i < expectedLayers.size()) {
+        for (size_t j = 0; j < expectedLayers.size(); j++) {
+            if (std::find_if(actualLayers.begin(), actualLayers.end(),
+                             find_id(expectedLayers[j].id)) == actualLayers.end()) {
+                ALOGD("expectedLayers [%d]:%s parent=%d z=%d frame=%" PRIu64, expectedLayers[j].id,
+                      expectedLayers[j].name.c_str(), expectedLayers[j].parent, expectedLayers[j].z,
+                      expectedLayers[j].curr_frame);
+            }
+        }
+        FAIL();
     }
 }
 
diff --git a/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope b/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope
new file mode 100644
index 0000000..16a91ee
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope
Binary files differ
diff --git a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope
new file mode 100644
index 0000000..cd62ab8
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope
Binary files differ
diff --git a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
index 9ab35d7..69d30c4 100644
--- a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
+++ b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
@@ -52,13 +52,18 @@
     void verifyAndClearExpectations();
     void sendActualWorkDurationGroup(std::vector<WorkDuration> durations,
                                      std::chrono::nanoseconds sleepBeforeLastSend);
+    std::chrono::nanoseconds mAllowedDeviation;
+    std::chrono::nanoseconds mStaleTimeout;
 };
 
 void AidlPowerHalWrapperTest::SetUp() {
-    mMockHal = new NiceMock<MockIPower>();
-    mMockSession = new NiceMock<MockIPowerHintSession>();
+    mMockHal = sp<NiceMock<MockIPower>>::make();
+    mMockSession = sp<NiceMock<MockIPowerHintSession>>::make();
     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/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp
index 6f85498..9082a22 100644
--- a/services/surfaceflinger/tests/unittests/CachingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CachingTest.cpp
@@ -26,15 +26,17 @@
 
 class SlotGenerationTest : public testing::Test {
 protected:
-    sp<BufferStateLayer::HwcSlotGenerator> mHwcSlotGenerator =
-            sp<BufferStateLayer::HwcSlotGenerator>::make();
-    sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
-    sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
-    sp<GraphicBuffer> mBuffer3{new GraphicBuffer(10, 10, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+    sp<HwcSlotGenerator> mHwcSlotGenerator = sp<HwcSlotGenerator>::make();
+    sp<GraphicBuffer> mBuffer1 =
+            sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
+    sp<GraphicBuffer> mBuffer2 =
+            sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
+    sp<GraphicBuffer> mBuffer3 =
+            sp<GraphicBuffer>::make(10u, 10u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
 };
 
 TEST_F(SlotGenerationTest, getHwcCacheSlot_Invalid) {
-    sp<IBinder> binder = new BBinder();
+    sp<IBinder> binder = sp<BBinder>::make();
     // test getting invalid client_cache_id
     client_cache_t id;
     int slot = mHwcSlotGenerator->getHwcCacheSlot(id);
@@ -42,7 +44,7 @@
 }
 
 TEST_F(SlotGenerationTest, getHwcCacheSlot_Basic) {
-    sp<IBinder> binder = new BBinder();
+    sp<IBinder> binder = sp<BBinder>::make();
     client_cache_t id;
     id.token = binder;
     id.id = 0;
@@ -63,7 +65,7 @@
 }
 
 TEST_F(SlotGenerationTest, getHwcCacheSlot_Reuse) {
-    sp<IBinder> binder = new BBinder();
+    sp<IBinder> binder = sp<BBinder>::make();
     std::vector<client_cache_t> ids;
     uint32_t cacheId = 0;
     // fill up cache
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index c541b92..2571e3a 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -37,8 +37,6 @@
 #include <system/window.h>
 #include <utils/String8.h>
 
-#include "BufferQueueLayer.h"
-#include "ContainerLayer.h"
 #include "DisplayRenderArea.h"
 #include "EffectLayer.h"
 #include "Layer.h"
@@ -131,13 +129,15 @@
 
         EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
         EXPECT_CALL(*eventThread, createEventConnection(_, _))
-                .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
-                                                           ResyncCallback())));
+                .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+                                                                 mock::EventThread::kCallingUid,
+                                                                 ResyncCallback())));
 
         EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
         EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
-                .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
-                                                           ResyncCallback())));
+                .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+                                                                 mock::EventThread::kCallingUid,
+                                                                 ResyncCallback())));
 
         auto vsyncController = std::make_unique<mock::VsyncController>();
         auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
@@ -179,11 +179,11 @@
     sp<DisplayDevice> mDisplay;
     sp<DisplayDevice> mExternalDisplay;
     sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
-            new compositionengine::mock::DisplaySurface();
-    mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
+            sp<compositionengine::mock::DisplaySurface>::make();
+    sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make();
     std::vector<sp<Layer>> mAuxiliaryLayers;
 
-    sp<GraphicBuffer> mBuffer = new GraphicBuffer();
+    sp<GraphicBuffer> mBuffer = sp<GraphicBuffer>::make();
     ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer();
 
     Hwc2::mock::Composer* mComposer = nullptr;
@@ -245,15 +245,14 @@
                                                                       HAL_PIXEL_FORMAT_RGBA_8888, 1,
                                                                       usage);
 
-    auto result = mFlinger.renderScreenImpl(*renderArea, traverseLayers, mCaptureScreenBuffer,
+    auto future = mFlinger.renderScreenImpl(*renderArea, traverseLayers, mCaptureScreenBuffer,
                                             forSystem, regionSampling);
-    EXPECT_TRUE(result.valid());
+    ASSERT_TRUE(future.valid());
+    const auto fenceResult = future.get();
 
-    auto& [status, drawFence] = result.get();
-
-    EXPECT_EQ(NO_ERROR, status);
-    if (drawFence.ok()) {
-        sync_wait(drawFence.get(), -1);
+    EXPECT_EQ(NO_ERROR, fenceStatus(fenceResult));
+    if (fenceResult.ok()) {
+        fenceResult.value()->waitForever(LOG_TAG);
     }
 
     LayerCase::cleanup(this);
@@ -318,7 +317,7 @@
                                  .setSecure(Derived::IS_SECURE)
                                  .setPowerMode(Derived::INIT_POWER_MODE)
                                  .inject();
-        Mock::VerifyAndClear(test->mNativeWindow);
+        Mock::VerifyAndClear(test->mNativeWindow.get());
         test->mDisplay->setLayerStack(LAYER_STACK);
     }
 
@@ -493,65 +492,31 @@
     static constexpr IComposerClient::BlendMode BLENDMODE =
             IComposerClient::BlendMode::PREMULTIPLIED;
 
-    static void enqueueBuffer(CompositionTest*, sp<BufferQueueLayer> layer) {
-        auto producer = layer->getProducer();
-
-        IGraphicBufferProducer::QueueBufferOutput qbo;
-        status_t result = producer->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &qbo);
-        if (result != NO_ERROR) {
-            ALOGE("Failed to connect() (%d)", result);
-            return;
-        }
-
-        int slot;
-        sp<Fence> fence;
-        result = producer->dequeueBuffer(&slot, &fence, LayerProperties::WIDTH,
-                                         LayerProperties::HEIGHT, LayerProperties::FORMAT,
-                                         LayerProperties::USAGE, nullptr, nullptr);
-        if (result != IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
-            ALOGE("Failed to dequeueBuffer() (%d)", result);
-            return;
-        }
-
-        sp<GraphicBuffer> buffer;
-        result = producer->requestBuffer(slot, &buffer);
-        if (result != NO_ERROR) {
-            ALOGE("Failed to requestBuffer() (%d)", result);
-            return;
-        }
-
-        IGraphicBufferProducer::QueueBufferInput qbi(systemTime(), false /* isAutoTimestamp */,
-                                                     LayerProperties::DATASPACE,
-                                                     Rect(LayerProperties::WIDTH,
-                                                          LayerProperties::HEIGHT),
-                                                     LayerProperties::SCALING_MODE,
-                                                     LayerProperties::TRANSFORM, Fence::NO_FENCE);
-        result = producer->queueBuffer(slot, qbi, &qbo);
-        if (result != NO_ERROR) {
-            ALOGE("Failed to queueBuffer (%d)", result);
-            return;
-        }
-    }
-
-    static void setupLatchedBuffer(CompositionTest* test, sp<BufferQueueLayer> layer) {
-        // TODO: Eliminate the complexity of actually creating a buffer
-        layer->setSizeForTest(LayerProperties::WIDTH, LayerProperties::HEIGHT);
-        status_t err =
-                layer->setDefaultBufferProperties(LayerProperties::WIDTH, LayerProperties::HEIGHT,
-                                                  LayerProperties::FORMAT);
-        ASSERT_EQ(NO_ERROR, err);
+    static void setupLatchedBuffer(CompositionTest* test, sp<BufferStateLayer> layer) {
         Mock::VerifyAndClear(test->mRenderEngine);
 
-        EXPECT_CALL(*test->mFlinger.scheduler(), scheduleFrame()).Times(1);
-        enqueueBuffer(test, layer);
-        Mock::VerifyAndClearExpectations(test->mFlinger.scheduler());
+        const auto buffer = std::make_shared<
+                renderengine::mock::FakeExternalTexture>(LayerProperties::WIDTH,
+                                                         LayerProperties::HEIGHT,
+                                                         DEFAULT_TEXTURE_ID,
+                                                         LayerProperties::FORMAT,
+                                                         LayerProperties::USAGE |
+                                                                 GraphicBuffer::USAGE_HW_TEXTURE);
+
+        auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
+        layerDrawingState.crop = Rect(0, 0, LayerProperties::HEIGHT, LayerProperties::WIDTH);
+        layerDrawingState.buffer = buffer;
+        layerDrawingState.acquireFence = Fence::NO_FENCE;
+        layerDrawingState.dataspace = ui::Dataspace::UNKNOWN;
+        layer->setSurfaceDamageRegion(
+                Region(Rect(LayerProperties::HEIGHT, LayerProperties::WIDTH)));
 
         bool ignoredRecomputeVisibleRegions;
-        layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, 0);
+        layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
         Mock::VerifyAndClear(test->mRenderEngine);
     }
 
-    static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+    static void setupLayerState(CompositionTest* test, sp<BufferStateLayer> layer) {
         setupLatchedBuffer(test, layer);
     }
 
@@ -665,7 +630,8 @@
                     EXPECT_EQ(false, layer.source.buffer.isY410BT2020);
                     EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha);
                     EXPECT_EQ(false, layer.source.buffer.isOpaque);
-                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.x);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.y);
                     EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
                     EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
                     return resultFuture;
@@ -715,7 +681,8 @@
                     EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
                                     LayerProperties::COLOR[2]),
                               layer.source.solidColor);
-                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.x);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.y);
                     EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
                     EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
                     return resultFuture;
@@ -737,7 +704,7 @@
     using Base = BaseLayerProperties<SidebandLayerProperties>;
     static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE;
 
-    static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+    static void setupLayerState(CompositionTest* test, sp<BufferStateLayer> layer) {
         sp<NativeHandle> stream =
                 NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM),
                                      false);
@@ -793,7 +760,8 @@
                     const renderengine::LayerSettings layer = layerSettings.back();
                     EXPECT_THAT(layer.source.buffer.buffer, IsNull());
                     EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor);
-                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.x);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.y);
                     EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
                     EXPECT_EQ(1.0f, layer.alpha);
                     return resultFuture;
@@ -819,14 +787,14 @@
 struct CursorLayerProperties : public BaseLayerProperties<CursorLayerProperties> {
     using Base = BaseLayerProperties<CursorLayerProperties>;
 
-    static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+    static void setupLayerState(CompositionTest* test, sp<BufferStateLayer> layer) {
         Base::setupLayerState(test, layer);
         test->mFlinger.setLayerPotentialCursor(layer, true);
     }
 };
 
 struct NoLayerVariant {
-    using FlingerLayerType = sp<BufferQueueLayer>;
+    using FlingerLayerType = sp<BufferStateLayer>;
 
     static FlingerLayerType createLayer(CompositionTest*) { return FlingerLayerType(); }
     static void injectLayer(CompositionTest*, FlingerLayerType) {}
@@ -901,7 +869,7 @@
 
     static FlingerLayerType createLayer(CompositionTest* test) {
         FlingerLayerType layer = Base::template createLayerWithFactory<EffectLayer>(test, [test]() {
-            return new EffectLayer(
+            return sp<EffectLayer>::make(
                     LayerCreationArgs(test->mFlinger.flinger(), sp<Client>(), "test-layer",
                                       LayerProperties::LAYER_FLAGS, LayerMetadata()));
         });
@@ -933,17 +901,17 @@
 template <typename LayerProperties>
 struct BufferLayerVariant : public BaseLayerVariant<LayerProperties> {
     using Base = BaseLayerVariant<LayerProperties>;
-    using FlingerLayerType = sp<BufferQueueLayer>;
+    using FlingerLayerType = sp<BufferStateLayer>;
 
     static FlingerLayerType createLayer(CompositionTest* test) {
         test->mFlinger.mutableTexturePool().push_back(DEFAULT_TEXTURE_ID);
 
         FlingerLayerType layer =
-                Base::template createLayerWithFactory<BufferQueueLayer>(test, [test]() {
+                Base::template createLayerWithFactory<BufferStateLayer>(test, [test]() {
                     LayerCreationArgs args(test->mFlinger.flinger(), sp<Client>(), "test-layer",
                                            LayerProperties::LAYER_FLAGS, LayerMetadata());
                     args.textureName = test->mFlinger.mutableTexturePool().back();
-                    return new BufferQueueLayer(args);
+                    return sp<BufferStateLayer>::make(args);
                 });
 
         LayerProperties::setupLayerState(test, layer);
@@ -985,12 +953,12 @@
 template <typename LayerProperties>
 struct ContainerLayerVariant : public BaseLayerVariant<LayerProperties> {
     using Base = BaseLayerVariant<LayerProperties>;
-    using FlingerLayerType = sp<ContainerLayer>;
+    using FlingerLayerType = sp<EffectLayer>;
 
     static FlingerLayerType createLayer(CompositionTest* test) {
         LayerCreationArgs args(test->mFlinger.flinger(), sp<Client>(), "test-container-layer",
                                LayerProperties::LAYER_FLAGS, LayerMetadata());
-        FlingerLayerType layer = new ContainerLayer(args);
+        FlingerLayerType layer = sp<EffectLayer>::make(args);
         Base::template initLayerDrawingStateAndComputeBounds(test, layer);
         return layer;
     }
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index f04221c..044c112 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -66,13 +66,15 @@
 void DisplayTransactionTest::injectMockScheduler() {
     EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*mEventThread, createEventConnection(_, _))
-            .WillOnce(Return(
-                    new EventThreadConnection(mEventThread, /*callingUid=*/0, ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(mEventThread,
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*mSFEventThread, createEventConnection(_, _))
-            .WillOnce(Return(
-                    new EventThreadConnection(mSFEventThread, /*callingUid=*/0, ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(mSFEventThread,
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     mFlinger.setupScheduler(std::unique_ptr<scheduler::VsyncController>(mVsyncController),
                             std::unique_ptr<scheduler::VSyncTracker>(mVSyncTracker),
@@ -100,8 +102,8 @@
     // This setup is only expected once per test.
     ASSERT_TRUE(mConsumer == nullptr && mProducer == nullptr);
 
-    mConsumer = new mock::GraphicBufferConsumer();
-    mProducer = new mock::GraphicBufferProducer();
+    mConsumer = sp<mock::GraphicBufferConsumer>::make();
+    mProducer = sp<mock::GraphicBufferProducer>::make();
 
     mFlinger.setCreateBufferQueueFunction([this](auto outProducer, auto outConsumer, bool) {
         *outProducer = mProducer;
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index f5235ce..0c071d4 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -111,8 +111,8 @@
     // Test instances
 
     TestableSurfaceFlinger mFlinger;
-    sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
-    sp<GraphicBuffer> mBuffer = new GraphicBuffer();
+    sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make();
+    sp<GraphicBuffer> mBuffer = sp<GraphicBuffer>::make();
     Hwc2::mock::PowerAdvisor mPowerAdvisor;
 
     // These mocks are created by the test, but are destroyed by SurfaceFlinger
@@ -120,7 +120,7 @@
     // to keep a reference to them for use in setting up call expectations.
     renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
     Hwc2::mock::Composer* mComposer = nullptr;
-    sp<mock::SurfaceInterceptor> mSurfaceInterceptor = new mock::SurfaceInterceptor;
+    sp<mock::SurfaceInterceptor> mSurfaceInterceptor = sp<mock::SurfaceInterceptor>::make();
 
     mock::VsyncController* mVsyncController = new mock::VsyncController;
     mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker;
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index c033af8..978afc5 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -72,7 +72,7 @@
     public:
         MockEventThreadConnection(impl::EventThread* eventThread, uid_t callingUid,
                                   ResyncCallback&& resyncCallback,
-                                  ISurfaceComposer::EventRegistrationFlags eventRegistration)
+                                  EventRegistrationFlags eventRegistration)
               : EventThreadConnection(eventThread, callingUid, std::move(resyncCallback),
                                       eventRegistration) {}
         MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
@@ -85,10 +85,9 @@
     ~EventThreadTest() override;
 
     void createThread(std::unique_ptr<VSyncSource>);
-    sp<MockEventThreadConnection> createConnection(
-            ConnectionEventRecorder& recorder,
-            ISurfaceComposer::EventRegistrationFlags eventRegistration = {},
-            uid_t ownerUid = mConnectionUid);
+    sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder,
+                                                   EventRegistrationFlags eventRegistration = {},
+                                                   uid_t ownerUid = mConnectionUid);
 
     void expectVSyncSetEnabledCallReceived(bool expectedState);
     void expectVSyncSetDurationCallReceived(std::chrono::nanoseconds expectedDuration,
@@ -149,11 +148,12 @@
             .WillRepeatedly(Invoke(mVSyncSetDurationCallRecorder.getInvocable()));
 
     createThread(std::move(vsyncSource));
-    mConnection = createConnection(mConnectionEventCallRecorder,
-                                   ISurfaceComposer::EventRegistration::modeChanged |
-                                           ISurfaceComposer::EventRegistration::frameRateOverride);
+    mConnection =
+            createConnection(mConnectionEventCallRecorder,
+                             gui::ISurfaceComposer::EventRegistration::modeChanged |
+                                     gui::ISurfaceComposer::EventRegistration::frameRateOverride);
     mThrottledConnection = createConnection(mThrottledConnectionEventCallRecorder,
-                                            ISurfaceComposer::EventRegistration::modeChanged,
+                                            gui::ISurfaceComposer::EventRegistration::modeChanged,
                                             mThrottledConnectionUid);
 
     // A display must be connected for VSYNC events to be delivered.
@@ -190,11 +190,12 @@
 }
 
 sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
-        ConnectionEventRecorder& recorder,
-        ISurfaceComposer::EventRegistrationFlags eventRegistration, uid_t ownerUid) {
+        ConnectionEventRecorder& recorder, EventRegistrationFlags eventRegistration,
+        uid_t ownerUid) {
     sp<MockEventThreadConnection> connection =
-            new MockEventThreadConnection(mThread.get(), ownerUid,
-                                          mResyncCallRecorder.getInvocable(), eventRegistration);
+            sp<MockEventThreadConnection>::make(mThread.get(), ownerUid,
+                                                mResyncCallRecorder.getInvocable(),
+                                                eventRegistration);
     EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable()));
     return connection;
 }
diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
index 9cac7c1..0b4e196 100644
--- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
@@ -24,7 +24,6 @@
 #include <gtest/gtest.h>
 #include <gui/LayerMetadata.h>
 
-#include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
 #include "EffectLayer.h"
 #include "FpsReporter.h"
@@ -96,8 +95,8 @@
 
     sp<TestableFpsListener> mFpsListener;
     fake::FakeClock* mClock = new fake::FakeClock();
-    sp<FpsReporter> mFpsReporter =
-            new FpsReporter(mFrameTimeline, *(mFlinger.flinger()), std::unique_ptr<Clock>(mClock));
+    sp<FpsReporter> mFpsReporter = sp<FpsReporter>::make(mFrameTimeline, *(mFlinger.flinger()),
+                                                         std::unique_ptr<Clock>(mClock));
 };
 
 FpsReporterTest::FpsReporterTest() {
@@ -108,7 +107,7 @@
     setupScheduler();
     mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
 
-    mFpsListener = new TestableFpsListener();
+    mFpsListener = sp<TestableFpsListener>::make();
 }
 
 FpsReporterTest::~FpsReporterTest() {
@@ -120,7 +119,7 @@
 sp<BufferStateLayer> FpsReporterTest::createBufferStateLayer(LayerMetadata metadata = {}) {
     sp<Client> client;
     LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, metadata);
-    return new BufferStateLayer(args);
+    return sp<BufferStateLayer>::make(args);
 }
 
 void FpsReporterTest::setupScheduler() {
@@ -129,13 +128,15 @@
 
     EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*eventThread, createEventConnection(_, _))
-            .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
-                                                       ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
-            .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
-                                                       ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     auto vsyncController = std::make_unique<mock::VsyncController>();
     auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index bc379f2..874fa7c 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -1680,7 +1680,7 @@
     EXPECT_EQ(displayFrame0->getActuals().presentTime, 52);
     EXPECT_EQ(displayFrame0->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
     EXPECT_EQ(displayFrame0->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
-    EXPECT_EQ(displayFrame0->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
+    EXPECT_EQ(displayFrame0->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed);
 
     // case 3 - cpu time = 86 - 82 = 4, vsync period = 30
     mFrameTimeline->setSfWakeUp(sfToken3, 106, Fps::fromPeriodNsecs(30));
@@ -2184,6 +2184,50 @@
     EXPECT_EQ(presentedSurfaceFrame2.getJankType(), JankType::BufferStuffing);
 }
 
+TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent_GpuAndCpuMiss) {
+    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    auto gpuFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
+    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+
+    // Case 1: cpu time = 33 - 12 = 21, vsync period = 11
+    mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
+    mFrameTimeline->setSfPresent(33, presentFence1, gpuFence1);
+    auto displayFrame = getDisplayFrame(0);
+    gpuFence1->signalForTest(36);
+    presentFence1->signalForTest(52);
+
+    // Fences haven't been flushed yet, so it should be 0
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 0);
+
+    addEmptyDisplayFrame();
+    displayFrame = getDisplayFrame(0);
+
+    // Fences have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame->getActuals().presentTime, 52);
+    EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+    EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed);
+
+    // Case 2: No GPU fence so it will not use GPU composition.
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(30));
+    mFrameTimeline->setSfPresent(66, presentFence2);
+    auto displayFrame2 = getDisplayFrame(2); // 2 because of previous empty frame
+    presentFence2->signalForTest(90);
+
+    // Fences for the frame haven't been flushed yet, so it should be 0
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
+
+    addEmptyDisplayFrame();
+
+    // Fences have flushed, so the present timestamps should be updated
+    EXPECT_EQ(displayFrame2->getActuals().presentTime, 90);
+    EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+    EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+    EXPECT_EQ(displayFrame2->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
+}
+
 TEST_F(FrameTimelineTest, computeFps_noLayerIds_returnsZero) {
     EXPECT_EQ(mFrameTimeline->computeFps({}), 0.0f);
 }
@@ -2342,4 +2386,38 @@
     EXPECT_EQ(mFrameTimeline->computeFps({sLayerIdOne}), 5.0f);
 }
 
+TEST_F(FrameTimelineTest, getMinTime) {
+    // Use SurfaceFrame::getBaseTime to test the getMinTime.
+    FrameTimelineInfo ftInfo;
+
+    // Valid prediction state test.
+    ftInfo.vsyncId = 0L;
+    mTokenManager->generateTokenForPredictions({10});
+    auto surfaceFrame =
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
+    ASSERT_EQ(surfaceFrame->getBaseTime(), 10);
+
+    // Test prediction state which is not valid.
+    ftInfo.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID;
+    surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                              sLayerNameOne, sLayerNameOne,
+                                                              /*isBuffer*/ true, sGameMode);
+    // Start time test.
+    surfaceFrame->setActualStartTime(200);
+    ASSERT_EQ(surfaceFrame->getBaseTime(), 200);
+
+    // End time test.
+    surfaceFrame->setAcquireFenceTime(100);
+    ASSERT_EQ(surfaceFrame->getBaseTime(), 100);
+
+    // Present time test.
+    auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame);
+    presentFence->signalForTest(std::chrono::nanoseconds(50ns).count());
+    mFrameTimeline->setSfPresent(50, presentFence);
+    ASSERT_EQ(surfaceFrame->getBaseTime(), 50);
+}
 } // namespace android::frametimeline
diff --git a/services/surfaceflinger/tests/unittests/GameModeTest.cpp b/services/surfaceflinger/tests/unittests/GameModeTest.cpp
index b79909a..cd857c3 100644
--- a/services/surfaceflinger/tests/unittests/GameModeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp
@@ -57,7 +57,7 @@
         sp<Client> client;
         LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0,
                                LayerMetadata());
-        return new BufferStateLayer(args);
+        return sp<BufferStateLayer>::make(args);
     }
 
     void setupScheduler() {
@@ -66,13 +66,15 @@
 
         EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
         EXPECT_CALL(*eventThread, createEventConnection(_, _))
-                .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
-                                                           ResyncCallback())));
+                .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+                                                                 mock::EventThread::kCallingUid,
+                                                                 ResyncCallback())));
 
         EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
         EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
-                .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
-                                                           ResyncCallback())));
+                .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+                                                                 mock::EventThread::kCallingUid,
+                                                                 ResyncCallback())));
 
         auto vsyncController = std::make_unique<mock::VsyncController>();
         auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 5241604..9d8e0a2 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -59,27 +59,62 @@
 using ::testing::SetArgPointee;
 using ::testing::StrictMock;
 
-TEST(HWComposerTest, isHeadless) {
-    Hwc2::mock::Composer* mHal = new StrictMock<Hwc2::mock::Composer>();
-    impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
-    ASSERT_TRUE(hwc.isHeadless());
+struct HWComposerTest : testing::Test {
+    using HalError = hardware::graphics::composer::V2_1::Error;
 
-    const hal::HWDisplayId hwcId = 1;
+    Hwc2::mock::Composer* const mHal = new StrictMock<Hwc2::mock::Composer>();
+    impl::HWComposer mHwc{std::unique_ptr<Hwc2::Composer>(mHal)};
 
-    EXPECT_CALL(*mHal, getDisplayIdentificationData(_, _, _))
-            .WillOnce(DoAll(SetArgPointee<2>(getExternalEdid()),
-                            Return(hardware::graphics::composer::V2_1::Error::NONE)));
+    void expectHotplugConnect(hal::HWDisplayId hwcDisplayId) {
+        constexpr uint8_t kPort = 255;
+        EXPECT_CALL(*mHal, getDisplayIdentificationData(hwcDisplayId, _, _))
+                .WillOnce(DoAll(SetArgPointee<1>(kPort),
+                                SetArgPointee<2>(getExternalEdid()), Return(HalError::NONE)));
 
-    EXPECT_CALL(*mHal, setVsyncEnabled(_, _));
-    EXPECT_CALL(*mHal, setClientTargetSlotCount(_));
+        EXPECT_CALL(*mHal, setClientTargetSlotCount(_));
+        EXPECT_CALL(*mHal, setVsyncEnabled(hwcDisplayId, Hwc2::IComposerClient::Vsync::DISABLE));
+    }
+};
 
-    auto info = hwc.onHotplug(hwcId, hal::Connection::CONNECTED);
+TEST_F(HWComposerTest, isHeadless) {
+    ASSERT_TRUE(mHwc.isHeadless());
+
+    constexpr hal::HWDisplayId kHwcDisplayId = 1;
+    expectHotplugConnect(kHwcDisplayId);
+
+    const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED);
     ASSERT_TRUE(info);
-    auto displayId = info->id;
-    ASSERT_FALSE(hwc.isHeadless());
 
-    hwc.disconnectDisplay(displayId);
-    ASSERT_TRUE(hwc.isHeadless());
+    ASSERT_FALSE(mHwc.isHeadless());
+
+    mHwc.disconnectDisplay(info->id);
+    ASSERT_TRUE(mHwc.isHeadless());
+}
+
+TEST_F(HWComposerTest, getActiveMode) {
+    // Unknown display.
+    EXPECT_EQ(mHwc.getActiveMode(PhysicalDisplayId::fromPort(0)), std::nullopt);
+
+    constexpr hal::HWDisplayId kHwcDisplayId = 2;
+    expectHotplugConnect(kHwcDisplayId);
+
+    const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED);
+    ASSERT_TRUE(info);
+
+    {
+        // Display is known to SF but not HWC, e.g. the hotplug disconnect is pending.
+        EXPECT_CALL(*mHal, getActiveConfig(kHwcDisplayId, _))
+                .WillOnce(Return(HalError::BAD_DISPLAY));
+
+        EXPECT_EQ(mHwc.getActiveMode(info->id), std::nullopt);
+    }
+    {
+        constexpr hal::HWConfigId kConfigId = 42;
+        EXPECT_CALL(*mHal, getActiveConfig(kHwcDisplayId, _))
+                .WillOnce(DoAll(SetArgPointee<1>(kConfigId), Return(HalError::NONE)));
+
+        EXPECT_EQ(mHwc.getActiveMode(info->id), kConfigId);
+    }
 }
 
 struct MockHWC2ComposerCallback final : StrictMock<HWC2::ComposerCallback> {
@@ -93,8 +128,7 @@
     MOCK_METHOD1(onComposerHalVsyncIdle, void(hal::HWDisplayId));
 };
 
-struct HWComposerSetCallbackTest : testing::Test {
-    Hwc2::mock::Composer* mHal = new StrictMock<Hwc2::mock::Composer>();
+struct HWComposerSetCallbackTest : HWComposerTest {
     MockHWC2ComposerCallback mCallback;
 };
 
@@ -113,10 +147,9 @@
                             Return(hardware::graphics::composer::V2_4::Error::NONE)));
     EXPECT_CALL(*mHal, registerCallback(_));
 
-    impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
-    hwc.setCallback(mCallback);
+    mHwc.setCallback(mCallback);
 
-    const auto& supported = hwc.getSupportedLayerGenericMetadata();
+    const auto& supported = mHwc.getSupportedLayerGenericMetadata();
     EXPECT_EQ(2u, supported.size());
     EXPECT_EQ(1u, supported.count(kMetadata1Name));
     EXPECT_EQ(kMetadata1Mandatory, supported.find(kMetadata1Name)->second);
@@ -130,11 +163,10 @@
             .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
     EXPECT_CALL(*mHal, registerCallback(_));
 
-    impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
-    hwc.setCallback(mCallback);
+    mHwc.setCallback(mCallback);
 
-    const auto& supported = hwc.getSupportedLayerGenericMetadata();
-    EXPECT_EQ(0u, supported.size());
+    const auto& supported = mHwc.getSupportedLayerGenericMetadata();
+    EXPECT_TRUE(supported.empty());
 }
 
 struct HWComposerLayerTest : public testing::Test {
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 17511cd..972198c 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -141,6 +141,54 @@
 
 namespace {
 
+TEST_F(LayerHistoryTest, singleLayerNoVoteDefaultCompatibility) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+    EXPECT_CALL(*layer, getDefaultFrameRateCompatibility())
+            .WillOnce(Return(LayerInfo::FrameRateCompatibility::NoVote));
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    nsecs_t time = systemTime();
+
+    // No layers returned if no layers are active.
+    EXPECT_TRUE(summarizeLayerHistory(time).empty());
+    EXPECT_EQ(0, activeLayerCount());
+
+    history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
+    history().setDefaultFrameRateCompatibility(layer.get(), true /* contentDetectionEnabled */);
+
+    EXPECT_TRUE(summarizeLayerHistory(time).empty());
+    EXPECT_EQ(1, activeLayerCount());
+}
+
+TEST_F(LayerHistoryTest, singleLayerMinVoteDefaultCompatibility) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+    EXPECT_CALL(*layer, getDefaultFrameRateCompatibility())
+            .WillOnce(Return(LayerInfo::FrameRateCompatibility::Min));
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    nsecs_t time = systemTime();
+
+    EXPECT_TRUE(summarizeLayerHistory(time).empty());
+    EXPECT_EQ(0, activeLayerCount());
+
+    history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
+    history().setDefaultFrameRateCompatibility(layer.get(), true /* contentDetectionEnabled */);
+
+    auto summary = summarizeLayerHistory(time);
+    ASSERT_EQ(1, summarizeLayerHistory(time).size());
+
+    EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+}
+
 TEST_F(LayerHistoryTest, oneLayer) {
     const auto layer = createLayer();
     EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
diff --git a/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp b/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp
index 5a2c147..b7a8a93 100644
--- a/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp
@@ -29,13 +29,13 @@
     sp<Client> client;
     LayerCreationArgs args(flinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS,
                            LayerMetadata());
-    return new BufferStateLayer(args);
+    return sp<BufferStateLayer>::make(args);
 }
 
 sp<Layer> EffectLayerFactory::createLayer(TestableSurfaceFlinger& flinger) {
     sp<Client> client;
     LayerCreationArgs args(flinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata());
-    return new EffectLayer(args);
+    return sp<EffectLayer>::make(args);
 }
 
 std::string PrintToStringParamName(
@@ -53,13 +53,15 @@
 
     EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*eventThread, createEventConnection(_, _))
-            .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
-                                                       ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
-            .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
-                                                       ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     auto vsyncController = std::make_unique<mock::VsyncController>();
     auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index e0aa0b1..f20b9f9 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -32,8 +32,8 @@
 using CallbackToken = scheduler::VSyncDispatch::CallbackToken;
 
 struct NoOpCompositor final : ICompositor {
-    bool commit(nsecs_t, int64_t, nsecs_t) override { return false; }
-    void composite(nsecs_t, int64_t) override {}
+    bool commit(TimePoint, VsyncId, TimePoint) override { return false; }
+    void composite(TimePoint, VsyncId) override {}
     void sample() override {}
 } gNoOpCompositor;
 
@@ -41,12 +41,15 @@
     struct MockHandler : MessageQueue::Handler {
         using MessageQueue::Handler::Handler;
 
-        MOCK_METHOD(void, dispatchFrame, (int64_t, nsecs_t), (override));
+        MOCK_METHOD(void, dispatchFrame, (VsyncId, TimePoint), (override));
     };
 
     explicit TestableMessageQueue(sp<MockHandler> handler)
           : impl::MessageQueue(gNoOpCompositor, handler), mHandler(std::move(handler)) {}
 
+    // impl::MessageQueue overrides:
+    void onFrameSignal(ICompositor&, VsyncId, TimePoint) override {}
+
 public:
     TestableMessageQueue() : TestableMessageQueue(sp<MockHandler>::make(*this)) {}
 
@@ -71,7 +74,7 @@
 struct MessageQueueTest : testing::Test {
     void SetUp() override {
         EXPECT_CALL(mVSyncDispatch, registerCallback(_, "sf")).WillOnce(Return(mCallbackToken));
-        EXPECT_NO_FATAL_FAILURE(mEventQueue.initVsync(mVSyncDispatch, mTokenManager, mDuration));
+        EXPECT_NO_FATAL_FAILURE(mEventQueue.initVsync(mVSyncDispatch, mTokenManager, kDuration));
         EXPECT_CALL(mVSyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
     }
 
@@ -80,16 +83,15 @@
     TestableMessageQueue mEventQueue;
 
     const CallbackToken mCallbackToken{5};
-    constexpr static auto mDuration = std::chrono::nanoseconds(100ms);
-    constexpr static auto mDifferentDuration = std::chrono::nanoseconds(250ms);
+
+    static constexpr Duration kDuration = 100ms;
+    static constexpr Duration kDifferentDuration = 250ms;
 };
 
 namespace {
-/* ------------------------------------------------------------------------
- * Test cases
- */
+
 TEST_F(MessageQueueTest, commit) {
-    const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
+    const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(),
                                                                  .readyDuration = 0,
                                                                  .earliestVsync = 0};
     EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
@@ -103,7 +105,7 @@
 
 TEST_F(MessageQueueTest, commitTwice) {
     InSequence s;
-    const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
+    const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(),
                                                                  .readyDuration = 0,
                                                                  .earliestVsync = 0};
 
@@ -122,7 +124,7 @@
 
 TEST_F(MessageQueueTest, commitTwiceWithCallback) {
     InSequence s;
-    const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
+    const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(),
                                                                  .readyDuration = 0,
                                                                  .earliestVsync = 0};
 
@@ -132,33 +134,36 @@
     ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
     EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
 
-    const auto startTime = 100;
-    const auto endTime = startTime + mDuration.count();
-    const auto presentTime = 500;
-    const auto vsyncId = 42;
+    constexpr TimePoint kStartTime = TimePoint::fromNs(100);
+    constexpr TimePoint kEndTime = kStartTime + kDuration;
+    constexpr TimePoint kPresentTime = TimePoint::fromNs(500);
+    constexpr VsyncId vsyncId{42};
+
     EXPECT_CALL(mTokenManager,
-                generateTokenForPredictions(
-                        frametimeline::TimelineItem(startTime, endTime, presentTime)))
-            .WillOnce(Return(vsyncId));
-    EXPECT_CALL(*mEventQueue.mHandler, dispatchFrame(vsyncId, presentTime)).Times(1);
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.vsyncCallback(presentTime, startTime, endTime));
+                generateTokenForPredictions(frametimeline::TimelineItem(kStartTime.ns(),
+                                                                        kEndTime.ns(),
+                                                                        kPresentTime.ns())))
+            .WillOnce(Return(vsyncId.value));
+    EXPECT_CALL(*mEventQueue.mHandler, dispatchFrame(vsyncId, kPresentTime)).Times(1);
+    EXPECT_NO_FATAL_FAILURE(
+            mEventQueue.vsyncCallback(kPresentTime.ns(), kStartTime.ns(), kEndTime.ns()));
 
     EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
 
     const auto timingAfterCallback =
-            scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
+            scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(),
                                                      .readyDuration = 0,
-                                                     .earliestVsync = presentTime};
+                                                     .earliestVsync = kPresentTime.ns()};
 
     EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback)).WillOnce(Return(0));
     EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
 }
 
 TEST_F(MessageQueueTest, commitWithDurationChange) {
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.setDuration(mDifferentDuration));
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.setDuration(kDifferentDuration));
 
     const auto timing =
-            scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDifferentDuration.count(),
+            scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDifferentDuration.ns(),
                                                      .readyDuration = 0,
                                                      .earliestVsync = 0};
 
diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index 597e5e7..aafc323 100644
--- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -130,6 +130,40 @@
     EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
 }
 
+// TODO(b/186417847) This test is new and passes locally, but may be flaky
+TEST_F(OneShotTimerTest, DISABLED_resetBackToBackSlowAdvanceTest) {
+    fake::FakeClock* clock = new fake::FakeClock();
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
+                                                           mResetTimerCallback.getInvocable(),
+                                                           mExpiredTimerCallback.getInvocable(),
+                                                           std::unique_ptr<fake::FakeClock>(clock));
+    mIdleTimer->start();
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+
+    mIdleTimer->reset();
+    EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
+    EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+
+    clock->advanceTime(200us);
+    mIdleTimer->reset();
+
+    // Normally we would check that the timer callbacks weren't invoked here
+    // after resetting the timer, but we need to precisely control the timing of
+    // this test, and checking that callbacks weren't invoked requires non-zero
+    // time.
+
+    clock->advanceTime(1500us);
+    EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1100us).has_value());
+    mIdleTimer->reset();
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+
+    mIdleTimer->stop();
+    clock->advanceTime(2ms);
+    // Final quick check that no more callback were observed.
+    EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+    EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
+}
+
 TEST_F(OneShotTimerTest, startNotCalledTest) {
     fake::FakeClock* clock = new fake::FakeClock();
     mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index 1e6e336..6752a39 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -93,17 +93,17 @@
     sp<Client> client;
     LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", LAYER_FLAGS,
                            LayerMetadata());
-    return new BufferStateLayer(args);
+    return sp<BufferStateLayer>::make(args);
 }
 
 sp<EffectLayer> RefreshRateSelectionTest::createEffectLayer() {
     sp<Client> client;
     LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata());
-    return new EffectLayer(args);
+    return sp<EffectLayer>::make(args);
 }
 
 void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) {
-    child->setParent(parent);
+    child->setParent(sp<Layer>::fromExisting(parent));
 }
 
 void RefreshRateSelectionTest::commitTransaction(Layer* layer) {
@@ -117,13 +117,15 @@
 
     EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*eventThread, createEventConnection(_, _))
-            .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
-                                                       ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
-            .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
-                                                       ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     auto vsyncController = std::make_unique<mock::VsyncController>();
     auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index aab2795..53e49eb 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -48,7 +48,8 @@
     class MockEventThreadConnection : public android::EventThreadConnection {
     public:
         explicit MockEventThreadConnection(EventThread* eventThread)
-              : EventThreadConnection(eventThread, /*callingUid=*/0, ResyncCallback()) {}
+              : EventThreadConnection(eventThread, /*callingUid*/ static_cast<uid_t>(0),
+                                      ResyncCallback()) {}
         ~MockEventThreadConnection() = default;
 
         MOCK_METHOD1(stealReceiveChannel, binder::Status(gui::BitTube* outChannel));
@@ -79,7 +80,7 @@
     mEventThread = eventThread.get();
     EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0));
 
-    mEventThreadConnection = new MockEventThreadConnection(mEventThread);
+    mEventThreadConnection = sp<MockEventThreadConnection>::make(mEventThread);
 
     // createConnection call to scheduler makes a createEventConnection call to EventThread. Make
     // sure that call gets executed and returns an EventThread::Connection object.
@@ -159,8 +160,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 +227,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/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index b9a5f36..6ee8174 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -78,11 +78,11 @@
 }
 
 void SetFrameRateTest::addChild(sp<Layer> layer, sp<Layer> child) {
-    layer.get()->addChild(child.get());
+    layer->addChild(child);
 }
 
 void SetFrameRateTest::removeChild(sp<Layer> layer, sp<Layer> child) {
-    layer.get()->removeChild(child.get());
+    layer->removeChild(child);
 }
 
 void SetFrameRateTest::commitTransaction() {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
index c7e61c9..40ef949 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
@@ -65,7 +65,7 @@
     // --------------------------------------------------------------------
     // Preconditions
 
-    sp<BBinder> displayToken = new BBinder();
+    sp<BBinder> displayToken = sp<BBinder>::make();
 
     // --------------------------------------------------------------------
     // Invocation
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 5872a47..b607b88 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -87,13 +87,15 @@
 
     EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*eventThread, createEventConnection(_, _))
-            .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
-                                                       ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
-            .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
-                                                       ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     auto vsyncController = std::make_unique<mock::VsyncController>();
     auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
index 9ac2907..bc9e801 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
@@ -408,12 +408,12 @@
 
     // A virtual display was added to the current state, and it has a
     // surface(producer)
-    sp<BBinder> displayToken = new BBinder();
+    sp<BBinder> displayToken = sp<BBinder>::make();
 
     DisplayDeviceState state;
     state.isSecure = static_cast<bool>(Case::Display::SECURE);
 
-    sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
+    sp<mock::GraphicBufferProducer> surface{sp<mock::GraphicBufferProducer>::make()};
     state.surface = surface;
     mFlinger.mutableCurrentState().displays.add(displayToken, state);
 
@@ -479,7 +479,7 @@
 
     // A virtual display was added to the current state, but it does not have a
     // surface.
-    sp<BBinder> displayToken = new BBinder();
+    sp<BBinder> displayToken = sp<BBinder>::make();
 
     DisplayDeviceState state;
     state.isSecure = static_cast<bool>(Case::Display::SECURE);
@@ -656,9 +656,11 @@
     // Preconditions
 
     // A display is set up
-    auto nativeWindow = new mock::NativeWindow();
-    auto displaySurface = new compositionengine::mock::DisplaySurface();
-    sp<GraphicBuffer> buf = new GraphicBuffer();
+    auto nativeWindow = sp<mock::NativeWindow>::make();
+    auto displaySurface = sp<compositionengine::mock::DisplaySurface>::make();
+    sp<GraphicBuffer> buf =
+
+            sp<GraphicBuffer>::make();
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.setNativeWindow(nativeWindow);
     display.setDisplaySurface(displaySurface);
@@ -701,9 +703,9 @@
     // Preconditions
 
     // A display is set up
-    auto nativeWindow = new mock::NativeWindow();
-    auto displaySurface = new compositionengine::mock::DisplaySurface();
-    sp<GraphicBuffer> buf = new GraphicBuffer();
+    auto nativeWindow = sp<mock::NativeWindow>::make();
+    auto displaySurface = sp<compositionengine::mock::DisplaySurface>::make();
+    sp<GraphicBuffer> buf = sp<GraphicBuffer>::make();
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.setNativeWindow(nativeWindow);
     display.setDisplaySurface(displaySurface);
@@ -750,9 +752,9 @@
     // Preconditions
 
     // A display is set up
-    auto nativeWindow = new mock::NativeWindow();
-    auto displaySurface = new compositionengine::mock::DisplaySurface();
-    sp<GraphicBuffer> buf = new GraphicBuffer();
+    auto nativeWindow = sp<mock::NativeWindow>::make();
+    auto displaySurface = sp<compositionengine::mock::DisplaySurface>::make();
+    sp<GraphicBuffer> buf = sp<GraphicBuffer>::make();
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.setNativeWindow(nativeWindow);
     display.setDisplaySurface(displaySurface);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp
index 0171f1b..5951c98 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp
@@ -95,7 +95,7 @@
 }
 
 TEST_F(GetDisplayNativePrimaries, notInternalDisplayToken) {
-    sp<BBinder> notInternalDisplayToken = new BBinder();
+    sp<BBinder> notInternalDisplayToken = sp<BBinder>::make();
 
     ui::DisplayPrimaries primaries;
     populateDummyDisplayNativePrimaries(primaries);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
index 37cf05e..98249bf 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
@@ -78,19 +78,8 @@
     auto displayDevice = primaryDisplay.mutableDisplayDevice();
     EXPECT_EQ(PowerMode::ON, displayDevice->getPowerMode());
 
-    // The display refresh period should be set in the orientedDisplaySpaceRect tracker.
-    FrameStats stats;
-    mFlinger.getAnimFrameTracker().getStats(&stats);
-    EXPECT_EQ(DEFAULT_VSYNC_PERIOD, stats.refreshPeriodNano);
-
     // The display transaction needed flag should be set.
     EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
-
-    // The compositor timing should be set to default values
-    const auto& compositorTiming = mFlinger.getCompositorTiming();
-    EXPECT_EQ(-DEFAULT_VSYNC_PERIOD, compositorTiming.deadline);
-    EXPECT_EQ(DEFAULT_VSYNC_PERIOD, compositorTiming.interval);
-    EXPECT_EQ(DEFAULT_VSYNC_PERIOD, compositorTiming.presentLatency);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
index 0a157c4..e256d2c 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
@@ -60,8 +60,8 @@
     renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
     sp<DisplayDevice> mDisplay;
     sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
-            new compositionengine::mock::DisplaySurface();
-    mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
+            sp<compositionengine::mock::DisplaySurface>::make();
+    sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make();
     mock::TimeStats* mTimeStats = new mock::TimeStats();
     Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr;
     Hwc2::mock::Composer* mComposer = nullptr;
@@ -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() {
@@ -104,13 +106,15 @@
 
     EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*eventThread, createEventConnection(_, _))
-            .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
-                                                       ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
-            .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
-                                                       ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     auto vsyncController = std::make_unique<mock::VsyncController>();
     auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
@@ -129,26 +133,41 @@
 TEST_F(SurfaceFlingerPowerHintTest, sendDurationsIncludingHwcWaitTime) {
     ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true));
 
-    const std::chrono::nanoseconds mockVsyncPeriod = 15ms;
-    const std::chrono::nanoseconds expectedTargetTime = 14ms;
-    EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(Gt(expectedTargetTime.count()))).Times(1);
-
-    const nsecs_t now = systemTime();
-    const std::chrono::nanoseconds mockHwcRunTime = 20ms;
+    EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(_)).Times(1);
     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(Gt(mockHwcRunTime.count()),
-                                       Gt(now + mockHwcRunTime.count())))
+    EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _)).WillOnce([] {
+        constexpr Duration kMockHwcRunTime = 20ms;
+        std::this_thread::sleep_for(kMockHwcRunTime);
+        return hardware::graphics::composer::V2_1::Error::NONE;
+    });
+    EXPECT_CALL(*mPowerAdvisor, sendActualWorkDuration()).Times(1);
+
+    const TimePoint frameTime = scheduler::SchedulerClock::now();
+    constexpr Period kMockVsyncPeriod = 15ms;
+    mFlinger.commitAndComposite(frameTime, VsyncId{123}, frameTime + kMockVsyncPeriod);
+}
+
+TEST_F(SurfaceFlingerPowerHintTest, inactiveOnDisplayDoze) {
+    ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true));
+
+    mDisplay->setPowerMode(hal::PowerMode::DOZE);
+
+    EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(_)).Times(0);
+    EXPECT_CALL(*mDisplaySurface,
+                prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc))
             .Times(1);
-    static constexpr bool kVsyncId = 123; // arbitrary
-    mFlinger.commitAndComposite(now, kVsyncId, now + mockVsyncPeriod.count());
+    EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _)).WillOnce([] {
+        constexpr Duration kMockHwcRunTime = 20ms;
+        std::this_thread::sleep_for(kMockHwcRunTime);
+        return hardware::graphics::composer::V2_1::Error::NONE;
+    });
+    EXPECT_CALL(*mPowerAdvisor, sendActualWorkDuration()).Times(0);
+
+    const TimePoint frameTime = scheduler::SchedulerClock::now();
+    constexpr Period kMockVsyncPeriod = 15ms;
+    mFlinger.commitAndComposite(frameTime, VsyncId{123}, frameTime + kMockVsyncPeriod);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
index 7d9e22b..9c7f55b 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
@@ -34,7 +34,7 @@
     // Preconditions
 
     // We have an unknown display token not associated with a known display
-    sp<BBinder> displayToken = new BBinder();
+    sp<BBinder> displayToken = sp<BBinder>::make();
 
     // The requested display state references the unknown display.
     DisplayState state;
@@ -95,7 +95,7 @@
     display.inject();
 
     // There is a surface that can be set.
-    sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
+    sp<mock::GraphicBufferProducer> surface = sp<mock::GraphicBufferProducer>::make();
 
     // The current display state has the surface set
     display.mutableCurrentDisplayState().surface = surface;
@@ -132,7 +132,7 @@
     display.inject();
 
     // There is a surface that can be set.
-    sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
+    sp<mock::GraphicBufferProducer> surface = sp<mock::GraphicBufferProducer>::make();
 
     // The current display state does not have a surface
     display.mutableCurrentDisplayState().surface = nullptr;
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 583cf5f..1756368 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -140,7 +140,6 @@
 
     static void verifyPostconditions(DisplayTransactionTest* test) {
         EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
-        EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
     }
 };
 
@@ -155,7 +154,6 @@
 
     static void verifyPostconditions(DisplayTransactionTest* test) {
         EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
-        EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
     }
 };
 
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index a0e078b..6aeb3fe 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -197,10 +197,10 @@
 
 template <typename Case>
 void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() {
-    const sp<BBinder> displayToken = new BBinder();
+    const sp<BBinder> displayToken = sp<BBinder>::make();
     const sp<compositionengine::mock::DisplaySurface> displaySurface =
-            new compositionengine::mock::DisplaySurface();
-    const sp<mock::GraphicBufferProducer> producer = new mock::GraphicBufferProducer();
+            sp<compositionengine::mock::DisplaySurface>::make();
+    const auto producer = sp<mock::GraphicBufferProducer>::make();
 
     // --------------------------------------------------------------------
     // Preconditions
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 4708572..66cdfd7 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -109,8 +109,8 @@
 
 private:
     // ICompositor overrides:
-    bool commit(nsecs_t, int64_t, nsecs_t) override { return false; }
-    void composite(nsecs_t, int64_t) override {}
+    bool commit(TimePoint, VsyncId, TimePoint) override { return false; }
+    void composite(TimePoint, VsyncId) override {}
     void sample() override {}
 };
 
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index f74ffa3..8f87123 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -27,11 +27,10 @@
 #include <compositionengine/impl/Display.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <compositionengine/mock/DisplaySurface.h>
+#include <ftl/fake_guard.h>
 #include <gui/ScreenCaptureResults.h>
 
-#include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
-#include "ContainerLayer.h"
 #include "DisplayDevice.h"
 #include "EffectLayer.h"
 #include "FakeVsyncConfiguration.h"
@@ -85,21 +84,21 @@
     }
 
     sp<SurfaceInterceptor> createSurfaceInterceptor() override {
-        return new android::impl::SurfaceInterceptor();
+        return sp<android::impl::SurfaceInterceptor>::make();
     }
 
     sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
-        return new StartPropertySetThread(timestampPropertyValue);
+        return sp<StartPropertySetThread>::make(timestampPropertyValue);
     }
 
     sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) override {
-        return new DisplayDevice(creationArgs);
+        return sp<DisplayDevice>::make(creationArgs);
     }
 
     sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
                                           uint32_t layerCount, uint64_t usage,
                                           std::string requestorName) override {
-        return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
+        return sp<GraphicBuffer>::make(width, height, format, layerCount, usage, requestorName);
     }
 
     void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
@@ -112,18 +111,6 @@
         mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
     }
 
-    sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>& producer,
-                                                       const sp<SurfaceFlinger>& flinger,
-                                                       const wp<Layer>& layer) override {
-        return new MonitoredProducer(producer, flinger, layer);
-    }
-
-    sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>& consumer,
-                                                      renderengine::RenderEngine& renderEngine,
-                                                      uint32_t textureName, Layer* layer) override {
-        return new BufferLayerConsumer(consumer, renderEngine, textureName, layer);
-    }
-
     std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
             const sp<IGraphicBufferProducer>& producer) override {
         if (!mCreateNativeWindowSurface) return nullptr;
@@ -134,20 +121,12 @@
         return compositionengine::impl::createCompositionEngine();
     }
 
-    sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
-        return nullptr;
-    }
-
     sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs&) override {
         return nullptr;
     }
 
     sp<EffectLayer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; }
 
-    sp<ContainerLayer> createContainerLayer(const LayerCreationArgs&) override {
-        return nullptr;
-    }
-
     std::unique_ptr<FrameTracer> createFrameTracer() override {
         return std::make_unique<mock::FrameTracer>();
     }
@@ -330,29 +309,30 @@
         layer->mDrawingParent = drawingParent;
     }
 
+    void setPowerHintSessionMode(bool early, bool late) {
+        mFlinger->mPowerHintSessionMode = {.late = late, .early = early};
+    }
+
     /* ------------------------------------------------------------------------
      * Forwarding for functions being tested
      */
 
-    nsecs_t commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVSyncTime) {
+    TimePoint commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVSyncTime) {
         mFlinger->commit(frameTime, vsyncId, expectedVSyncTime);
         return frameTime;
     }
 
-    nsecs_t commit(nsecs_t frameTime, int64_t vsyncId) {
-        std::chrono::nanoseconds period = 10ms;
-        return commit(frameTime, vsyncId, frameTime + period.count());
+    TimePoint commit(TimePoint frameTime, VsyncId vsyncId) {
+        return commit(frameTime, vsyncId, frameTime + Period(10ms));
     }
 
-    nsecs_t commit() {
-        const nsecs_t now = systemTime();
-        const nsecs_t expectedVsyncTime = now + 10'000'000;
-        return commit(now, kVsyncId, expectedVsyncTime);
+    TimePoint commit() {
+        const TimePoint frameTime = scheduler::SchedulerClock::now();
+        return commit(frameTime, kVsyncId);
     }
 
-    void commitAndComposite(const nsecs_t frameTime, const int64_t vsyncId,
-                            const nsecs_t expectedVsyncTime) {
-        mFlinger->composite(commit(frameTime, vsyncId, expectedVsyncTime), kVsyncId);
+    void commitAndComposite(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime) {
+        mFlinger->composite(commit(frameTime, vsyncId, expectedVsyncTime), vsyncId);
     }
 
     void commitAndComposite() { mFlinger->composite(commit(), kVsyncId); }
@@ -434,7 +414,7 @@
         return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
     }
 
-    auto& getTransactionQueue() { return mFlinger->mTransactionQueue; }
+    auto& getTransactionQueue() { return mFlinger->mLocklessTransactionQueue; }
     auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
     auto& getTransactionCommittedSignals() { return mFlinger->mTransactionCommittedSignals; }
 
@@ -450,7 +430,9 @@
                                              listenerCallbacks, transactionId);
     }
 
-    auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(0); };
+    auto flushTransactionQueues() {
+        return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues(kVsyncId));
+    }
 
     auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
         return mFlinger->onTransact(code, data, reply, flags);
@@ -494,16 +476,12 @@
      * Read-only access to private data to assert post-conditions.
      */
 
-    const auto& getAnimFrameTracker() const { return mFlinger->mAnimFrameTracker; }
-    const auto& getHasPoweredOff() const { return mFlinger->mHasPoweredOff; }
     const auto& getVisibleRegionsDirty() const { return mFlinger->mVisibleRegionsDirty; }
     auto& getHwComposer() const {
         return static_cast<impl::HWComposer&>(mFlinger->getHwComposer());
     }
     auto& getCompositionEngine() const { return mFlinger->getCompositionEngine(); }
 
-    const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; }
-
     mock::FrameTracer* getFrameTracer() const {
         return static_cast<mock::FrameTracer*>(mFlinger->mFrameTracer.get());
     }
@@ -736,8 +714,8 @@
                                   std::optional<ui::DisplayConnectionType> connectionType,
                                   std::optional<hal::HWDisplayId> hwcDisplayId, bool isPrimary)
               : mFlinger(flinger),
-                mCreationArgs(flinger.mFlinger.get(), flinger.mFlinger->getHwComposer(),
-                              mDisplayToken, display),
+                mCreationArgs(flinger.mFlinger, flinger.mFlinger->getHwComposer(), mDisplayToken,
+                              display),
                 mHwcDisplayId(hwcDisplayId) {
             mCreationArgs.connectionType = connectionType;
             mCreationArgs.isPrimary = isPrimary;
@@ -885,13 +863,13 @@
 
     private:
         TestableSurfaceFlinger& mFlinger;
-        sp<BBinder> mDisplayToken = new BBinder();
+        sp<BBinder> mDisplayToken = sp<BBinder>::make();
         DisplayDeviceCreationArgs mCreationArgs;
         const std::optional<hal::HWDisplayId> mHwcDisplayId;
     };
 
 private:
-    constexpr static int64_t kVsyncId = 123;
+    static constexpr VsyncId kVsyncId{123};
 
     surfaceflinger::test::Factory mFactory;
     sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index ded7531..efb9e0c 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -60,13 +60,15 @@
 
         EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
         EXPECT_CALL(*eventThread, createEventConnection(_, _))
-                .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
-                                                           ResyncCallback())));
+                .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+                                                                 mock::EventThread::kCallingUid,
+                                                                 ResyncCallback())));
 
         EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
         EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
-                .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
-                                                           ResyncCallback())));
+                .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+                                                                 mock::EventThread::kCallingUid,
+                                                                 ResyncCallback())));
 
         EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
         EXPECT_CALL(*mVSyncTracker, currentPeriod())
@@ -107,22 +109,20 @@
         EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime);
     }
 
-    void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows,
-                     int64_t desiredPresentTime, bool isAutoTimestamp,
-                     const FrameTimelineInfo& frameTimelineInfo) {
+    void setupSingle(TransactionInfo& transaction, uint32_t flags, int64_t desiredPresentTime,
+                     bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo) {
         mTransactionNumber++;
         transaction.flags |= flags; // ISurfaceComposer::eSynchronous;
-        transaction.inputWindowCommands.syncInputWindows = syncInputWindows;
         transaction.desiredPresentTime = desiredPresentTime;
         transaction.isAutoTimestamp = isAutoTimestamp;
         transaction.frameTimelineInfo = frameTimelineInfo;
     }
 
-    void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
-        ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
+    void NotPlacedOnTransactionQueue(uint32_t flags) {
+        ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
         EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
         TransactionInfo transaction;
-        setupSingle(transaction, flags, syncInputWindows,
+        setupSingle(transaction, flags,
                     /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
                     FrameTimelineInfo{});
         nsecs_t applicationTime = systemTime();
@@ -133,31 +133,29 @@
                                      transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
                                      transaction.id);
 
-        // If transaction is synchronous or syncs input windows, SF
-        // applyTransactionState should time out (5s) wating for SF to commit
-        // the transaction or to receive a signal that syncInputWindows has
-        // completed.  If this is animation, it should not time out waiting.
+        // If transaction is synchronous, SF applyTransactionState should time out (5s) wating for
+        // SF to commit the transaction. If this is animation, it should not time out waiting.
         nsecs_t returnedTime = systemTime();
-        if (flags & ISurfaceComposer::eSynchronous || syncInputWindows) {
+        if (flags & ISurfaceComposer::eSynchronous) {
             EXPECT_GE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout());
         } else {
             EXPECT_LE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout());
         }
         // Each transaction should have been placed on the transaction queue
-        auto transactionQueue = mFlinger.getTransactionQueue();
-        EXPECT_EQ(1u, transactionQueue.size());
+        auto& transactionQueue = mFlinger.getTransactionQueue();
+        EXPECT_FALSE(transactionQueue.isEmpty());
     }
 
-    void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
-        ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
+    void PlaceOnTransactionQueue(uint32_t flags) {
+        ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
         EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
         // first check will see desired present time has not passed,
         // but afterwards it will look like the desired present time has passed
         nsecs_t time = systemTime();
         TransactionInfo transaction;
-        setupSingle(transaction, flags, syncInputWindows,
-                    /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{});
+        setupSingle(transaction, flags, /*desiredPresentTime*/ time + s2ns(1), false,
+                    FrameTimelineInfo{});
         nsecs_t applicationSentTime = systemTime();
         mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
                                      transaction.displays, transaction.flags,
@@ -167,7 +165,7 @@
                                      transaction.id);
 
         nsecs_t returnedTime = systemTime();
-        if ((flags & ISurfaceComposer::eSynchronous) || syncInputWindows) {
+        if (flags & ISurfaceComposer::eSynchronous) {
             EXPECT_GE(systemTime(),
                       applicationSentTime + mFlinger.getAnimationTransactionTimeout());
         } else {
@@ -175,29 +173,25 @@
                       applicationSentTime + mFlinger.getAnimationTransactionTimeout());
         }
         // This transaction should have been placed on the transaction queue
-        auto transactionQueue = mFlinger.getTransactionQueue();
-        EXPECT_EQ(1u, transactionQueue.size());
+        auto& transactionQueue = mFlinger.getTransactionQueue();
+        EXPECT_FALSE(transactionQueue.isEmpty());
     }
 
-    void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
-        ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
+    void BlockedByPriorTransaction(uint32_t flags) {
+        ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
         nsecs_t time = systemTime();
-        if (!syncInputWindows) {
-            EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(2);
-        } else {
-            EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
-        }
+        EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(2);
+
         // transaction that should go on the pending thread
         TransactionInfo transactionA;
-        setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
-                    /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{});
+        setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ time + s2ns(1), false,
+                    FrameTimelineInfo{});
 
         // transaction that would not have gone on the pending thread if not
         // blocked
         TransactionInfo transactionB;
-        setupSingle(transactionB, flags, syncInputWindows,
-                    /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
-                    FrameTimelineInfo{});
+        setupSingle(transactionB, flags, /*desiredPresentTime*/ systemTime(),
+                    /*isAutoTimestamp*/ true, FrameTimelineInfo{});
 
         nsecs_t applicationSentTime = systemTime();
         mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
@@ -226,8 +220,7 @@
         // if this is an animation, this thread should be blocked for 5s
         // in setTransactionState waiting for transactionA to flush.  Otherwise,
         // the transaction should be placed on the pending queue
-        if (flags & (ISurfaceComposer::eSynchronous) ||
-            syncInputWindows) {
+        if (flags & ISurfaceComposer::eSynchronous) {
             EXPECT_GE(systemTime(),
                       applicationSentTime + mFlinger.getAnimationTransactionTimeout());
         } else {
@@ -248,13 +241,13 @@
     int mTransactionNumber = 0;
 };
 
-TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
-    ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
+TEST_F(TransactionApplicationTest, AddToPendingQueue) {
+    ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
     EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     TransactionInfo transactionA; // transaction to go on pending queue
-    setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
-                /*desiredPresentTime*/ s2ns(1), false, FrameTimelineInfo{});
+    setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ s2ns(1), false,
+                FrameTimelineInfo{});
     mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
                                  transactionA.displays, transactionA.flags, transactionA.applyToken,
                                  transactionA.inputWindowCommands, transactionA.desiredPresentTime,
@@ -262,10 +255,27 @@
                                  mHasListenerCallbacks, mCallbacks, transactionA.id);
 
     auto& transactionQueue = mFlinger.getTransactionQueue();
-    ASSERT_EQ(1u, transactionQueue.size());
+    ASSERT_FALSE(transactionQueue.isEmpty());
 
-    auto& transactionState = transactionQueue.front();
+    auto transactionState = transactionQueue.pop().value();
     checkEqual(transactionA, transactionState);
+}
+
+TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
+    ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
+
+    TransactionInfo transactionA; // transaction to go on pending queue
+    setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ s2ns(1), false,
+                FrameTimelineInfo{});
+    mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
+                                 transactionA.displays, transactionA.flags, transactionA.applyToken,
+                                 transactionA.inputWindowCommands, transactionA.desiredPresentTime,
+                                 transactionA.isAutoTimestamp, transactionA.uncacheBuffer,
+                                 mHasListenerCallbacks, mCallbacks, transactionA.id);
+
+    auto& transactionQueue = mFlinger.getTransactionQueue();
+    ASSERT_FALSE(transactionQueue.isEmpty());
 
     // because flushing uses the cached expected present time, we send an empty
     // transaction here (sending a null applyToken to fake it as from a
@@ -281,35 +291,27 @@
     // passed
     mFlinger.flushTransactionQueues();
 
-    EXPECT_EQ(0u, transactionQueue.size());
+    EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
 }
 
 TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) {
-    NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+    NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous);
 }
 
 TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_SyncInputWindows) {
-    NotPlacedOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true);
+    NotPlacedOnTransactionQueue(/*flags*/ 0);
 }
 
 TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Synchronous) {
-    PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+    PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous);
 }
 
 TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_SyncInputWindows) {
-    PlaceOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true);
+    PlaceOnTransactionQueue(/*flags*/ 0);
 }
 
 TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Synchronous) {
-    BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
-}
-
-TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Animation) {
-    BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
-}
-
-TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_SyncInputWindows) {
-    BlockedByPriorTransaction(/*flags*/ 0, /*syncInputWindows*/ true);
+    BlockedByPriorTransaction(ISurfaceComposer::eSynchronous);
 }
 
 TEST_F(TransactionApplicationTest, FromHandle) {
@@ -323,7 +325,9 @@
     void TearDown() override {
         // Clear all transaction queues to release all transactions we sent
         // in the tests. Otherwise, gmock complains about memory leaks.
-        mFlinger.getTransactionQueue().clear();
+        while (!mFlinger.getTransactionQueue().isEmpty()) {
+            mFlinger.getTransactionQueue().pop();
+        }
         mFlinger.getPendingTransactionQueue().clear();
         mFlinger.getTransactionCommittedSignals().clear();
         mFlinger.commitTransactionsLocked(eTransactionMask);
@@ -359,13 +363,11 @@
                                           const std::vector<ComposerState>& states) {
         TransactionInfo transaction;
         const uint32_t kFlags = ISurfaceComposer::eSynchronous;
-        const bool kSyncInputWindows = false;
         const nsecs_t kDesiredPresentTime = systemTime();
         const bool kIsAutoTimestamp = true;
         const auto kFrameTimelineInfo = FrameTimelineInfo{};
 
-        setupSingle(transaction, kFlags, kSyncInputWindows, kDesiredPresentTime, kIsAutoTimestamp,
-                    kFrameTimelineInfo);
+        setupSingle(transaction, kFlags, kDesiredPresentTime, kIsAutoTimestamp, kFrameTimelineInfo);
         transaction.applyToken = applyToken;
         for (const auto& state : states) {
             transaction.states.push_back(state);
@@ -377,7 +379,7 @@
     void setTransactionStates(const std::vector<TransactionInfo>& transactions,
                               size_t expectedTransactionsApplied,
                               size_t expectedTransactionsPending) {
-        EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
+        EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
         EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
 
         for (const auto& transaction : transactions) {
@@ -389,7 +391,7 @@
                                          mHasListenerCallbacks, mCallbacks, transaction.id);
         }
         mFlinger.flushTransactionQueues();
-        EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
+        EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
         EXPECT_EQ(expectedTransactionsPending, mFlinger.getPendingTransactionQueue().size());
         EXPECT_EQ(expectedTransactionsApplied, mFlinger.getTransactionCommittedSignals().size());
     }
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index 5364630..cd64325 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -60,7 +60,7 @@
         sp<Client> client;
         LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0,
                                LayerMetadata());
-        return new BufferStateLayer(args);
+        return sp<BufferStateLayer>::make(args);
     }
 
     void commitTransaction(Layer* layer) {
@@ -74,13 +74,15 @@
 
         EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
         EXPECT_CALL(*eventThread, createEventConnection(_, _))
-                .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
-                                                           ResyncCallback())));
+                .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+                                                                 mock::EventThread::kCallingUid,
+                                                                 ResyncCallback())));
 
         EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
         EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
-                .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
-                                                           ResyncCallback())));
+                .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+                                                                 mock::EventThread::kCallingUid,
+                                                                 ResyncCallback())));
 
         auto vsyncController = std::make_unique<mock::VsyncController>();
         auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
@@ -101,7 +103,7 @@
     void BLASTTransactionSendsFrameTracerEvents() {
         sp<BufferStateLayer> layer = createBufferStateLayer();
 
-        sp<Fence> fence(new Fence());
+        sp<Fence> fence(sp<Fence>::make());
         int32_t layerId = layer->getSequence();
         uint64_t bufferId = 42;
         uint64_t frameNumber = 5;
@@ -127,7 +129,6 @@
                          dequeueTime, FrameTimelineInfo{});
 
         commitTransaction(layer.get());
-        bool computeVisisbleRegions;
         nsecs_t latchTime = 25;
         EXPECT_CALL(*mFlinger.getFrameTracer(),
                     traceFence(layerId, bufferId, frameNumber, _,
@@ -135,7 +136,7 @@
         EXPECT_CALL(*mFlinger.getFrameTracer(),
                     traceTimestamp(layerId, bufferId, frameNumber, latchTime,
                                    FrameTracer::FrameEvent::LATCH, /*duration*/ 0));
-        layer->updateTexImage(computeVisisbleRegions, latchTime, /*expectedPresentTime*/ 0);
+        layer->updateTexImage(latchTime);
 
         auto glDoneFence = fenceFactory.createFenceTimeForTest(fence);
         auto presentFence = fenceFactory.createFenceTimeForTest(fence);
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index 669fa3a..1f011be 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -27,8 +27,8 @@
 namespace android {
 
 TEST(TransactionProtoParserTest, parse) {
-    const sp<IBinder> layerHandle = new BBinder();
-    const sp<IBinder> displayHandle = new BBinder();
+    const sp<IBinder> layerHandle = sp<BBinder>::make();
+    const sp<IBinder> displayHandle = sp<BBinder>::make();
     TransactionState t1;
     t1.originPid = 1;
     t1.originUid = 2;
@@ -49,7 +49,7 @@
         ComposerState s;
         if (i == 1) {
             layer.parentSurfaceControlForChild =
-                    new SurfaceControl(SurfaceComposerClient::getDefault(), layerHandle, 42);
+                    sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), layerHandle, 42);
         }
         s.state = layer;
         t1.states.add(s);
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index 6d58303..d5823c3 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -60,7 +60,7 @@
         sp<Client> client;
         LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0,
                                LayerMetadata());
-        return new BufferStateLayer(args);
+        return sp<BufferStateLayer>::make(args);
     }
 
     void commitTransaction(Layer* layer) {
@@ -74,13 +74,15 @@
 
         EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
         EXPECT_CALL(*eventThread, createEventConnection(_, _))
-                .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
-                                                           ResyncCallback())));
+                .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+                                                                 mock::EventThread::kCallingUid,
+                                                                 ResyncCallback())));
 
         EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
         EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
-                .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
-                                                           ResyncCallback())));
+                .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+                                                                 mock::EventThread::kCallingUid,
+                                                                 ResyncCallback())));
 
         auto vsyncController = std::make_unique<mock::VsyncController>();
         auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
@@ -115,7 +117,7 @@
 
     void PresentedSurfaceFrameForBufferTransaction() {
         sp<BufferStateLayer> layer = createBufferStateLayer();
-        sp<Fence> fence(new Fence());
+        sp<Fence> fence(sp<Fence>::make());
         auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
         BufferData bufferData;
         bufferData.acquireFence = fence;
@@ -140,8 +142,7 @@
         // Buffers are presented only at latch time.
         EXPECT_EQ(PresentState::Unknown, surfaceFrame->getPresentState());
 
-        bool computeVisisbleRegions;
-        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+        layer->updateTexImage(15);
 
         EXPECT_EQ(1, surfaceFrame->getToken());
         EXPECT_EQ(true, surfaceFrame->getIsBuffer());
@@ -151,7 +152,7 @@
     void DroppedSurfaceFrameForBufferTransaction() {
         sp<BufferStateLayer> layer = createBufferStateLayer();
 
-        sp<Fence> fence1(new Fence());
+        sp<Fence> fence1(sp<Fence>::make());
         auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
         BufferData bufferData;
         bufferData.acquireFence = fence1;
@@ -171,7 +172,7 @@
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
 
-        sp<Fence> fence2(new Fence());
+        sp<Fence> fence2(sp<Fence>::make());
         auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
         nsecs_t start = systemTime();
         bufferData.acquireFence = fence2;
@@ -192,8 +193,7 @@
         const auto presentedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
 
         commitTransaction(layer.get());
-        bool computeVisisbleRegions;
-        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+        layer->updateTexImage(15);
 
         EXPECT_EQ(1, droppedSurfaceFrame->getToken());
         EXPECT_EQ(true, droppedSurfaceFrame->getIsBuffer());
@@ -218,7 +218,7 @@
         EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_EQ(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
 
-        sp<Fence> fence(new Fence());
+        sp<Fence> fence(sp<Fence>::make());
         auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
         BufferData bufferData;
         bufferData.acquireFence = fence;
@@ -243,15 +243,14 @@
         // Buffers are presented only at latch time.
         EXPECT_EQ(PresentState::Unknown, surfaceFrame->getPresentState());
 
-        bool computeVisisbleRegions;
-        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+        layer->updateTexImage(15);
 
         EXPECT_EQ(PresentState::Presented, surfaceFrame->getPresentState());
     }
 
     void BufferlessSurfaceFrameNotCreatedIfBufferSufaceFrameExists() {
         sp<BufferStateLayer> layer = createBufferStateLayer();
-        sp<Fence> fence(new Fence());
+        sp<Fence> fence(sp<Fence>::make());
         auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
         BufferData bufferData;
         bufferData.acquireFence = fence;
@@ -294,7 +293,7 @@
         ASSERT_EQ(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto bufferlessSurfaceFrame2 = layer->mDrawingState.bufferlessSurfaceFramesTX[4];
 
-        sp<Fence> fence(new Fence());
+        sp<Fence> fence(sp<Fence>::make());
         auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
         BufferData bufferData;
         bufferData.acquireFence = fence;
@@ -331,8 +330,7 @@
         // Buffers are presented only at latch time.
         EXPECT_EQ(PresentState::Unknown, bufferSurfaceFrameTX->getPresentState());
 
-        bool computeVisisbleRegions;
-        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+        layer->updateTexImage(15);
 
         EXPECT_EQ(PresentState::Presented, bufferSurfaceFrameTX->getPresentState());
     }
@@ -340,7 +338,7 @@
     void PendingSurfaceFramesRemovedAfterClassification() {
         sp<BufferStateLayer> layer = createBufferStateLayer();
 
-        sp<Fence> fence1(new Fence());
+        sp<Fence> fence1(sp<Fence>::make());
         auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
         BufferData bufferData;
         bufferData.acquireFence = fence1;
@@ -359,7 +357,7 @@
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
 
-        sp<Fence> fence2(new Fence());
+        sp<Fence> fence2(sp<Fence>::make());
         auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
         bufferData.acquireFence = fence2;
         bufferData.frameNumber = 1;
@@ -377,8 +375,7 @@
         auto presentedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
 
         commitTransaction(layer.get());
-        bool computeVisisbleRegions;
-        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+        layer->updateTexImage(15);
 
         // Both the droppedSurfaceFrame and presentedSurfaceFrame should be in
         // pendingJankClassifications.
@@ -393,7 +390,7 @@
     void BufferSurfaceFrame_ReplaceValidTokenBufferWithInvalidTokenBuffer() {
         sp<BufferStateLayer> layer = createBufferStateLayer();
 
-        sp<Fence> fence1(new Fence());
+        sp<Fence> fence1(sp<Fence>::make());
         auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
         BufferData bufferData;
         bufferData.acquireFence = fence1;
@@ -413,7 +410,7 @@
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto droppedSurfaceFrame1 = layer->mDrawingState.bufferSurfaceFrameTX;
 
-        sp<Fence> fence2(new Fence());
+        sp<Fence> fence2(sp<Fence>::make());
         auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
         auto dropStartTime1 = systemTime();
         bufferData.acquireFence = fence2;
@@ -434,7 +431,7 @@
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto droppedSurfaceFrame2 = layer->mDrawingState.bufferSurfaceFrameTX;
 
-        sp<Fence> fence3(new Fence());
+        sp<Fence> fence3(sp<Fence>::make());
         auto acquireFence3 = fenceFactory.createFenceTimeForTest(fence3);
         auto dropStartTime2 = systemTime();
         bufferData.acquireFence = fence3;
@@ -458,8 +455,7 @@
         const auto presentedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
 
         commitTransaction(layer.get());
-        bool computeVisisbleRegions;
-        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+        layer->updateTexImage(15);
 
         EXPECT_EQ(1, droppedSurfaceFrame1->getToken());
         EXPECT_EQ(true, droppedSurfaceFrame1->getIsBuffer());
@@ -485,7 +481,7 @@
         uint32_t surfaceFramesPendingClassification = 0;
         std::vector<std::shared_ptr<frametimeline::SurfaceFrame>> bufferlessSurfaceFrames;
         for (int i = 0; i < 10; i += 2) {
-            sp<Fence> fence(new Fence());
+            sp<Fence> fence(sp<Fence>::make());
             BufferData bufferData;
             bufferData.acquireFence = fence;
             bufferData.frameNumber = 1;
@@ -517,8 +513,7 @@
         }
 
         auto presentedBufferSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
-        bool computeVisisbleRegions;
-        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+        layer->updateTexImage(15);
         // BufferlessSurfaceFrames are immediately set to presented and added to the DisplayFrame.
         // Since we don't have access to DisplayFrame here, trigger an onPresent directly.
         for (auto& surfaceFrame : bufferlessSurfaceFrames) {
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index 61b72a0..2dbcfbd 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -101,10 +101,10 @@
     void SetUp() override {
         // add layers
         mTracing.setBufferSize(SMALL_BUFFER_SIZE);
-        const sp<IBinder> fakeLayerHandle = new BBinder();
+        const sp<IBinder> fakeLayerHandle = sp<BBinder>::make();
         mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent",
                               123 /* flags */, -1 /* parentId */);
-        const sp<IBinder> fakeChildLayerHandle = new BBinder();
+        const sp<IBinder> fakeChildLayerHandle = sp<BBinder>::make();
         mTracing.onLayerAdded(fakeChildLayerHandle->localBinder(), mChildLayerId, "child",
                               456 /* flags */, mParentLayerId);
 
@@ -127,6 +127,8 @@
             std::vector<TransactionState> transactions;
             transactions.emplace_back(transaction);
             VSYNC_ID_FIRST_LAYER_CHANGE = ++mVsyncId;
+            mTracing.onLayerAddedToDrawingState(mParentLayerId, VSYNC_ID_FIRST_LAYER_CHANGE);
+            mTracing.onLayerAddedToDrawingState(mChildLayerId, VSYNC_ID_FIRST_LAYER_CHANGE);
             mTracing.addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE);
             flush(VSYNC_ID_FIRST_LAYER_CHANGE);
         }
@@ -232,12 +234,14 @@
     void SetUp() override {
         // add layers
         mTracing.setBufferSize(SMALL_BUFFER_SIZE);
-        const sp<IBinder> fakeLayerHandle = new BBinder();
+        const sp<IBinder> fakeLayerHandle = sp<BBinder>::make();
         mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mLayerId, "Test Layer",
                               123 /* flags */, -1 /* parentId */);
-        const sp<IBinder> fakeMirrorLayerHandle = new BBinder();
+        const sp<IBinder> fakeMirrorLayerHandle = sp<BBinder>::make();
         mTracing.onMirrorLayerAdded(fakeMirrorLayerHandle->localBinder(), mMirrorLayerId, "Mirror",
                                     mLayerId);
+        mTracing.onLayerAddedToDrawingState(mLayerId, mVsyncId);
+        mTracing.onLayerAddedToDrawingState(mMirrorLayerId, mVsyncId);
 
         // add some layer transaction
         {
@@ -257,7 +261,7 @@
 
             std::vector<TransactionState> transactions;
             transactions.emplace_back(transaction);
-            mTracing.addCommittedTransactions(transactions, ++mVsyncId);
+            mTracing.addCommittedTransactions(transactions, mVsyncId);
             flush(mVsyncId);
         }
     }
diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
index 15fea9c..45ebb85 100644
--- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
@@ -99,7 +99,7 @@
         LayerMetadata metadata = {}) {
     sp<Client> client;
     LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, metadata);
-    return new BufferStateLayer(args);
+    return sp<BufferStateLayer>::make(args);
 }
 
 void TunnelModeEnabledReporterTest::setupScheduler() {
@@ -108,13 +108,15 @@
 
     EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*eventThread, createEventConnection(_, _))
-            .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
-                                                       ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
-            .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
-                                                       ResyncCallback())));
+            .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+                                                             mock::EventThread::kCallingUid,
+                                                             ResyncCallback())));
 
     auto vsyncController = std::make_unique<mock::VsyncController>();
     auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index b7f968d..f660753 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -44,6 +44,8 @@
         ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_))
                 .WillByDefault(Invoke(this, &MockVSyncTracker::nextVSyncTime));
         ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true));
+        ON_CALL(*this, currentPeriod())
+                .WillByDefault(Invoke(this, &MockVSyncTracker::getCurrentPeriod));
     }
 
     MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t));
@@ -62,6 +64,8 @@
         return (timePoint - (timePoint % mPeriod) + mPeriod);
     }
 
+    nsecs_t getCurrentPeriod() const { return mPeriod; }
+
 protected:
     nsecs_t const mPeriod;
 };
@@ -393,6 +397,43 @@
     EXPECT_THAT(cb1.mCalls[0], Eq(1063));
 }
 
+TEST_F(VSyncDispatchTimerQueueTest, noCloseCallbacksAfterPeriodChange) {
+    EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
+            .Times(4)
+            .WillOnce(Return(1000))
+            .WillOnce(Return(2000))
+            .WillOnce(Return(2500))
+            .WillOnce(Return(4000));
+
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 3900)).InSequence(seq);
+
+    CountingCallback cb(mDispatch);
+
+    mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 0});
+
+    advanceToNextCallback();
+
+    ASSERT_THAT(cb.mCalls.size(), Eq(1));
+    EXPECT_THAT(cb.mCalls[0], Eq(1000));
+
+    mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
+
+    advanceToNextCallback();
+
+    ASSERT_THAT(cb.mCalls.size(), Eq(2));
+    EXPECT_THAT(cb.mCalls[1], Eq(2000));
+
+    mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000});
+
+    advanceToNextCallback();
+
+    ASSERT_THAT(cb.mCalls.size(), Eq(3));
+    EXPECT_THAT(cb.mCalls[2], Eq(4000));
+}
+
 TEST_F(VSyncDispatchTimerQueueTest, rearmsFaroutTimeoutWhenCancellingCloseOne) {
     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
             .Times(4)
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 4eb9055..a35ff96 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -77,12 +77,12 @@
 };
 
 std::shared_ptr<android::FenceTime> generateInvalidFence() {
-    sp<Fence> fence = new Fence();
+    sp<Fence> fence = sp<Fence>::make();
     return std::make_shared<android::FenceTime>(fence);
 }
 
 std::shared_ptr<android::FenceTime> generatePendingFence() {
-    sp<Fence> fence = new Fence(dup(fileno(tmpfile())));
+    sp<Fence> fence = sp<Fence>::make(dup(fileno(tmpfile())));
     return std::make_shared<android::FenceTime>(fence);
 }
 
@@ -92,7 +92,7 @@
 }
 
 std::shared_ptr<android::FenceTime> generateSignalledFenceWithTime(nsecs_t time) {
-    sp<Fence> fence = new Fence(dup(fileno(tmpfile())));
+    sp<Fence> fence = sp<Fence>::make(dup(fileno(tmpfile())));
     std::shared_ptr<android::FenceTime> ft = std::make_shared<android::FenceTime>(fence);
     signalFenceWithTime(ft, time);
     return ft;
@@ -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/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 3e0d6d3..07cd15d 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -80,7 +80,7 @@
     MOCK_METHOD(hal::Error, presentOrValidate,
                 (nsecs_t, uint32_t *, uint32_t *, android::sp<android::Fence> *, uint32_t *),
                 (override));
-    MOCK_METHOD(std::future<hal::Error>, setDisplayBrightness,
+    MOCK_METHOD(ftl::Future<hal::Error>, setDisplayBrightness,
                 (float, float, const Hwc2::Composer::DisplayBrightnessOptions &), (override));
     MOCK_METHOD(hal::Error, setActiveConfigWithConstraints,
                 (hal::HWConfigId, const hal::VsyncPeriodChangeConstraints &,
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/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index c5ca86a..ded6806 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -24,12 +24,13 @@
 
 class EventThread : public android::EventThread {
 public:
+    static constexpr auto kCallingUid = static_cast<uid_t>(0);
+
     EventThread();
     ~EventThread() override;
 
     MOCK_CONST_METHOD2(createEventConnection,
-                       sp<EventThreadConnection>(ResyncCallback,
-                                                 ISurfaceComposer::EventRegistrationFlags));
+                       sp<EventThreadConnection>(ResyncCallback, EventRegistrationFlags));
     MOCK_METHOD0(onScreenReleased, void());
     MOCK_METHOD0(onScreenAcquired, void());
     MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index 0840a2f..d086d79 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -25,7 +25,10 @@
 class MockLayer : public Layer {
 public:
     MockLayer(SurfaceFlinger* flinger, std::string name)
-          : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {}
+          : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {
+        EXPECT_CALL(*this, getDefaultFrameRateCompatibility())
+                .WillOnce(testing::Return(scheduler::LayerInfo::FrameRateCompatibility::Default));
+    }
     explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {}
 
     MOCK_CONST_METHOD0(getType, const char*());
@@ -33,6 +36,8 @@
     MOCK_CONST_METHOD0(isVisible, bool());
     MOCK_METHOD0(createClone, sp<Layer>());
     MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate());
+    MOCK_CONST_METHOD0(getDefaultFrameRateCompatibility,
+                       scheduler::LayerInfo::FrameRateCompatibility());
     MOCK_CONST_METHOD0(getOwnerUid, uid_t());
     MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace());
 };
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/surfaceflinger/tests/utils/ColorUtils.h b/services/surfaceflinger/tests/utils/ColorUtils.h
index 07916b6..38c422a 100644
--- a/services/surfaceflinger/tests/utils/ColorUtils.h
+++ b/services/surfaceflinger/tests/utils/ColorUtils.h
@@ -33,6 +33,10 @@
     static const Color WHITE;
     static const Color BLACK;
     static const Color TRANSPARENT;
+
+    half3 toHalf3() { return half3{r / 255.0f, g / 255.0f, b / 255.0f}; }
+
+    half4 toHalf4() { return half4{r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f}; }
 };
 
 const Color Color::RED{255, 0, 0, 255};
@@ -81,6 +85,14 @@
         }
         color = ret;
     }
+
+    static half3 toHalf3(const Color& color) {
+        return half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f};
+    }
+
+    static half4 toHalf4(const Color& color) {
+        return half4{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f};
+    }
 };
 } // namespace
 } // namespace android
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index dfd3b91..cb7040a 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -39,7 +39,7 @@
         SurfaceComposerClient::Transaction().apply(true);
 
         captureArgs.dataspace = ui::Dataspace::V0_SRGB;
-        const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+        const sp<SyncScreenCaptureListener> captureListener = sp<SyncScreenCaptureListener>::make();
         binder::Status status = sf->captureDisplay(captureArgs, captureListener);
         status_t err = statusTFromBinderStatus(status);
         if (err != NO_ERROR) {
@@ -63,7 +63,8 @@
                                DisplayCaptureArgs& captureArgs) {
         ScreenCaptureResults captureResults;
         ASSERT_EQ(NO_ERROR, captureDisplay(captureArgs, captureResults));
-        *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
+        *sc = std::make_unique<ScreenCapture>(captureResults.buffer,
+                                              captureResults.capturedHdrLayers);
     }
 
     static status_t captureLayers(LayerCaptureArgs& captureArgs,
@@ -72,7 +73,7 @@
         SurfaceComposerClient::Transaction().apply(true);
 
         captureArgs.dataspace = ui::Dataspace::V0_SRGB;
-        const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+        const sp<SyncScreenCaptureListener> captureListener = sp<SyncScreenCaptureListener>::make();
         binder::Status status = sf->captureLayers(captureArgs, captureListener);
         status_t err = statusTFromBinderStatus(status);
         if (err != NO_ERROR) {
@@ -85,9 +86,12 @@
     static void captureLayers(std::unique_ptr<ScreenCapture>* sc, LayerCaptureArgs& captureArgs) {
         ScreenCaptureResults captureResults;
         ASSERT_EQ(NO_ERROR, captureLayers(captureArgs, captureResults));
-        *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
+        *sc = std::make_unique<ScreenCapture>(captureResults.buffer,
+                                              captureResults.capturedHdrLayers);
     }
 
+    bool capturedHdrLayers() const { return mContainsHdr; }
+
     void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
         ASSERT_NE(nullptr, mOutBuffer);
         ASSERT_NE(nullptr, mPixels);
@@ -185,7 +189,8 @@
         EXPECT_EQ(height, mOutBuffer->getHeight());
     }
 
-    explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
+    explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer, bool containsHdr)
+          : mOutBuffer(outBuffer), mContainsHdr(containsHdr) {
         if (mOutBuffer) {
             mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
         }
@@ -197,6 +202,7 @@
 
 private:
     sp<GraphicBuffer> mOutBuffer;
+    bool mContainsHdr = mContainsHdr;
     uint8_t* mPixels = nullptr;
 };
 } // namespace
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index 667dfb9..8b4a6be 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -18,7 +18,13 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wconversion"
 
+// This file is included by modules that have host support but android/looper.h is not supported
+// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled.
+#ifndef __BIONIC__
+#define __REMOVED_IN(x) __attribute__((deprecated))
+#endif
 #include <android/looper.h>
+
 #include <gui/DisplayEventReceiver.h>
 #include <utils/Looper.h>
 
@@ -55,8 +61,7 @@
 {
     DisplayEventReceiver myDisplayEvent;
 
-
-    sp<Looper> loop = new Looper(false);
+    sp<Looper> loop = sp<Looper>::make(false);
     loop->addFd(myDisplayEvent.getFd(), 0, ALOOPER_EVENT_INPUT, receiver,
             &myDisplayEvent);
 
diff --git a/services/utils/tests/Android.bp b/services/utils/tests/Android.bp
index 54cf5b7..cfa8a08 100644
--- a/services/utils/tests/Android.bp
+++ b/services/utils/tests/Android.bp
@@ -34,5 +34,4 @@
         "libgmock",
         "libserviceutils",
     ],
-    clang: true,
 }
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 440c5b1..5719b5c 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -37,7 +37,6 @@
             "vulkan_headers",
         ],
     },
-    clang: true,
     sanitize: {
         misc_undefined: ["integer"],
     },
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index c4b1487..0a33760 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -785,12 +785,16 @@
     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});
     }
 
     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) {
             all_formats.emplace_back(
                 VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
@@ -806,6 +810,9 @@
         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) {
             all_formats.emplace_back(
                 VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
@@ -939,8 +946,7 @@
         // VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR and
         // VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR.  We technically cannot
         // know if VK_PRESENT_MODE_SHARED_MAILBOX_KHR is supported without a
-        // surface, and that cannot be relied upon.
-        present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
+        // surface, and that cannot be relied upon.  Therefore, don't return it.
         present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
     } else {
         ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
@@ -1228,11 +1234,15 @@
               decodePixelFormat(native_pixel_format).c_str(), strerror(-err), err);
         return VK_ERROR_SURFACE_LOST_KHR;
     }
-    err = native_window_set_buffers_data_space(window, native_dataspace);
-    if (err != android::OK) {
-        ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
-              native_dataspace, strerror(-err), err);
-        return VK_ERROR_SURFACE_LOST_KHR;
+
+    /* Respect consumer default dataspace upon HAL_DATASPACE_ARBITRARY. */
+    if (native_dataspace != HAL_DATASPACE_ARBITRARY) {
+        err = native_window_set_buffers_data_space(window, native_dataspace);
+        if (err != android::OK) {
+            ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
+                  native_dataspace, strerror(-err), err);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
     }
 
     err = native_window_set_buffers_dimensions(
@@ -1844,6 +1854,11 @@
             if (swapchain_result != VK_SUCCESS) {
                 OrphanSwapchain(device, &swapchain);
             }
+            // Android will only return VK_SUBOPTIMAL_KHR for vkQueuePresentKHR,
+            // and only when the window's transform/rotation changes.  Extent
+            // changes will not cause VK_SUBOPTIMAL_KHR because of the
+            // application issues that were caused when the following transform
+            // change was added.
             int window_transform_hint;
             err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT,
                                 &window_transform_hint);
diff --git a/vulkan/nulldrv/Android.bp b/vulkan/nulldrv/Android.bp
index 0daad9c..a6d540b 100644
--- a/vulkan/nulldrv/Android.bp
+++ b/vulkan/nulldrv/Android.bp
@@ -27,7 +27,6 @@
     proprietary: true,
     relative_install_path: "hw",
 
-    clang: true,
     cflags: [
         "-fvisibility=hidden",
         "-fstrict-aliasing",
diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp
index fa0258b..b6d3a0b 100644
--- a/vulkan/vkjson/Android.bp
+++ b/vulkan/vkjson/Android.bp
@@ -37,7 +37,6 @@
 
 cc_library_static {
     name: "libvkjson_ndk",
-    clang: true,
     srcs: [
         "vkjson.cc",
         "vkjson_instance.cc",