Reconcile native and Java parcel code for WorkSource. am: c1359ac51c am: 1ce5be5b7d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/19135348

Change-Id: I01df1f4f6376b6173bd861ba0ae31eb8edac7d20
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 6fb9a4d..b37a457 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -1195,6 +1195,11 @@
     bool traceStream = false;
     bool onlyUserspace = false;
 
+    fprintf(stderr,
+            "** Warning: atrace will end vendor support in the next Android Release. **\n"
+            "** Perfetto is the suggested replacement tool. It will gain vendor      **\n"
+            "** support. See https://perfetto.dev/docs/quickstart/android-tracing    **\n\n");
+
     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
         showHelp(argv[0]);
         exit(0);
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 5267b02..891b1c6 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -181,6 +181,8 @@
     chmod 0666 /sys/kernel/tracing/events/clk/clk_enable/enable
     chmod 0666 /sys/kernel/debug/tracing/events/clk/clk_set_rate/enable
     chmod 0666 /sys/kernel/tracing/events/clk/clk_set_rate/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/printk/console/enable
+    chmod 0666 /sys/kernel/tracing/events/printk/console/enable
 
     # disk
     chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
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 2b94b71..f759674 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) {
@@ -1619,6 +1641,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");
@@ -3076,7 +3100,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 +3413,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 +3430,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/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 a49f563..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;
@@ -2876,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();
     }
 
@@ -3565,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/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/main.cpp b/cmds/servicemanager/main.cpp
index 2fb9c2b..1d458b7 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -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);
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/include/input/Input.h b/include/input/Input.h
index e7d68fc..e0c9de4 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -1059,6 +1059,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/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/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/binder/Android.bp b/libs/binder/Android.bp
index d8d2cf2..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,12 +175,124 @@
         "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,
+}
 
-    header_abi_checker: {
-        diff_flags: ["-allow-adding-removing-weak-symbols"],
-    },
+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 {
@@ -300,9 +363,7 @@
     local_include_dir: "aidl",
     host_supported: true,
     srcs: [
-        "aidl/android/content/pm/IPackageChangeObserver.aidl",
         "aidl/android/content/pm/IPackageManagerNative.aidl",
-        "aidl/android/content/pm/PackageChangeEvent.aidl",
         "aidl/android/content/pm/IStagedApexObserver.aidl",
         "aidl/android/content/pm/ApexStagedEvent.aidl",
         "aidl/android/content/pm/StagedApexInfo.aidl",
@@ -370,6 +431,7 @@
 
 cc_library {
     name: "libbatterystats_aidl",
+    host_supported: true,
     srcs: [
         "IBatteryStats.cpp",
     ],
@@ -382,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..532bacb 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.",
@@ -620,13 +648,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..49fc195 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) {
@@ -328,6 +345,11 @@
 {
     if (isRpcBinder()) return UNKNOWN_TRANSACTION;
 
+    if constexpr (!kEnableKernelIpc) {
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return INVALID_OPERATION;
+    }
+
     Obituary ob;
     ob.recipient = recipient;
     ob.cookie = cookie;
@@ -366,6 +388,11 @@
 {
     if (isRpcBinder()) return UNKNOWN_TRANSACTION;
 
+    if constexpr (!kEnableKernelIpc) {
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return INVALID_OPERATION;
+    }
+
     AutoMutex _l(mLock);
 
     if (mObitsSent) {
@@ -401,6 +428,11 @@
 {
     LOG_ALWAYS_FATAL_IF(isRpcBinder(), "Cannot send obituary for remote binder.");
 
+    if constexpr (!kEnableKernelIpc) {
+        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");
 
@@ -469,12 +501,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 +541,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 +598,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..5c7102e 100644
--- a/libs/binder/FdTrigger.h
+++ b/libs/binder/FdTrigger.h
@@ -55,7 +55,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..d536219 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;
 }
 
@@ -989,6 +1001,7 @@
         if (acquireResult) *acquireResult = err;
         if (reply) reply->setError(err);
         mLastError = err;
+        logExtendedError();
     }
 
     return err;
@@ -1443,6 +1456,23 @@
     return ret;
 }
 
+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(Parcel* parcel, const uint8_t* data,
                                 size_t /*dataSize*/,
                                 const binder_size_t* /*objects*/,
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index fd2d868..fd47783 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -167,7 +167,7 @@
     }
 }
 
-#if !defined(__ANDROID_VNDK__) && defined(__ANDROID__)
+#if !defined(__ANDROID_VNDK__)
 // IPermissionController is not accessible to vendors
 
 bool checkCallingPermission(const String16& permission)
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..537527e 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,54 @@
 
             // 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);
+
+    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;
+
+    if (objectTableSize != ancillaryFds.size()) {
+        ALOGE("objectTableSize=%zu ancillaryFds.size=%zu", objectTableSize, ancillaryFds.size());
+        freeData(); // don't leak mData
+        return BAD_VALUE;
+    }
+
+    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 +2628,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 +2650,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 +2705,9 @@
     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();
+        mOwner(this, mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
+               kernelFields ? kernelFields->mObjectsSize : 0);
     } else {
         LOG_ALLOC("Parcel %p: freeing allocated data", this);
         releaseObjects();
@@ -2358,7 +2720,8 @@
             }
             free(mData);
         }
-        if (mObjects) free(mObjects);
+        auto* kernelFields = maybeKernelFields();
+        if (kernelFields && kernelFields->mObjects) free(kernelFields->mObjects);
     }
 }
 
@@ -2433,13 +2796,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 +2821,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 +2862,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 +2873,27 @@
 
             // 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);
+        mOwner(this, 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 +2901,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 +2985,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 +3007,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 +3046,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 +3073,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 +3095,7 @@
     }
     return openAshmemSize;
 }
+#endif // BINDER_WITH_KERNEL_IPC
 
 // --- Parcel::Blob ---
 
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 4a01d81..7faff47 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -35,14 +35,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 +101,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 +176,10 @@
     // the thread handler is installed
     if (gProcess) {
         gProcess->mForked = true;
+
+        // "O_CLOFORK"
+        close(gProcess->mDriverFD);
+        gProcess->mDriverFD = -1;
     }
     gProcessMutex.unlock();
 }
@@ -182,7 +192,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 +299,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 +400,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 +419,20 @@
     return result;
 }
 
-size_t ProcessState::getThreadPoolMaxThreadCount() const {
+size_t ProcessState::getThreadPoolMaxTotalThreadCount() const {
     // 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 +440,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 +518,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..096d5cc 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,31 @@
         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);
+
+            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 +243,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 +280,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 +290,12 @@
 }
 
 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) {
+                                    std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen) {
     // 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 +316,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 +331,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 +362,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 +371,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 +410,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");
                 }
@@ -484,7 +524,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 +538,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..80f6a37 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,17 @@
 #include <binder/RpcServer.h>
 #include <binder/RpcTransportRaw.h>
 #include <binder/Stability.h>
+#include <utils/Compat.h>
 #include <utils/String8.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 +60,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,7 +77,7 @@
 }
 
 void RpcSession::setMaxIncomingThreads(size_t threads) {
-    std::lock_guard<std::mutex> _l(mMutex);
+    RpcMutexLockGuard _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)",
@@ -89,12 +86,12 @@
 }
 
 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);
+    RpcMutexLockGuard _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)",
@@ -103,7 +100,7 @@
 }
 
 size_t RpcSession::getMaxOutgoingThreads() {
-    std::lock_guard<std::mutex> _l(mMutex);
+    RpcMutexLockGuard _l(mMutex);
     return mMaxOutgoingThreads;
 }
 
@@ -116,7 +113,7 @@
         return false;
     }
 
-    std::lock_guard<std::mutex> _l(mMutex);
+    RpcMutexLockGuard _l(mMutex);
     if (mProtocolVersion && version > *mProtocolVersion) {
         ALOGE("Cannot upgrade explicitly capped protocol version %u to newer version %u",
               *mProtocolVersion, version);
@@ -128,10 +125,18 @@
 }
 
 std::optional<uint32_t> RpcSession::getProtocolVersion() {
-    std::lock_guard<std::mutex> _l(mMutex);
+    RpcMutexLockGuard _l(mMutex);
     return mProtocolVersion;
 }
 
+void RpcSession::setFileDescriptorTransportMode(FileDescriptorTransportMode mode) {
+    mFileDescriptorTransportMode = mode;
+}
+
+RpcSession::FileDescriptorTransportMode RpcSession::getFileDescriptorTransportMode() {
+    return mFileDescriptorTransportMode;
+}
+
 status_t RpcSession::setupUnixDomainClient(const char* path) {
     return setupSocketClient(UnixSocketAddress(path));
 }
@@ -152,13 +157,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 +166,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 +209,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 +222,7 @@
     }
 
     _l.unlock();
+
     mRpcBinderState->clear();
 
     return true;
@@ -255,7 +257,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 +283,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 +294,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 +325,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 +405,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,7 +439,7 @@
 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);
+        RpcMutexLockGuard _l(mMutex);
         LOG_ALWAYS_FATAL_IF(mConnections.mOutgoing.size() != 0,
                             "Must only setup session once, but already has %zu clients",
                             mConnections.mOutgoing.size());
@@ -499,7 +501,11 @@
         return status;
     }
 
+#ifdef BINDER_RPC_SINGLE_THREADED
+    constexpr size_t outgoingThreads = 1;
+#else  // BINDER_RPC_SINGLE_THREADED
     size_t outgoingThreads = std::min(numThreadsAvailable, mMaxOutgoingThreads);
+#endif // BINDER_RPC_SINGLE_THREADED
     ALOGI_IF(outgoingThreads != numThreadsAvailable,
              "Server hints client to start %zu outgoing threads, but client will only start %zu "
              "because it is preconfigured to start at most %zu outgoing threads.",
@@ -613,6 +619,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 +628,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 +640,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 +660,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 +683,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 +703,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 +715,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 +728,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 +742,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 +760,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 +769,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 +786,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 +805,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 +892,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 +924,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..0ae75cd 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);
@@ -216,17 +227,17 @@
 }
 
 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(),
@@ -309,9 +320,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 +333,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 +345,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 +372,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 +386,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 +466,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 +487,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 +503,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 +525,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 +535,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.
@@ -563,7 +584,7 @@
 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));
+    delete[] const_cast<uint8_t*>(data);
     (void)dataSize;
     LOG_ALWAYS_FATAL_IF(objects != nullptr);
     LOG_ALWAYS_FATAL_IF(objectsCount != 0, "%zu objects remaining", objectsCount);
@@ -571,43 +592,74 @@
 
 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) {
+        Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(rpcReply.parcelDataSize);
+        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 +670,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 +695,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 +728,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 +768,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,10 +779,12 @@
         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,
@@ -734,9 +796,10 @@
     (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 +843,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 +887,78 @@
     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) {
+            Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(transaction->parcelDataSize);
+            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 +984,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 +1030,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 +1109,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 +1129,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..6fb2e4a 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>
@@ -178,28 +179,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
@@ -257,7 +269,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..7cc58cd 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -18,6 +18,7 @@
 #include <log/log.h>
 
 #include <poll.h>
+#include <stddef.h>
 
 #include <binder/RpcTransportRaw.h>
 
@@ -28,30 +29,37 @@
 
 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;
+        } else if (ret == 0) {
+            return DEAD_OBJECT;
         }
 
-        *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) {
+    status_t interruptableReadOrWrite(
+            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) {
@@ -81,15 +89,7 @@
 
         bool havePolled = false;
         while (true) {
-            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));
-
+            ssize_t processSize = sendOrReceiveFun(iovs, niovs);
             if (processSize < 0) {
                 int savedErrno = errno;
 
@@ -126,7 +126,7 @@
             }
 
             if (altPoll) {
-                if (status_t status = altPoll(); status != OK) return status;
+                if (status_t status = (*altPoll)(); status != OK) return status;
                 if (fdTrigger->isTriggered()) {
                     return DEAD_OBJECT;
                 }
@@ -139,16 +139,123 @@
         }
     }
 
-    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 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),
+            };
+            return TEMP_FAILURE_RETRY(sendmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
+        };
+        return interruptableReadOrWrite(fdTrigger, iovs, niovs, send, "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);
+    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))];
+
+                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;
+                }
+
+                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;
+                    }
+                }
+
+                if (msg.msg_flags & MSG_CTRUNC) {
+                    ALOGE("msg was truncated. Aborting session.");
+                    errno = EPIPE;
+                    return -1;
+                }
+
+                return processSize;
+            }
+            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(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/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..7c6d6f1 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,37 @@
 // 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.
+    //
+    // Aborts if offset > size.
+    Span<T> splitOff(size_t offset) {
+        LOG_ALWAYS_FATAL_IF(offset > size);
+        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/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index 7c99f76..f8a8843 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -17,7 +17,6 @@
 
 package android.content.pm;
 
-import android.content.pm.IPackageChangeObserver;
 import android.content.pm.IStagedApexObserver;
 import android.content.pm.StagedApexInfo;
 
@@ -92,18 +91,6 @@
      */
     @utf8InCpp String getModuleMetadataPackageName();
 
-    /* Returns the names of all packages. */
-    @utf8InCpp String[] getAllPackages();
-
-    /** Register an extra package change observer to receive the multi-cast. */
-    void registerPackageChangeObserver(in IPackageChangeObserver observer);
-
-    /**
-     * Unregister an existing package change observer.
-     * This does nothing if this observer was not already registered.
-     */
-    void unregisterPackageChangeObserver(in IPackageChangeObserver observer);
-
     /**
      * Returns true if the package has the SHA 256 version of the signing certificate.
      * @see PackageManager#hasSigningCertificate(String, byte[], int), where type
diff --git a/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl b/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl
deleted file mode 100644
index e30e907..0000000
--- a/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-/**
- * This event is designed for notification to native code listener about
- * any changes on a package including update, deletion and etc.
- *
- * @hide
- */
-parcelable PackageChangeEvent {
-  @utf8InCpp String packageName;
-  long version;
-  long lastUpdateTimeMillis;
-  boolean newInstalled;
-  boolean dataRemoved;
-  boolean isDeleted;
-}
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 7067830..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();
 };
 
@@ -219,80 +219,79 @@
 
 namespace internal {
 constexpr const char* const kManualInterfaces[] = {
-  "android.app.IActivityManager",
-  "android.app.IUidObserver",
-  "android.drm.IDrm",
-  "android.dvr.IVsyncCallback",
-  "android.dvr.IVsyncService",
-  "android.gfx.tests.ICallback",
-  "android.gfx.tests.IIPCTest",
-  "android.gfx.tests.ISafeInterfaceTest",
-  "android.graphicsenv.IGpuService",
-  "android.gui.IConsumerListener",
-  "android.gui.IGraphicBufferConsumer",
-  "android.gui.ITransactionComposerListener",
-  "android.gui.SensorEventConnection",
-  "android.gui.SensorServer",
-  "android.hardware.ICamera",
-  "android.hardware.ICameraClient",
-  "android.hardware.ICameraRecordingProxy",
-  "android.hardware.ICameraRecordingProxyListener",
-  "android.hardware.ICrypto",
-  "android.hardware.IOMXObserver",
-  "android.hardware.IStreamListener",
-  "android.hardware.IStreamSource",
-  "android.media.IAudioService",
-  "android.media.IDataSource",
-  "android.media.IDrmClient",
-  "android.media.IMediaCodecList",
-  "android.media.IMediaDrmService",
-  "android.media.IMediaExtractor",
-  "android.media.IMediaExtractorService",
-  "android.media.IMediaHTTPConnection",
-  "android.media.IMediaHTTPService",
-  "android.media.IMediaLogService",
-  "android.media.IMediaMetadataRetriever",
-  "android.media.IMediaMetricsService",
-  "android.media.IMediaPlayer",
-  "android.media.IMediaPlayerClient",
-  "android.media.IMediaPlayerService",
-  "android.media.IMediaRecorder",
-  "android.media.IMediaRecorderClient",
-  "android.media.IMediaResourceMonitor",
-  "android.media.IMediaSource",
-  "android.media.IRemoteDisplay",
-  "android.media.IRemoteDisplayClient",
-  "android.media.IResourceManagerClient",
-  "android.media.IResourceManagerService",
-  "android.os.IComplexTypeInterface",
-  "android.os.IPermissionController",
-  "android.os.IPingResponder",
-  "android.os.IProcessInfoService",
-  "android.os.ISchedulingPolicyService",
-  "android.os.IStringConstants",
-  "android.os.storage.IObbActionListener",
-  "android.os.storage.IStorageEventListener",
-  "android.os.storage.IStorageManager",
-  "android.os.storage.IStorageShutdownObserver",
-  "android.service.vr.IPersistentVrStateCallbacks",
-  "android.service.vr.IVrManager",
-  "android.service.vr.IVrStateCallbacks",
-  "android.ui.ISurfaceComposer",
-  "android.ui.ISurfaceComposerClient",
-  "android.utils.IMemory",
-  "android.utils.IMemoryHeap",
-  "com.android.car.procfsinspector.IProcfsInspector",
-  "com.android.internal.app.IAppOpsCallback",
-  "com.android.internal.app.IAppOpsService",
-  "com.android.internal.app.IBatteryStats",
-  "com.android.internal.os.IResultReceiver",
-  "com.android.internal.os.IShellCallback",
-  "drm.IDrmManagerService",
-  "drm.IDrmServiceListener",
-  "IAAudioClient",
-  "IAAudioService",
-  "VtsFuzzer",
-  nullptr,
+        "android.app.IActivityManager",
+        "android.app.IUidObserver",
+        "android.drm.IDrm",
+        "android.dvr.IVsyncCallback",
+        "android.dvr.IVsyncService",
+        "android.gfx.tests.ICallback",
+        "android.gfx.tests.IIPCTest",
+        "android.gfx.tests.ISafeInterfaceTest",
+        "android.graphicsenv.IGpuService",
+        "android.gui.IConsumerListener",
+        "android.gui.IGraphicBufferConsumer",
+        "android.gui.ITransactionComposerListener",
+        "android.gui.SensorEventConnection",
+        "android.gui.SensorServer",
+        "android.hardware.ICamera",
+        "android.hardware.ICameraClient",
+        "android.hardware.ICameraRecordingProxy",
+        "android.hardware.ICameraRecordingProxyListener",
+        "android.hardware.ICrypto",
+        "android.hardware.IOMXObserver",
+        "android.hardware.IStreamListener",
+        "android.hardware.IStreamSource",
+        "android.media.IAudioService",
+        "android.media.IDataSource",
+        "android.media.IDrmClient",
+        "android.media.IMediaCodecList",
+        "android.media.IMediaDrmService",
+        "android.media.IMediaExtractor",
+        "android.media.IMediaExtractorService",
+        "android.media.IMediaHTTPConnection",
+        "android.media.IMediaHTTPService",
+        "android.media.IMediaLogService",
+        "android.media.IMediaMetadataRetriever",
+        "android.media.IMediaMetricsService",
+        "android.media.IMediaPlayer",
+        "android.media.IMediaPlayerClient",
+        "android.media.IMediaPlayerService",
+        "android.media.IMediaRecorder",
+        "android.media.IMediaRecorderClient",
+        "android.media.IMediaResourceMonitor",
+        "android.media.IMediaSource",
+        "android.media.IRemoteDisplay",
+        "android.media.IRemoteDisplayClient",
+        "android.media.IResourceManagerClient",
+        "android.media.IResourceManagerService",
+        "android.os.IComplexTypeInterface",
+        "android.os.IPermissionController",
+        "android.os.IPingResponder",
+        "android.os.IProcessInfoService",
+        "android.os.ISchedulingPolicyService",
+        "android.os.IStringConstants",
+        "android.os.storage.IObbActionListener",
+        "android.os.storage.IStorageEventListener",
+        "android.os.storage.IStorageManager",
+        "android.os.storage.IStorageShutdownObserver",
+        "android.service.vr.IPersistentVrStateCallbacks",
+        "android.service.vr.IVrManager",
+        "android.service.vr.IVrStateCallbacks",
+        "android.ui.ISurfaceComposer",
+        "android.utils.IMemory",
+        "android.utils.IMemoryHeap",
+        "com.android.car.procfsinspector.IProcfsInspector",
+        "com.android.internal.app.IAppOpsCallback",
+        "com.android.internal.app.IAppOpsService",
+        "com.android.internal.app.IBatteryStats",
+        "com.android.internal.os.IResultReceiver",
+        "com.android.internal.os.IShellCallback",
+        "drm.IDrmManagerService",
+        "drm.IDrmServiceListener",
+        "IAAudioClient",
+        "IAAudioService",
+        "VtsFuzzer",
+        nullptr,
 };
 
 constexpr const char* const kDownstreamManualInterfaces[] = {
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index bf02099..8ce3bc9 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:
@@ -216,6 +220,7 @@
     static  void                freeBuffer(Parcel* parcel,
                                            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/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..91febbd 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);
 
@@ -600,16 +606,25 @@
     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..882dfbf 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);
@@ -132,8 +137,12 @@
     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..9318c27 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>
@@ -114,6 +115,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 +135,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();
 
     /**
@@ -177,25 +195,30 @@
     void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
     void onSessionIncomingThreadEnded() override;
 
+    static constexpr size_t kRpcAddressSize = 128;
     static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
-                                    const sockaddr_storage addr, socklen_t addrLen);
+                                    std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen);
     [[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 a579442..a2b28db 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -15,15 +15,16 @@
  */
 #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 {
@@ -37,7 +38,13 @@
 
 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 = 0;
+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
@@ -88,6 +95,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.
@@ -199,10 +218,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 +230,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 +244,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 +276,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 +296,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 +326,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 +340,14 @@
 
     std::unique_ptr<RpcState> mRpcBinderState;
 
-    std::mutex mMutex; // for all below
+    RpcMutex mMutex; // for all below
 
     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 +356,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..b21a7e9 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;
@@ -133,7 +134,8 @@
         } else {
             // b/155793159
             LOG(ERROR) << __func__ << ": Cannot associate class '" << newDescriptor
-                       << "' to dead binder.";
+                       << "' to dead binder with cached descriptor '" << SanitizeString(descriptor)
+                       << "'.";
         }
         return false;
     }
@@ -458,7 +460,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 +542,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 +554,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 +630,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 +677,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 +690,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/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..f3f2886 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -146,8 +146,8 @@
     AIBinder_Class_disableInterfaceTokenHeader;
     AIBinder_DeathRecipient_setOnUnlinked;
     AIBinder_isHandlingTransaction;
-    AIBinder_setInheritRt; # llndk
-    AIBinder_setMinSchedulerPolicy; # llndk
+    AIBinder_setInheritRt; # apex llndk
+    AIBinder_setMinSchedulerPolicy; # apex llndk
     AParcel_marshal;
     AParcel_unmarshal;
 };
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index b7c7ae4..3edeebf 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -335,11 +335,16 @@
         // 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);
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..f6bdf5c 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -117,8 +117,8 @@
 ) -> Result<(), StatusCode> {
     match code {
         bindings::Transaction_TEST_BOOL => {
-            assert_eq!(parcel.read::<bool>()?, true);
-            assert_eq!(parcel.read::<bool>()?, false);
+            assert!(parcel.read::<bool>()?);
+            assert!(!parcel.read::<bool>()?);
             assert_eq!(parcel.read::<Vec<bool>>()?, unsafe {
                 bindings::TESTDATA_BOOL
             });
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/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/binder/tests/BinderRpcTestServerConfig.aidl
similarity index 64%
copy from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
copy to libs/binder/tests/BinderRpcTestServerConfig.aidl
index 6929a6c..34d74be 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/binder/tests/BinderRpcTestServerConfig.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,12 @@
  * limitations under the License.
  */
 
-package android.content.pm;
-
-import android.content.pm.PackageChangeEvent;
-
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
+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..4ed3309 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,80 @@
     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 - 1; 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(1);
+    // 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();
+    // No more than 16 threads should exist.
+    EXPECT_TRUE(replyi == kKernelThreads || 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 +1773,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 +1819,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 +1921,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..4e41d8e 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,35 +38,14 @@
 
 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;
@@ -99,17 +54,19 @@
     EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
 }
 
-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;
@@ -1190,7 +935,7 @@
     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
@@ -1270,6 +1030,12 @@
                 // need to manually shut it down
                 EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
 
+                proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+                    // Flaky. Sometimes gets SIGABRT.
+                    EXPECT_TRUE((WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) ||
+                                (WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT))
+                            << "server process failed: " << WaitStatusToString(wstatus);
+                });
                 proc.expectAlreadyShutdown = true;
             }
         }
@@ -1299,33 +1065,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 +1253,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 +1281,7 @@
     return ret;
 }
 
-TEST_P(BinderRpc, Fds) {
+TEST_P(BinderRpcThreads, Fds) {
     ssize_t beforeFds = countFds();
     ASSERT_GE(beforeFds, 0);
     {
@@ -1382,20 +1304,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 +1404,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 +1482,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 +1518,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 +1564,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 +1586,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 +1706,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 +1718,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 +1740,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 +1790,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 +1819,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 +1861,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 +1880,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 +1905,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 +1926,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 +1955,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 +1967,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 +2015,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 +2051,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 +2071,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/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/binder/tests/binderRpcTestCommon.cpp
similarity index 63%
copy from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
copy to libs/binder/tests/binderRpcTestCommon.cpp
index 6929a6c..0d9aa95 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/binder/tests/binderRpcTestCommon.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,11 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+#include "binderRpcTestCommon.h"
 
-import android.content.pm.PackageChangeEvent;
+namespace android {
 
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
-}
+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 4fcf42d..3dab2c7 100644
--- a/libs/binder/tests/binderRpcWireProtocolTest.cpp
+++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp
@@ -233,11 +233,15 @@
         "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 == 0,
+static_assert(RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL,
               "If the binder wire protocol is updated, this test should test additional versions. "
               "The binder wire protocol should only be updated on upstream AOSP.");
 
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index e5d32da..2ca6ebd 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -59,6 +59,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/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 47ec776..7059d30 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -73,20 +73,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 +102,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 +113,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 +127,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 +154,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 +170,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 +268,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 +289,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 +308,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 +325,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 +345,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();
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 5aeb5cc..26d6770 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -70,7 +70,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 +80,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;
         },
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/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp
index f435dae..180a177 100644
--- a/libs/binder/tests/parcel_fuzzer/main.cpp
+++ b/libs/binder/tests/parcel_fuzzer/main.cpp
@@ -83,22 +83,36 @@
     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()));
+
+    P p0, p1;
+    fillRandomParcel(&p0, FuzzedDataProvider(bytes.data(), bytes.size()));
+    fillRandomParcel(&p1, std::move(provider));
+
+    FUZZ_LOG() << "backend: " << backend;
+    FUZZ_LOG() << "start: " << start << " len: " << len;
+
+    p0.appendFrom(&p1, start, len);
+}
+
 void* NothingClass_onCreate(void* args) {
     return args;
 }
@@ -148,6 +162,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/bufferqueueconverter/Android.bp b/libs/bufferqueueconverter/Android.bp
index c5d3a32..5f145a1 100644
--- a/libs/bufferqueueconverter/Android.bp
+++ b/libs/bufferqueueconverter/Android.bp
@@ -22,6 +22,7 @@
     double_loadable: true,
 
     srcs: [
+        ":libgui_frame_event_aidl",
         "BufferQueueConverter.cpp",
     ],
 
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 7e9bb7d..d169043 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -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;
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 0f1a02a..a6585c5 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -85,7 +85,20 @@
 
 /* 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 */
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 d634c58..d098e3a 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -120,6 +120,12 @@
     path: "aidl/",
 }
 
+filegroup {
+    name: "libgui_frame_event_aidl",
+    srcs: ["aidl/android/gui/FrameEvent.aidl"],
+    path: "aidl/",
+}
+
 cc_library_static {
     name: "libgui_aidl_static",
     vendor_available: true,
@@ -136,16 +142,24 @@
         "include",
     ],
 
+    include_dirs: [
+        "frameworks/native/include",
+    ],
+
     export_shared_lib_headers: [
         "libbinder",
     ],
 
     static_libs: [
         "libui-types",
+        "libgui_window_info_static",
     ],
 
     aidl: {
         export_aidl_headers: true,
+        include_dirs: [
+            "frameworks/native/libs/gui",
+        ],
     },
 }
 
@@ -184,14 +198,12 @@
         "DebugEGLImageTracker.cpp",
         "DisplayEventDispatcher.cpp",
         "DisplayEventReceiver.cpp",
-        "FrameTimelineInfo.cpp",
         "GLConsumer.cpp",
         "IConsumerListener.cpp",
         "IGraphicBufferConsumer.cpp",
         "IGraphicBufferProducer.cpp",
         "IProducerListener.cpp",
         "ISurfaceComposer.cpp",
-        "ISurfaceComposerClient.cpp",
         "ITransactionCompletedListener.cpp",
         "LayerDebugInfo.cpp",
         "LayerMetadata.cpp",
@@ -282,10 +294,16 @@
     defaults: ["libgui_bufferqueue-defaults"],
 
     srcs: [
+        ":libgui_frame_event_aidl",
         ":inputconstants_aidl",
         ":libgui_bufferqueue_sources",
-        ":libgui_aidl",
     ],
+
+    aidl: {
+        include_dirs: [
+            "frameworks/native/libs/gui",
+        ],
+    },
 }
 
 filegroup {
@@ -316,7 +334,6 @@
 cc_defaults {
     name: "libgui_bufferqueue-defaults",
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -337,7 +354,7 @@
     },
 
     whole_static_libs: [
-        "LibGuiProperties",
+        "libLibGuiProperties",
     ],
 
     shared_libs: [
@@ -405,6 +422,7 @@
     ],
 
     srcs: [
+        ":libgui_frame_event_aidl",
         "mock/GraphicBufferConsumer.cpp",
         "mock/GraphicBufferProducer.cpp",
     ],
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index dbccf30..2212e58 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -33,6 +33,7 @@
 #include <utils/Trace.h>
 
 #include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 
 #include <chrono>
 
@@ -158,9 +159,8 @@
     id++;
     mBufferItemConsumer->setName(String8(consumerName.c_str()));
     mBufferItemConsumer->setFrameAvailableListener(this);
-    mBufferItemConsumer->setBufferFreedListener(this);
 
-    ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
+    ComposerServiceAIDL::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
     mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
     mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
     mNumAcquired = 0;
@@ -287,18 +287,17 @@
 
                 // We need to check if we were waiting for a transaction callback in order to
                 // process any pending buffers and unblock. It's possible to get transaction
-                // callbacks for previous requests so we need to ensure the frame from this
-                // transaction callback matches the last acquired buffer. Since acquireNextBuffer
-                // will stop processing buffers when mWaitForTransactionCallback is set, we know
-                // that mLastAcquiredFrameNumber is the frame we're waiting on.
-                // We also want to check if mNextTransaction is null because it's possible another
+                // callbacks for previous requests so we need to ensure that there are no pending
+                // frame numbers that were in a sync. We remove the frame from mSyncedFrameNumbers
+                // set and then check if it's empty. If there are no more pending syncs, we can
+                // proceed with flushing the shadow queue.
+                // We also want to check if mSyncTransaction is null because it's possible another
                 // sync request came in while waiting, but it hasn't started processing yet. In that
                 // case, we don't actually want to flush the frames in between since they will get
                 // processed and merged with the sync transaction and released earlier than if they
                 // were sent to SF
-                if (mWaitForTransactionCallback && mSyncTransaction == nullptr &&
-                    currFrameNumber >= mLastAcquiredFrameNumber) {
-                    mWaitForTransactionCallback = false;
+                mSyncedFrameNumbers.erase(currFrameNumber);
+                if (mSyncedFrameNumbers.empty() && mSyncTransaction == nullptr) {
                     flushShadowQueue();
                 }
             } else {
@@ -416,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);
         }
     }
@@ -442,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(
@@ -562,7 +566,7 @@
         if (dequeueTime != mDequeueTimestamps.end()) {
             Parcel p;
             p.writeInt64(dequeueTime->second);
-            t->setMetadata(mSurfaceControl, METADATA_DEQUEUE_TIME, p);
+            t->setMetadata(mSurfaceControl, gui::METADATA_DEQUEUE_TIME, p);
             mDequeueTimestamps.erase(dequeueTime);
         }
     }
@@ -608,7 +612,7 @@
 }
 
 void BLASTBufferQueue::flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock) {
-    if (mWaitForTransactionCallback && mNumFrameAvailable > 0) {
+    if (!mSyncedFrameNumbers.empty() && mNumFrameAvailable > 0) {
         // We are waiting on a previous sync's transaction callback so allow another sync
         // transaction to proceed.
         //
@@ -635,6 +639,8 @@
 void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
     std::function<void(SurfaceComposerClient::Transaction*)> prevCallback = nullptr;
     SurfaceComposerClient::Transaction* prevTransaction = nullptr;
+    bool waitForTransactionCallback = !mSyncedFrameNumbers.empty();
+
     {
         BBQ_TRACE();
         std::unique_lock _lock{mMutex};
@@ -666,7 +672,7 @@
 
         // add to shadow queue
         mNumFrameAvailable++;
-        if (mWaitForTransactionCallback && mNumFrameAvailable >= 2) {
+        if (waitForTransactionCallback && mNumFrameAvailable >= 2) {
             acquireAndReleaseBuffer();
         }
         ATRACE_INT(mQueuedBufferTrace.c_str(),
@@ -683,14 +689,14 @@
             incStrong((void*)transactionCommittedCallbackThunk);
             mSyncTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk,
                                                               static_cast<void*>(this));
-            mWaitForTransactionCallback = true;
+            mSyncedFrameNumbers.emplace(item.mFrameNumber);
             if (mAcquireSingleBuffer) {
                 prevCallback = mTransactionReadyCallback;
                 prevTransaction = mSyncTransaction;
                 mTransactionReadyCallback = nullptr;
                 mSyncTransaction = nullptr;
             }
-        } else if (!mWaitForTransactionCallback) {
+        } else if (!waitForTransactionCallback) {
             acquireNextBufferLocked(std::nullopt);
         }
     }
@@ -1097,9 +1103,9 @@
     }
 
     // Clear sync states
-    if (mWaitForTransactionCallback) {
-        BQA_LOGD("mWaitForTransactionCallback cleared");
-        mWaitForTransactionCallback = false;
+    if (!mSyncedFrameNumbers.empty()) {
+        BQA_LOGD("mSyncedFrameNumbers cleared");
+        mSyncedFrameNumbers.clear();
     }
 
     if (mSyncTransaction != nullptr) {
@@ -1113,7 +1119,6 @@
     if (mBufferItemConsumer != nullptr) {
         mBufferItemConsumer->abandon();
         mBufferItemConsumer->setFrameAvailableListener(nullptr);
-        mBufferItemConsumer->setBufferFreedListener(nullptr);
     }
     mBufferItemConsumer = nullptr;
     mConsumer = nullptr;
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/FrameTimelineInfo.cpp b/libs/gui/FrameTimelineInfo.cpp
deleted file mode 100644
index 3800b88..0000000
--- a/libs/gui/FrameTimelineInfo.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "FrameTimelineInfo"
-
-#include <inttypes.h>
-
-#include <android/os/IInputConstants.h>
-#include <gui/FrameTimelineInfo.h>
-#include <gui/LayerState.h>
-#include <private/gui/ParcelUtils.h>
-#include <utils/Errors.h>
-
-#include <cmath>
-
-using android::os::IInputConstants;
-
-namespace android {
-
-status_t FrameTimelineInfo::write(Parcel& output) const {
-    SAFE_PARCEL(output.writeInt64, vsyncId);
-    SAFE_PARCEL(output.writeInt32, inputEventId);
-    SAFE_PARCEL(output.writeInt64, startTimeNanos);
-    return NO_ERROR;
-}
-
-status_t FrameTimelineInfo::read(const Parcel& input) {
-    SAFE_PARCEL(input.readInt64, &vsyncId);
-    SAFE_PARCEL(input.readInt32, &inputEventId);
-    SAFE_PARCEL(input.readInt64, &startTimeNanos);
-    return NO_ERROR;
-}
-
-void FrameTimelineInfo::merge(const FrameTimelineInfo& other) {
-    // When merging vsync Ids we take the oldest valid one
-    if (vsyncId != INVALID_VSYNC_ID && other.vsyncId != INVALID_VSYNC_ID) {
-        if (other.vsyncId > vsyncId) {
-            vsyncId = other.vsyncId;
-            inputEventId = other.inputEventId;
-            startTimeNanos = other.startTimeNanos;
-        }
-    } else if (vsyncId == INVALID_VSYNC_ID) {
-        vsyncId = other.vsyncId;
-        inputEventId = other.inputEventId;
-        startTimeNanos = other.startTimeNanos;
-    }
-}
-
-void FrameTimelineInfo::clear() {
-    vsyncId = INVALID_VSYNC_ID;
-    inputEventId = IInputConstants::INVALID_INPUT_EVENT_ID;
-    startTimeNanos = 0;
-}
-
-}; // namespace android
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 24d39fe..af64b3b 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -25,8 +25,6 @@
 #include <binder/Parcel.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/ISurfaceComposer.h>
-#include <gui/ISurfaceComposerClient.h>
-#include <gui/LayerDebugInfo.h>
 #include <gui/LayerState.h>
 #include <private/gui/ParcelUtils.h>
 #include <stdint.h>
@@ -37,7 +35,6 @@
 #include <ui/DisplayState.h>
 #include <ui/DynamicDisplayInfo.h>
 #include <ui/HdrCapabilities.h>
-#include <ui/StaticDisplayInfo.h>
 #include <utils/Log.h>
 
 // ---------------------------------------------------------------------------
@@ -63,14 +60,6 @@
 
     virtual ~BpSurfaceComposer();
 
-    virtual sp<ISurfaceComposerClient> createConnection()
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply);
-        return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
-    }
-
     status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
                                  const Vector<ComposerState>& state,
                                  const Vector<DisplayState>& displays, uint32_t flags,
@@ -82,7 +71,7 @@
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
 
-        SAFE_PARCEL(frameTimelineInfo.write, data);
+        frameTimelineInfo.writeToParcel(&data);
 
         SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(state.size()));
         for (const auto& s : state) {
@@ -119,905 +108,6 @@
                     data, &reply);
         }
     }
-
-    void bootFinished() override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
-    }
-
-    bool authenticateSurfaceTexture(
-            const sp<IGraphicBufferProducer>& bufferProducer) const override {
-        Parcel data, reply;
-        int err = NO_ERROR;
-        err = data.writeInterfaceToken(
-                ISurfaceComposer::getInterfaceDescriptor());
-        if (err != NO_ERROR) {
-            ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error writing "
-                    "interface descriptor: %s (%d)", strerror(-err), -err);
-            return false;
-        }
-        err = data.writeStrongBinder(IInterface::asBinder(bufferProducer));
-        if (err != NO_ERROR) {
-            ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error writing "
-                    "strong binder to parcel: %s (%d)", strerror(-err), -err);
-            return false;
-        }
-        err = remote()->transact(BnSurfaceComposer::AUTHENTICATE_SURFACE, data,
-                &reply);
-        if (err != NO_ERROR) {
-            ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error "
-                    "performing transaction: %s (%d)", strerror(-err), -err);
-            return false;
-        }
-        int32_t result = 0;
-        err = reply.readInt32(&result);
-        if (err != NO_ERROR) {
-            ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error "
-                    "retrieving result: %s (%d)", strerror(-err), -err);
-            return false;
-        }
-        return result != 0;
-    }
-
-    status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override {
-        if (!outSupported) {
-            return UNEXPECTED_NULL;
-        }
-        outSupported->clear();
-
-        Parcel data, reply;
-
-        status_t err = data.writeInterfaceToken(
-                ISurfaceComposer::getInterfaceDescriptor());
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        err = remote()->transact(
-                BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS,
-                data, &reply);
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        int32_t result = 0;
-        err = reply.readInt32(&result);
-        if (err != NO_ERROR) {
-            return err;
-        }
-        if (result != NO_ERROR) {
-            return result;
-        }
-
-        std::vector<int32_t> supported;
-        err = reply.readInt32Vector(&supported);
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        outSupported->reserve(supported.size());
-        for (int32_t s : supported) {
-            outSupported->push_back(static_cast<FrameEvent>(s));
-        }
-        return NO_ERROR;
-    }
-
-    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;
-    }
-
-    status_t getStaticDisplayInfo(const sp<IBinder>& display,
-                                  ui::StaticDisplayInfo* info) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-        remote()->transact(BnSurfaceComposer::GET_STATIC_DISPLAY_INFO, data, &reply);
-        const status_t result = reply.readInt32();
-        if (result != NO_ERROR) return result;
-        return reply.read(*info);
-    }
-
-    status_t getDynamicDisplayInfo(const sp<IBinder>& display,
-                                   ui::DynamicDisplayInfo* info) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-        remote()->transact(BnSurfaceComposer::GET_DYNAMIC_DISPLAY_INFO, data, &reply);
-        const status_t result = reply.readInt32();
-        if (result != NO_ERROR) return result;
-        return reply.read(*info);
-    }
-
-    status_t getDisplayNativePrimaries(const sp<IBinder>& display,
-                                       ui::DisplayPrimaries& primaries) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("getDisplayNativePrimaries failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("getDisplayNativePrimaries failed to writeStrongBinder: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_NATIVE_PRIMARIES, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("getDisplayNativePrimaries failed to transact: %d", result);
-            return result;
-        }
-        result = reply.readInt32();
-        if (result == NO_ERROR) {
-            memcpy(&primaries, reply.readInplace(sizeof(ui::DisplayPrimaries)),
-                    sizeof(ui::DisplayPrimaries));
-        }
-        return result;
-    }
-
-    status_t setActiveColorMode(const sp<IBinder>& display, ColorMode colorMode) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("setActiveColorMode failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("setActiveColorMode failed to writeStrongBinder: %d", result);
-            return result;
-        }
-        result = data.writeInt32(static_cast<int32_t>(colorMode));
-        if (result != NO_ERROR) {
-            ALOGE("setActiveColorMode failed to writeInt32: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::SET_ACTIVE_COLOR_MODE, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("setActiveColorMode failed to transact: %d", result);
-            return result;
-        }
-        return static_cast<status_t>(reply.readInt32());
-    }
-
-    status_t setBootDisplayMode(const sp<IBinder>& display,
-                                ui::DisplayModeId displayModeId) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("setBootDisplayMode failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("setBootDisplayMode failed to writeStrongBinder: %d", result);
-            return result;
-        }
-        result = data.writeInt32(displayModeId);
-        if (result != NO_ERROR) {
-            ALOGE("setBootDisplayMode failed to writeIint32: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::SET_BOOT_DISPLAY_MODE, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("setBootDisplayMode failed to transact: %d", result);
-        }
-        return result;
-    }
-
-    status_t clearAnimationFrameStats() override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("clearAnimationFrameStats failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("clearAnimationFrameStats failed to transact: %d", result);
-            return result;
-        }
-        return reply.readInt32();
-    }
-
-    status_t getAnimationFrameStats(FrameStats* outStats) const override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::GET_ANIMATION_FRAME_STATS, data, &reply);
-        reply.read(*outStats);
-        return reply.readInt32();
-    }
-
-    virtual status_t overrideHdrTypes(const sp<IBinder>& display,
-                                      const std::vector<ui::Hdr>& hdrTypes) {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeStrongBinder, display);
-
-        std::vector<int32_t> hdrTypesVector;
-        for (ui::Hdr i : hdrTypes) {
-            hdrTypesVector.push_back(static_cast<int32_t>(i));
-        }
-        SAFE_PARCEL(data.writeInt32Vector, hdrTypesVector);
-
-        status_t result = remote()->transact(BnSurfaceComposer::OVERRIDE_HDR_TYPES, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("overrideHdrTypes failed to transact: %d", result);
-            return result;
-        }
-        return result;
-    }
-
-    status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeInt32, atomId);
-
-        status_t err = remote()->transact(BnSurfaceComposer::ON_PULL_ATOM, data, &reply);
-        if (err != NO_ERROR) {
-            ALOGE("onPullAtom failed to transact: %d", err);
-            return err;
-        }
-
-        int32_t size = 0;
-        SAFE_PARCEL(reply.readInt32, &size);
-        const void* dataPtr = reply.readInplace(size);
-        if (dataPtr == nullptr) {
-            return UNEXPECTED_NULL;
-        }
-        pulledData->assign((const char*)dataPtr, size);
-        SAFE_PARCEL(reply.readBool, success);
-        return NO_ERROR;
-    }
-
-    status_t enableVSyncInjections(bool enable) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("enableVSyncInjections failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeBool(enable);
-        if (result != NO_ERROR) {
-            ALOGE("enableVSyncInjections failed to writeBool: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS, data, &reply,
-                                    IBinder::FLAG_ONEWAY);
-        if (result != NO_ERROR) {
-            ALOGE("enableVSyncInjections failed to transact: %d", result);
-            return result;
-        }
-        return result;
-    }
-
-    status_t injectVSync(nsecs_t when) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("injectVSync failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeInt64(when);
-        if (result != NO_ERROR) {
-            ALOGE("injectVSync failed to writeInt64: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::INJECT_VSYNC, data, &reply,
-                                    IBinder::FLAG_ONEWAY);
-        if (result != NO_ERROR) {
-            ALOGE("injectVSync failed to transact: %d", result);
-            return result;
-        }
-        return result;
-    }
-
-    status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override {
-        if (!outLayers) {
-            return UNEXPECTED_NULL;
-        }
-
-        Parcel data, reply;
-
-        status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        err = remote()->transact(BnSurfaceComposer::GET_LAYER_DEBUG_INFO, data, &reply);
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        int32_t result = 0;
-        err = reply.readInt32(&result);
-        if (err != NO_ERROR) {
-            return err;
-        }
-        if (result != NO_ERROR) {
-            return result;
-        }
-
-        outLayers->clear();
-        return reply.readParcelableVector(outLayers);
-    }
-
-    status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
-                                      ui::PixelFormat* defaultPixelFormat,
-                                      ui::Dataspace* wideColorGamutDataspace,
-                                      ui::PixelFormat* wideColorGamutPixelFormat) const override {
-        Parcel data, reply;
-        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (error != NO_ERROR) {
-            return error;
-        }
-        error = remote()->transact(BnSurfaceComposer::GET_COMPOSITION_PREFERENCE, data, &reply);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        error = static_cast<status_t>(reply.readInt32());
-        if (error == NO_ERROR) {
-            *defaultDataspace = static_cast<ui::Dataspace>(reply.readInt32());
-            *defaultPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
-            *wideColorGamutDataspace = static_cast<ui::Dataspace>(reply.readInt32());
-            *wideColorGamutPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
-        }
-        return error;
-    }
-
-    status_t getColorManagement(bool* outGetColorManagement) const override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::GET_COLOR_MANAGEMENT, data, &reply);
-        bool result;
-        status_t err = reply.readBool(&result);
-        if (err == NO_ERROR) {
-            *outGetColorManagement = result;
-        }
-        return err;
-    }
-
-    status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
-                                                   ui::PixelFormat* outFormat,
-                                                   ui::Dataspace* outDataspace,
-                                                   uint8_t* outComponentMask) const override {
-        if (!outFormat || !outDataspace || !outComponentMask) return BAD_VALUE;
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-
-        status_t error =
-                remote()->transact(BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
-                                   data, &reply);
-        if (error != NO_ERROR) {
-            return error;
-        }
-
-        uint32_t value = 0;
-        error = reply.readUint32(&value);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        *outFormat = static_cast<ui::PixelFormat>(value);
-
-        error = reply.readUint32(&value);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        *outDataspace = static_cast<ui::Dataspace>(value);
-
-        error = reply.readUint32(&value);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        *outComponentMask = static_cast<uint8_t>(value);
-        return error;
-    }
-
-    status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
-                                              uint8_t componentMask, uint64_t maxFrames) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-        data.writeBool(enable);
-        data.writeByte(static_cast<int8_t>(componentMask));
-        data.writeUint64(maxFrames);
-        status_t result =
-                remote()->transact(BnSurfaceComposer::SET_DISPLAY_CONTENT_SAMPLING_ENABLED, data,
-                                   &reply);
-        return result;
-    }
-
-    status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
-                                       uint64_t timestamp,
-                                       DisplayedFrameStats* outStats) const override {
-        if (!outStats) return BAD_VALUE;
-
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-        data.writeUint64(maxFrames);
-        data.writeUint64(timestamp);
-
-        status_t result =
-                remote()->transact(BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLE, data, &reply);
-
-        if (result != NO_ERROR) {
-            return result;
-        }
-
-        result = reply.readUint64(&outStats->numFrames);
-        if (result != NO_ERROR) {
-            return result;
-        }
-
-        result = reply.readUint64Vector(&outStats->component_0_sample);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        result = reply.readUint64Vector(&outStats->component_1_sample);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        result = reply.readUint64Vector(&outStats->component_2_sample);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        result = reply.readUint64Vector(&outStats->component_3_sample);
-        return result;
-    }
-
-    status_t getProtectedContentSupport(bool* outSupported) const override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        status_t error =
-                remote()->transact(BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT, data, &reply);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        error = reply.readBool(outSupported);
-        return error;
-    }
-
-    status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
-                                       const sp<IRegionSamplingListener>& listener) override {
-        Parcel data, reply;
-        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (error != NO_ERROR) {
-            ALOGE("addRegionSamplingListener: Failed to write interface token");
-            return error;
-        }
-        error = data.write(samplingArea);
-        if (error != NO_ERROR) {
-            ALOGE("addRegionSamplingListener: Failed to write sampling area");
-            return error;
-        }
-        error = data.writeStrongBinder(stopLayerHandle);
-        if (error != NO_ERROR) {
-            ALOGE("addRegionSamplingListener: Failed to write stop layer handle");
-            return error;
-        }
-        error = data.writeStrongBinder(IInterface::asBinder(listener));
-        if (error != NO_ERROR) {
-            ALOGE("addRegionSamplingListener: Failed to write listener");
-            return error;
-        }
-        error = remote()->transact(BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER, data, &reply);
-        if (error != NO_ERROR) {
-            ALOGE("addRegionSamplingListener: Failed to transact");
-        }
-        return error;
-    }
-
-    status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override {
-        Parcel data, reply;
-        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (error != NO_ERROR) {
-            ALOGE("removeRegionSamplingListener: Failed to write interface token");
-            return error;
-        }
-        error = data.writeStrongBinder(IInterface::asBinder(listener));
-        if (error != NO_ERROR) {
-            ALOGE("removeRegionSamplingListener: Failed to write listener");
-            return error;
-        }
-        error = remote()->transact(BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER, data,
-                                   &reply);
-        if (error != NO_ERROR) {
-            ALOGE("removeRegionSamplingListener: Failed to transact");
-        }
-        return error;
-    }
-
-    virtual status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeInt32, taskId);
-        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
-        const status_t error =
-                remote()->transact(BnSurfaceComposer::ADD_FPS_LISTENER, data, &reply);
-        if (error != OK) {
-            ALOGE("addFpsListener: Failed to transact");
-        }
-        return error;
-    }
-
-    virtual status_t removeFpsListener(const sp<gui::IFpsListener>& listener) {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
-
-        const status_t error =
-                remote()->transact(BnSurfaceComposer::REMOVE_FPS_LISTENER, data, &reply);
-        if (error != OK) {
-            ALOGE("removeFpsListener: Failed to transact");
-        }
-        return error;
-    }
-
-    virtual status_t addTunnelModeEnabledListener(
-            const sp<gui::ITunnelModeEnabledListener>& listener) {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
-
-        const status_t error =
-                remote()->transact(BnSurfaceComposer::ADD_TUNNEL_MODE_ENABLED_LISTENER, data,
-                                   &reply);
-        if (error != NO_ERROR) {
-            ALOGE("addTunnelModeEnabledListener: Failed to transact");
-        }
-        return error;
-    }
-
-    virtual status_t removeTunnelModeEnabledListener(
-            const sp<gui::ITunnelModeEnabledListener>& listener) {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
-
-        const status_t error =
-                remote()->transact(BnSurfaceComposer::REMOVE_TUNNEL_MODE_ENABLED_LISTENER, data,
-                                   &reply);
-        if (error != NO_ERROR) {
-            ALOGE("removeTunnelModeEnabledListener: Failed to transact");
-        }
-        return error;
-    }
-
-    status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
-                                        ui::DisplayModeId defaultMode, bool allowGroupSwitching,
-                                        float primaryRefreshRateMin, float primaryRefreshRateMax,
-                                        float appRequestRefreshRateMin,
-                                        float appRequestRefreshRateMax) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayModeSpecs: failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeStrongBinder(displayToken);
-        if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayModeSpecs: failed to write display token: %d", result);
-            return result;
-        }
-        result = data.writeInt32(defaultMode);
-        if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayModeSpecs failed to write defaultMode: %d", result);
-            return result;
-        }
-        result = data.writeBool(allowGroupSwitching);
-        if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayModeSpecs failed to write allowGroupSwitching: %d", result);
-            return result;
-        }
-        result = data.writeFloat(primaryRefreshRateMin);
-        if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayModeSpecs failed to write primaryRefreshRateMin: %d", result);
-            return result;
-        }
-        result = data.writeFloat(primaryRefreshRateMax);
-        if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayModeSpecs failed to write primaryRefreshRateMax: %d", result);
-            return result;
-        }
-        result = data.writeFloat(appRequestRefreshRateMin);
-        if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayModeSpecs failed to write appRequestRefreshRateMin: %d",
-                  result);
-            return result;
-        }
-        result = data.writeFloat(appRequestRefreshRateMax);
-        if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayModeSpecs failed to write appRequestRefreshRateMax: %d",
-                  result);
-            return result;
-        }
-
-        result =
-                remote()->transact(BnSurfaceComposer::SET_DESIRED_DISPLAY_MODE_SPECS, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayModeSpecs failed to transact: %d", result);
-            return result;
-        }
-        return reply.readInt32();
-    }
-
-    status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
-                                        ui::DisplayModeId* outDefaultMode,
-                                        bool* outAllowGroupSwitching,
-                                        float* outPrimaryRefreshRateMin,
-                                        float* outPrimaryRefreshRateMax,
-                                        float* outAppRequestRefreshRateMin,
-                                        float* outAppRequestRefreshRateMax) override {
-        if (!outDefaultMode || !outAllowGroupSwitching || !outPrimaryRefreshRateMin ||
-            !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin ||
-            !outAppRequestRefreshRateMax) {
-            return BAD_VALUE;
-        }
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayModeSpecs failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeStrongBinder(displayToken);
-        if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayModeSpecs failed to writeStrongBinder: %d", result);
-            return result;
-        }
-        result =
-                remote()->transact(BnSurfaceComposer::GET_DESIRED_DISPLAY_MODE_SPECS, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayModeSpecs failed to transact: %d", result);
-            return result;
-        }
-
-        result = reply.readInt32(outDefaultMode);
-        if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayModeSpecs failed to read defaultMode: %d", result);
-            return result;
-        }
-        if (*outDefaultMode < 0) {
-            ALOGE("%s: defaultMode must be non-negative but it was %d", __func__, *outDefaultMode);
-            return BAD_VALUE;
-        }
-
-        result = reply.readBool(outAllowGroupSwitching);
-        if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayModeSpecs failed to read allowGroupSwitching: %d", result);
-            return result;
-        }
-        result = reply.readFloat(outPrimaryRefreshRateMin);
-        if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayModeSpecs failed to read primaryRefreshRateMin: %d", result);
-            return result;
-        }
-        result = reply.readFloat(outPrimaryRefreshRateMax);
-        if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayModeSpecs failed to read primaryRefreshRateMax: %d", result);
-            return result;
-        }
-        result = reply.readFloat(outAppRequestRefreshRateMin);
-        if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayModeSpecs failed to read appRequestRefreshRateMin: %d", result);
-            return result;
-        }
-        result = reply.readFloat(outAppRequestRefreshRateMax);
-        if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayModeSpecs failed to read appRequestRefreshRateMax: %d", result);
-            return result;
-        }
-        return reply.readInt32();
-    }
-
-    status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
-                                     float lightPosY, float lightPosZ, float lightRadius) override {
-        Parcel data, reply;
-        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (error != NO_ERROR) {
-            ALOGE("setGlobalShadowSettings: failed to write interface token: %d", error);
-            return error;
-        }
-
-        std::vector<float> shadowConfig = {ambientColor.r, ambientColor.g, ambientColor.b,
-                                           ambientColor.a, spotColor.r,    spotColor.g,
-                                           spotColor.b,    spotColor.a,    lightPosY,
-                                           lightPosZ,      lightRadius};
-
-        error = data.writeFloatVector(shadowConfig);
-        if (error != NO_ERROR) {
-            ALOGE("setGlobalShadowSettings: failed to write shadowConfig: %d", error);
-            return error;
-        }
-
-        error = remote()->transact(BnSurfaceComposer::SET_GLOBAL_SHADOW_SETTINGS, data, &reply,
-                                   IBinder::FLAG_ONEWAY);
-        if (error != NO_ERROR) {
-            ALOGE("setGlobalShadowSettings: failed to transact: %d", error);
-            return error;
-        }
-        return NO_ERROR;
-    }
-
-    status_t getDisplayDecorationSupport(
-            const sp<IBinder>& displayToken,
-            std::optional<common::DisplayDecorationSupport>* outSupport) const override {
-        Parcel data, reply;
-        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (error != NO_ERROR) {
-            ALOGE("getDisplayDecorationSupport: failed to write interface token: %d", error);
-            return error;
-        }
-        error = data.writeStrongBinder(displayToken);
-        if (error != NO_ERROR) {
-            ALOGE("getDisplayDecorationSupport: failed to write display token: %d", error);
-            return error;
-        }
-        error = remote()->transact(BnSurfaceComposer::GET_DISPLAY_DECORATION_SUPPORT, data, &reply);
-        if (error != NO_ERROR) {
-            ALOGE("getDisplayDecorationSupport: failed to transact: %d", error);
-            return error;
-        }
-        bool support;
-        error = reply.readBool(&support);
-        if (error != NO_ERROR) {
-            ALOGE("getDisplayDecorationSupport: failed to read support: %d", error);
-            return error;
-        }
-
-        if (support) {
-            int32_t format, alphaInterpretation;
-            error = reply.readInt32(&format);
-            if (error != NO_ERROR) {
-                ALOGE("getDisplayDecorationSupport: failed to read format: %d", error);
-                return error;
-            }
-            error = reply.readInt32(&alphaInterpretation);
-            if (error != NO_ERROR) {
-                ALOGE("getDisplayDecorationSupport: failed to read alphaInterpretation: %d", error);
-                return error;
-            }
-            outSupport->emplace();
-            outSupport->value().format = static_cast<common::PixelFormat>(format);
-            outSupport->value().alphaInterpretation =
-                    static_cast<common::AlphaInterpretation>(alphaInterpretation);
-        } else {
-            outSupport->reset();
-        }
-        return NO_ERROR;
-    }
-
-    status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
-                          int8_t compatibility, int8_t changeFrameRateStrategy) override {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(surface));
-        SAFE_PARCEL(data.writeFloat, frameRate);
-        SAFE_PARCEL(data.writeByte, compatibility);
-        SAFE_PARCEL(data.writeByte, changeFrameRateStrategy);
-
-        status_t err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply);
-        if (err != NO_ERROR) {
-            ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err);
-            return err;
-        }
-
-        return reply.readInt32();
-    }
-
-    status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface,
-                                  const FrameTimelineInfo& frameTimelineInfo) override {
-        Parcel data, reply;
-        status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (err != NO_ERROR) {
-            ALOGE("%s: failed writing interface token: %s (%d)", __func__, strerror(-err), -err);
-            return err;
-        }
-
-        err = data.writeStrongBinder(IInterface::asBinder(surface));
-        if (err != NO_ERROR) {
-            ALOGE("%s: failed writing strong binder: %s (%d)", __func__, strerror(-err), -err);
-            return err;
-        }
-
-        SAFE_PARCEL(frameTimelineInfo.write, data);
-
-        err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_INFO, data, &reply);
-        if (err != NO_ERROR) {
-            ALOGE("%s: failed to transact: %s (%d)", __func__, strerror(-err), err);
-            return err;
-        }
-
-        return reply.readInt32();
-    }
-
-    status_t addTransactionTraceListener(
-            const sp<gui::ITransactionTraceListener>& listener) override {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
-
-        return remote()->transact(BnSurfaceComposer::ADD_TRANSACTION_TRACE_LISTENER, data, &reply);
-    }
-
-    /**
-     * Get priority of the RenderEngine in surface flinger.
-     */
-    int getGPUContextPriority() override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        status_t err =
-                remote()->transact(BnSurfaceComposer::GET_GPU_CONTEXT_PRIORITY, data, &reply);
-        if (err != NO_ERROR) {
-            ALOGE("getGPUContextPriority failed to read data:  %s (%d)", strerror(-err), err);
-            return 0;
-        }
-        return reply.readInt32();
-    }
-
-    status_t getMaxAcquiredBufferCount(int* buffers) const override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        status_t err =
-                remote()->transact(BnSurfaceComposer::GET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply);
-        if (err != NO_ERROR) {
-            ALOGE("getMaxAcquiredBufferCount failed to read data:  %s (%d)", strerror(-err), err);
-            return err;
-        }
-
-        return reply.readInt32(buffers);
-    }
-
-    status_t addWindowInfosListener(
-            const sp<IWindowInfosListener>& windowInfosListener) const override {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener));
-        return remote()->transact(BnSurfaceComposer::ADD_WINDOW_INFOS_LISTENER, data, &reply);
-    }
-
-    status_t removeWindowInfosListener(
-            const sp<IWindowInfosListener>& windowInfosListener) const override {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener));
-        return remote()->transact(BnSurfaceComposer::REMOVE_WINDOW_INFOS_LISTENER, data, &reply);
-    }
-
-    status_t setOverrideFrameRate(uid_t uid, float frameRate) override {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeUint32, uid);
-        SAFE_PARCEL(data.writeFloat, frameRate);
-
-        status_t err = remote()->transact(BnSurfaceComposer::SET_OVERRIDE_FRAME_RATE, data, &reply);
-        if (err != NO_ERROR) {
-            ALOGE("setOverrideFrameRate: failed to transact %s (%d)", strerror(-err), err);
-            return err;
-        }
-
-        return NO_ERROR;
-    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -1031,18 +121,12 @@
 status_t BnSurfaceComposer::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
-    switch(code) {
-        case CREATE_CONNECTION: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> b = IInterface::asBinder(createConnection());
-            reply->writeStrongBinder(b);
-            return NO_ERROR;
-        }
+    switch (code) {
         case SET_TRANSACTION_STATE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
 
             FrameTimelineInfo frameTimelineInfo;
-            SAFE_PARCEL(frameTimelineInfo.read, data);
+            frameTimelineInfo.readFromParcel(&data);
 
             uint32_t count = 0;
             SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize());
@@ -1102,642 +186,6 @@
                                        uncachedBuffer, hasListenerCallbacks, listenerCallbacks,
                                        transactionId);
         }
-        case BOOT_FINISHED: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            bootFinished();
-            return NO_ERROR;
-        }
-        case AUTHENTICATE_SURFACE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IGraphicBufferProducer> bufferProducer =
-                    interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
-            int32_t result = authenticateSurfaceTexture(bufferProducer) ? 1 : 0;
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case GET_SUPPORTED_FRAME_TIMESTAMPS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            std::vector<FrameEvent> supportedTimestamps;
-            status_t result = getSupportedFrameTimestamps(&supportedTimestamps);
-            status_t err = reply->writeInt32(result);
-            if (err != NO_ERROR) {
-                return err;
-            }
-            if (result != NO_ERROR) {
-                return result;
-            }
-
-            std::vector<int32_t> supported;
-            supported.reserve(supportedTimestamps.size());
-            for (FrameEvent s : supportedTimestamps) {
-                supported.push_back(static_cast<int32_t>(s));
-            }
-            return reply->writeInt32Vector(supported);
-        }
-        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;
-        }
-        case GET_STATIC_DISPLAY_INFO: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            ui::StaticDisplayInfo info;
-            const sp<IBinder> display = data.readStrongBinder();
-            const status_t result = getStaticDisplayInfo(display, &info);
-            SAFE_PARCEL(reply->writeInt32, result);
-            if (result != NO_ERROR) return result;
-            SAFE_PARCEL(reply->write, info);
-            return NO_ERROR;
-        }
-        case GET_DYNAMIC_DISPLAY_INFO: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            ui::DynamicDisplayInfo info;
-            const sp<IBinder> display = data.readStrongBinder();
-            const status_t result = getDynamicDisplayInfo(display, &info);
-            SAFE_PARCEL(reply->writeInt32, result);
-            if (result != NO_ERROR) return result;
-            SAFE_PARCEL(reply->write, info);
-            return NO_ERROR;
-        }
-        case GET_DISPLAY_NATIVE_PRIMARIES: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            ui::DisplayPrimaries primaries;
-            sp<IBinder> display = nullptr;
-
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("getDisplayNativePrimaries failed to readStrongBinder: %d", result);
-                return result;
-            }
-
-            result = getDisplayNativePrimaries(display, primaries);
-            reply->writeInt32(result);
-            if (result == NO_ERROR) {
-                memcpy(reply->writeInplace(sizeof(ui::DisplayPrimaries)), &primaries,
-                        sizeof(ui::DisplayPrimaries));
-            }
-
-            return NO_ERROR;
-        }
-        case SET_ACTIVE_COLOR_MODE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = nullptr;
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("getActiveColorMode failed to readStrongBinder: %d", result);
-                return result;
-            }
-            int32_t colorModeInt = 0;
-            result = data.readInt32(&colorModeInt);
-            if (result != NO_ERROR) {
-                ALOGE("setActiveColorMode failed to readInt32: %d", result);
-                return result;
-            }
-            result = setActiveColorMode(display,
-                    static_cast<ColorMode>(colorModeInt));
-            result = reply->writeInt32(result);
-            return result;
-        }
-        case SET_BOOT_DISPLAY_MODE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = nullptr;
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("setBootDisplayMode failed to readStrongBinder: %d", result);
-                return result;
-            }
-            ui::DisplayModeId displayModeId;
-            result = data.readInt32(&displayModeId);
-            if (result != NO_ERROR) {
-                ALOGE("setBootDisplayMode failed to readInt32: %d", result);
-                return result;
-            }
-            return setBootDisplayMode(display, displayModeId);
-        }
-        case CLEAR_ANIMATION_FRAME_STATS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            status_t result = clearAnimationFrameStats();
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case GET_ANIMATION_FRAME_STATS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            FrameStats stats;
-            status_t result = getAnimationFrameStats(&stats);
-            reply->write(stats);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case ENABLE_VSYNC_INJECTIONS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            bool enable = false;
-            status_t result = data.readBool(&enable);
-            if (result != NO_ERROR) {
-                ALOGE("enableVSyncInjections failed to readBool: %d", result);
-                return result;
-            }
-            return enableVSyncInjections(enable);
-        }
-        case INJECT_VSYNC: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            int64_t when = 0;
-            status_t result = data.readInt64(&when);
-            if (result != NO_ERROR) {
-                ALOGE("enableVSyncInjections failed to readInt64: %d", result);
-                return result;
-            }
-            return injectVSync(when);
-        }
-        case GET_LAYER_DEBUG_INFO: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            std::vector<LayerDebugInfo> outLayers;
-            status_t result = getLayerDebugInfo(&outLayers);
-            reply->writeInt32(result);
-            if (result == NO_ERROR)
-            {
-                result = reply->writeParcelableVector(outLayers);
-            }
-            return result;
-        }
-        case GET_COMPOSITION_PREFERENCE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            ui::Dataspace defaultDataspace;
-            ui::PixelFormat defaultPixelFormat;
-            ui::Dataspace wideColorGamutDataspace;
-            ui::PixelFormat wideColorGamutPixelFormat;
-            status_t error =
-                    getCompositionPreference(&defaultDataspace, &defaultPixelFormat,
-                                             &wideColorGamutDataspace, &wideColorGamutPixelFormat);
-            reply->writeInt32(error);
-            if (error == NO_ERROR) {
-                reply->writeInt32(static_cast<int32_t>(defaultDataspace));
-                reply->writeInt32(static_cast<int32_t>(defaultPixelFormat));
-                reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
-                reply->writeInt32(static_cast<int32_t>(wideColorGamutPixelFormat));
-            }
-            return error;
-        }
-        case GET_COLOR_MANAGEMENT: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            bool result;
-            status_t error = getColorManagement(&result);
-            if (error == NO_ERROR) {
-                reply->writeBool(result);
-            }
-            return error;
-        }
-        case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-
-            sp<IBinder> display = data.readStrongBinder();
-            ui::PixelFormat format;
-            ui::Dataspace dataspace;
-            uint8_t component = 0;
-            auto result =
-                    getDisplayedContentSamplingAttributes(display, &format, &dataspace, &component);
-            if (result == NO_ERROR) {
-                reply->writeUint32(static_cast<uint32_t>(format));
-                reply->writeUint32(static_cast<uint32_t>(dataspace));
-                reply->writeUint32(static_cast<uint32_t>(component));
-            }
-            return result;
-        }
-        case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-
-            sp<IBinder> display = nullptr;
-            bool enable = false;
-            int8_t componentMask = 0;
-            uint64_t maxFrames = 0;
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("setDisplayContentSamplingEnabled failure in reading Display token: %d",
-                      result);
-                return result;
-            }
-
-            result = data.readBool(&enable);
-            if (result != NO_ERROR) {
-                ALOGE("setDisplayContentSamplingEnabled failure in reading enable: %d", result);
-                return result;
-            }
-
-            result = data.readByte(static_cast<int8_t*>(&componentMask));
-            if (result != NO_ERROR) {
-                ALOGE("setDisplayContentSamplingEnabled failure in reading component mask: %d",
-                      result);
-                return result;
-            }
-
-            result = data.readUint64(&maxFrames);
-            if (result != NO_ERROR) {
-                ALOGE("setDisplayContentSamplingEnabled failure in reading max frames: %d", result);
-                return result;
-            }
-
-            return setDisplayContentSamplingEnabled(display, enable,
-                                                    static_cast<uint8_t>(componentMask), maxFrames);
-        }
-        case GET_DISPLAYED_CONTENT_SAMPLE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-
-            sp<IBinder> display = data.readStrongBinder();
-            uint64_t maxFrames = 0;
-            uint64_t timestamp = 0;
-
-            status_t result = data.readUint64(&maxFrames);
-            if (result != NO_ERROR) {
-                ALOGE("getDisplayedContentSample failure in reading max frames: %d", result);
-                return result;
-            }
-
-            result = data.readUint64(&timestamp);
-            if (result != NO_ERROR) {
-                ALOGE("getDisplayedContentSample failure in reading timestamp: %d", result);
-                return result;
-            }
-
-            DisplayedFrameStats stats;
-            result = getDisplayedContentSample(display, maxFrames, timestamp, &stats);
-            if (result == NO_ERROR) {
-                reply->writeUint64(stats.numFrames);
-                reply->writeUint64Vector(stats.component_0_sample);
-                reply->writeUint64Vector(stats.component_1_sample);
-                reply->writeUint64Vector(stats.component_2_sample);
-                reply->writeUint64Vector(stats.component_3_sample);
-            }
-            return result;
-        }
-        case GET_PROTECTED_CONTENT_SUPPORT: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            bool result;
-            status_t error = getProtectedContentSupport(&result);
-            if (error == NO_ERROR) {
-                reply->writeBool(result);
-            }
-            return error;
-        }
-        case ADD_REGION_SAMPLING_LISTENER: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            Rect samplingArea;
-            status_t result = data.read(samplingArea);
-            if (result != NO_ERROR) {
-                ALOGE("addRegionSamplingListener: Failed to read sampling area");
-                return result;
-            }
-            sp<IBinder> stopLayerHandle;
-            result = data.readNullableStrongBinder(&stopLayerHandle);
-            if (result != NO_ERROR) {
-                ALOGE("addRegionSamplingListener: Failed to read stop layer handle");
-                return result;
-            }
-            sp<IRegionSamplingListener> listener;
-            result = data.readNullableStrongBinder(&listener);
-            if (result != NO_ERROR) {
-                ALOGE("addRegionSamplingListener: Failed to read listener");
-                return result;
-            }
-            return addRegionSamplingListener(samplingArea, stopLayerHandle, listener);
-        }
-        case REMOVE_REGION_SAMPLING_LISTENER: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IRegionSamplingListener> listener;
-            status_t result = data.readNullableStrongBinder(&listener);
-            if (result != NO_ERROR) {
-                ALOGE("removeRegionSamplingListener: Failed to read listener");
-                return result;
-            }
-            return removeRegionSamplingListener(listener);
-        }
-        case ADD_FPS_LISTENER: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            int32_t taskId;
-            status_t result = data.readInt32(&taskId);
-            if (result != NO_ERROR) {
-                ALOGE("addFpsListener: Failed to read layer handle");
-                return result;
-            }
-            sp<gui::IFpsListener> listener;
-            result = data.readNullableStrongBinder(&listener);
-            if (result != NO_ERROR) {
-                ALOGE("addFpsListener: Failed to read listener");
-                return result;
-            }
-            return addFpsListener(taskId, listener);
-        }
-        case REMOVE_FPS_LISTENER: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<gui::IFpsListener> listener;
-            status_t result = data.readNullableStrongBinder(&listener);
-            if (result != NO_ERROR) {
-                ALOGE("removeFpsListener: Failed to read listener");
-                return result;
-            }
-            return removeFpsListener(listener);
-        }
-        case ADD_TUNNEL_MODE_ENABLED_LISTENER: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<gui::ITunnelModeEnabledListener> listener;
-            status_t result = data.readNullableStrongBinder(&listener);
-            if (result != NO_ERROR) {
-                ALOGE("addTunnelModeEnabledListener: Failed to read listener");
-                return result;
-            }
-            return addTunnelModeEnabledListener(listener);
-        }
-        case REMOVE_TUNNEL_MODE_ENABLED_LISTENER: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<gui::ITunnelModeEnabledListener> listener;
-            status_t result = data.readNullableStrongBinder(&listener);
-            if (result != NO_ERROR) {
-                ALOGE("removeTunnelModeEnabledListener: Failed to read listener");
-                return result;
-            }
-            return removeTunnelModeEnabledListener(listener);
-        }
-        case SET_DESIRED_DISPLAY_MODE_SPECS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> displayToken = data.readStrongBinder();
-            ui::DisplayModeId defaultMode;
-            status_t result = data.readInt32(&defaultMode);
-            if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayModeSpecs: failed to read defaultMode: %d", result);
-                return result;
-            }
-            if (defaultMode < 0) {
-                ALOGE("%s: defaultMode must be non-negative but it was %d", __func__, defaultMode);
-                return BAD_VALUE;
-            }
-            bool allowGroupSwitching;
-            result = data.readBool(&allowGroupSwitching);
-            if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayModeSpecs: failed to read allowGroupSwitching: %d", result);
-                return result;
-            }
-            float primaryRefreshRateMin;
-            result = data.readFloat(&primaryRefreshRateMin);
-            if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayModeSpecs: failed to read primaryRefreshRateMin: %d",
-                      result);
-                return result;
-            }
-            float primaryRefreshRateMax;
-            result = data.readFloat(&primaryRefreshRateMax);
-            if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayModeSpecs: failed to read primaryRefreshRateMax: %d",
-                      result);
-                return result;
-            }
-            float appRequestRefreshRateMin;
-            result = data.readFloat(&appRequestRefreshRateMin);
-            if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayModeSpecs: failed to read appRequestRefreshRateMin: %d",
-                      result);
-                return result;
-            }
-            float appRequestRefreshRateMax;
-            result = data.readFloat(&appRequestRefreshRateMax);
-            if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayModeSpecs: failed to read appRequestRefreshRateMax: %d",
-                      result);
-                return result;
-            }
-            result = setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching,
-                                                primaryRefreshRateMin, primaryRefreshRateMax,
-                                                appRequestRefreshRateMin, appRequestRefreshRateMax);
-            if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayModeSpecs: failed to call setDesiredDisplayModeSpecs: "
-                      "%d",
-                      result);
-                return result;
-            }
-            reply->writeInt32(result);
-            return result;
-        }
-        case GET_DESIRED_DISPLAY_MODE_SPECS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> displayToken = data.readStrongBinder();
-            ui::DisplayModeId defaultMode;
-            bool allowGroupSwitching;
-            float primaryRefreshRateMin;
-            float primaryRefreshRateMax;
-            float appRequestRefreshRateMin;
-            float appRequestRefreshRateMax;
-
-            status_t result =
-                    getDesiredDisplayModeSpecs(displayToken, &defaultMode, &allowGroupSwitching,
-                                               &primaryRefreshRateMin, &primaryRefreshRateMax,
-                                               &appRequestRefreshRateMin,
-                                               &appRequestRefreshRateMax);
-            if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayModeSpecs: failed to get getDesiredDisplayModeSpecs: "
-                      "%d",
-                      result);
-                return result;
-            }
-
-            result = reply->writeInt32(defaultMode);
-            if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayModeSpecs: failed to write defaultMode: %d", result);
-                return result;
-            }
-            result = reply->writeBool(allowGroupSwitching);
-            if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayModeSpecs: failed to write allowGroupSwitching: %d",
-                      result);
-                return result;
-            }
-            result = reply->writeFloat(primaryRefreshRateMin);
-            if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayModeSpecs: failed to write primaryRefreshRateMin: %d",
-                      result);
-                return result;
-            }
-            result = reply->writeFloat(primaryRefreshRateMax);
-            if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayModeSpecs: failed to write primaryRefreshRateMax: %d",
-                      result);
-                return result;
-            }
-            result = reply->writeFloat(appRequestRefreshRateMin);
-            if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayModeSpecs: failed to write appRequestRefreshRateMin: %d",
-                      result);
-                return result;
-            }
-            result = reply->writeFloat(appRequestRefreshRateMax);
-            if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayModeSpecs: failed to write appRequestRefreshRateMax: %d",
-                      result);
-                return result;
-            }
-            reply->writeInt32(result);
-            return result;
-        }
-        case SET_GLOBAL_SHADOW_SETTINGS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-
-            std::vector<float> shadowConfig;
-            status_t error = data.readFloatVector(&shadowConfig);
-            if (error != NO_ERROR || shadowConfig.size() != 11) {
-                ALOGE("setGlobalShadowSettings: failed to read shadowConfig: %d", error);
-                return error;
-            }
-
-            half4 ambientColor = {shadowConfig[0], shadowConfig[1], shadowConfig[2],
-                                  shadowConfig[3]};
-            half4 spotColor = {shadowConfig[4], shadowConfig[5], shadowConfig[6], shadowConfig[7]};
-            float lightPosY = shadowConfig[8];
-            float lightPosZ = shadowConfig[9];
-            float lightRadius = shadowConfig[10];
-            return setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ,
-                                           lightRadius);
-        }
-        case GET_DISPLAY_DECORATION_SUPPORT: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> displayToken;
-            SAFE_PARCEL(data.readNullableStrongBinder, &displayToken);
-            std::optional<common::DisplayDecorationSupport> support;
-            auto error = getDisplayDecorationSupport(displayToken, &support);
-            if (error != NO_ERROR) {
-                ALOGE("getDisplayDecorationSupport failed with error %d", error);
-                return error;
-            }
-            reply->writeBool(support.has_value());
-            if (support) {
-                reply->writeInt32(static_cast<int32_t>(support.value().format));
-                reply->writeInt32(static_cast<int32_t>(support.value().alphaInterpretation));
-            }
-            return error;
-        }
-        case SET_FRAME_RATE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> binder;
-            SAFE_PARCEL(data.readStrongBinder, &binder);
-
-            sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(binder);
-            if (!surface) {
-                ALOGE("setFrameRate: failed to cast to IGraphicBufferProducer");
-                return BAD_VALUE;
-            }
-            float frameRate;
-            SAFE_PARCEL(data.readFloat, &frameRate);
-
-            int8_t compatibility;
-            SAFE_PARCEL(data.readByte, &compatibility);
-
-            int8_t changeFrameRateStrategy;
-            SAFE_PARCEL(data.readByte, &changeFrameRateStrategy);
-
-            status_t result =
-                    setFrameRate(surface, frameRate, compatibility, changeFrameRateStrategy);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case SET_FRAME_TIMELINE_INFO: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> binder;
-            status_t err = data.readStrongBinder(&binder);
-            if (err != NO_ERROR) {
-                ALOGE("setFrameTimelineInfo: failed to read strong binder: %s (%d)", strerror(-err),
-                      -err);
-                return err;
-            }
-            sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(binder);
-            if (!surface) {
-                ALOGE("setFrameTimelineInfo: failed to cast to IGraphicBufferProducer: %s (%d)",
-                      strerror(-err), -err);
-                return err;
-            }
-
-            FrameTimelineInfo frameTimelineInfo;
-            SAFE_PARCEL(frameTimelineInfo.read, data);
-
-            status_t result = setFrameTimelineInfo(surface, frameTimelineInfo);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case ADD_TRANSACTION_TRACE_LISTENER: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<gui::ITransactionTraceListener> listener;
-            SAFE_PARCEL(data.readStrongBinder, &listener);
-
-            return addTransactionTraceListener(listener);
-        }
-        case GET_GPU_CONTEXT_PRIORITY: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            int priority = getGPUContextPriority();
-            SAFE_PARCEL(reply->writeInt32, priority);
-            return NO_ERROR;
-        }
-        case GET_MAX_ACQUIRED_BUFFER_COUNT: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            int buffers = 0;
-            int err = getMaxAcquiredBufferCount(&buffers);
-            if (err != NO_ERROR) {
-                return err;
-            }
-            SAFE_PARCEL(reply->writeInt32, buffers);
-            return NO_ERROR;
-        }
-        case OVERRIDE_HDR_TYPES: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = nullptr;
-            SAFE_PARCEL(data.readStrongBinder, &display);
-
-            std::vector<int32_t> hdrTypes;
-            SAFE_PARCEL(data.readInt32Vector, &hdrTypes);
-
-            std::vector<ui::Hdr> hdrTypesVector;
-            for (int i : hdrTypes) {
-                hdrTypesVector.push_back(static_cast<ui::Hdr>(i));
-            }
-            return overrideHdrTypes(display, hdrTypesVector);
-        }
-        case ON_PULL_ATOM: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            int32_t atomId = 0;
-            SAFE_PARCEL(data.readInt32, &atomId);
-
-            std::string pulledData;
-            bool success;
-            status_t err = onPullAtom(atomId, &pulledData, &success);
-            SAFE_PARCEL(reply->writeByteArray, pulledData.size(),
-                        reinterpret_cast<const uint8_t*>(pulledData.data()));
-            SAFE_PARCEL(reply->writeBool, success);
-            return err;
-        }
-        case ADD_WINDOW_INFOS_LISTENER: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IWindowInfosListener> listener;
-            SAFE_PARCEL(data.readStrongBinder, &listener);
-
-            return addWindowInfosListener(listener);
-        }
-        case REMOVE_WINDOW_INFOS_LISTENER: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IWindowInfosListener> listener;
-            SAFE_PARCEL(data.readStrongBinder, &listener);
-
-            return removeWindowInfosListener(listener);
-        }
-        case SET_OVERRIDE_FRAME_RATE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-
-            uid_t uid;
-            SAFE_PARCEL(data.readUint32, &uid);
-
-            float frameRate;
-            SAFE_PARCEL(data.readFloat, &frameRate);
-
-            return setOverrideFrameRate(uid, frameRate);
-        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
deleted file mode 100644
index 5e7a7ec..0000000
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ /dev/null
@@ -1,124 +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.
- */
-
-// tag as surfaceflinger
-#define LOG_TAG "SurfaceFlinger"
-
-#include <gui/ISurfaceComposerClient.h>
-
-#include <gui/IGraphicBufferProducer.h>
-
-#include <binder/SafeInterface.h>
-
-#include <ui/FrameStats.h>
-
-namespace android {
-
-namespace { // Anonymous
-
-enum class Tag : uint32_t {
-    CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
-    CREATE_WITH_SURFACE_PARENT,
-    CLEAR_LAYER_FRAME_STATS,
-    GET_LAYER_FRAME_STATS,
-    MIRROR_SURFACE,
-    LAST = MIRROR_SURFACE,
-};
-
-} // Anonymous namespace
-
-class BpSurfaceComposerClient : public SafeBpInterface<ISurfaceComposerClient> {
-public:
-    explicit BpSurfaceComposerClient(const sp<IBinder>& impl)
-          : SafeBpInterface<ISurfaceComposerClient>(impl, "BpSurfaceComposerClient") {}
-
-    ~BpSurfaceComposerClient() override;
-
-    status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format,
-                           uint32_t flags, const sp<IBinder>& parent, LayerMetadata metadata,
-                           sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp,
-                           int32_t* outLayerId, uint32_t* outTransformHint) override {
-        return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE,
-                                                                            name, width, height,
-                                                                            format, flags, parent,
-                                                                            std::move(metadata),
-                                                                            handle, gbp, outLayerId,
-                                                                            outTransformHint);
-    }
-
-    status_t createWithSurfaceParent(const String8& name, uint32_t width, uint32_t height,
-                                     PixelFormat format, uint32_t flags,
-                                     const sp<IGraphicBufferProducer>& parent,
-                                     LayerMetadata metadata, sp<IBinder>* handle,
-                                     sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId,
-                                     uint32_t* outTransformHint) override {
-        return callRemote<decltype(
-                &ISurfaceComposerClient::createWithSurfaceParent)>(Tag::CREATE_WITH_SURFACE_PARENT,
-                                                                   name, width, height, format,
-                                                                   flags, parent,
-                                                                   std::move(metadata), handle, gbp,
-                                                                   outLayerId, outTransformHint);
-    }
-
-    status_t clearLayerFrameStats(const sp<IBinder>& handle) const override {
-        return callRemote<decltype(
-                &ISurfaceComposerClient::clearLayerFrameStats)>(Tag::CLEAR_LAYER_FRAME_STATS,
-                                                                handle);
-    }
-
-    status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const override {
-        return callRemote<decltype(
-                &ISurfaceComposerClient::getLayerFrameStats)>(Tag::GET_LAYER_FRAME_STATS, handle,
-                                                              outStats);
-    }
-
-    status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,
-                           int32_t* outLayerId) override {
-        return callRemote<decltype(&ISurfaceComposerClient::mirrorSurface)>(Tag::MIRROR_SURFACE,
-                                                                            mirrorFromHandle,
-                                                                            outHandle, outLayerId);
-    }
-};
-
-// Out-of-line virtual method definition to trigger vtable emission in this
-// translation unit (see clang warning -Wweak-vtables)
-BpSurfaceComposerClient::~BpSurfaceComposerClient() {}
-
-IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient");
-
-// ----------------------------------------------------------------------
-
-status_t BnSurfaceComposerClient::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-                                             uint32_t flags) {
-    if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
-        return BBinder::onTransact(code, data, reply, flags);
-    }
-    auto tag = static_cast<Tag>(code);
-    switch (tag) {
-        case Tag::CREATE_SURFACE:
-            return callLocal(data, reply, &ISurfaceComposerClient::createSurface);
-        case Tag::CREATE_WITH_SURFACE_PARENT:
-            return callLocal(data, reply, &ISurfaceComposerClient::createWithSurfaceParent);
-        case Tag::CLEAR_LAYER_FRAME_STATS:
-            return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
-        case Tag::GET_LAYER_FRAME_STATS:
-            return callLocal(data, reply, &ISurfaceComposerClient::getLayerFrameStats);
-        case Tag::MIRROR_SURFACE:
-            return callLocal(data, reply, &ISurfaceComposerClient::mirrorSurface);
-    }
-}
-
-} // namespace android
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
index ea5fb29..15b2221 100644
--- a/libs/gui/LayerDebugInfo.cpp
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -27,7 +27,7 @@
 
 #define RETURN_ON_ERROR(X) do {status_t res = (X); if (res != NO_ERROR) return res;} while(false)
 
-namespace android {
+namespace android::gui {
 
 status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const {
     RETURN_ON_ERROR(parcel->writeCString(mName.c_str()));
@@ -149,4 +149,4 @@
     return result;
 }
 
-} // android
+} // namespace android::gui
diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp
index 189d51a..4e12fd3 100644
--- a/libs/gui/LayerMetadata.cpp
+++ b/libs/gui/LayerMetadata.cpp
@@ -23,7 +23,7 @@
 
 using android::base::StringPrintf;
 
-namespace android {
+namespace android::gui {
 
 LayerMetadata::LayerMetadata() = default;
 
@@ -144,4 +144,4 @@
     }
 }
 
-} // namespace android
+} // namespace android::gui
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 502031c..bb66085 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -19,10 +19,10 @@
 #include <cinttypes>
 #include <cmath>
 
+#include <android/gui/ISurfaceComposerClient.h>
 #include <android/native_window.h>
 #include <binder/Parcel.h>
 #include <gui/IGraphicBufferProducer.h>
-#include <gui/ISurfaceComposerClient.h>
 #include <gui/LayerState.h>
 #include <private/gui/ParcelUtils.h>
 #include <system/window.h>
@@ -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/Surface.cpp b/libs/gui/Surface.cpp
index 54b6d6a..e8aac2f 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -39,6 +39,7 @@
 #include <ui/GraphicBuffer.h>
 #include <ui/Region.h>
 
+#include <gui/AidlStatusUtil.h>
 #include <gui/BufferItem.h>
 #include <gui/IProducerListener.h>
 
@@ -49,6 +50,7 @@
 
 namespace android {
 
+using gui::aidl_utils::statusTFromBinderStatus;
 using ui::Dataspace;
 
 namespace {
@@ -182,7 +184,7 @@
     gui::DisplayStatInfo stats;
     binder::Status status = composerServiceAIDL()->getDisplayStats(nullptr, &stats);
     if (!status.isOk()) {
-        return status.transactionError();
+        return statusTFromBinderStatus(status);
     }
 
     *outRefreshDuration = stats.vsyncPeriod;
@@ -355,7 +357,7 @@
 
     *supported = false;
     binder::Status status = composerServiceAIDL()->isWideColorDisplay(display, supported);
-    return status.transactionError();
+    return statusTFromBinderStatus(status);
 }
 
 status_t Surface::getHdrSupport(bool* supported) {
@@ -366,12 +368,13 @@
         return NAME_NOT_FOUND;
     }
 
-    ui::DynamicDisplayInfo info;
-    if (status_t err = composerService()->getDynamicDisplayInfo(display, &info); err != NO_ERROR) {
-        return err;
+    gui::DynamicDisplayInfo info;
+    if (binder::Status status = composerServiceAIDL()->getDynamicDisplayInfo(display, &info);
+        !status.isOk()) {
+        return statusTFromBinderStatus(status);
     }
 
-    *supported = !info.hdrCapabilities.getSupportedHdrTypes().empty();
+    *supported = !info.hdrCapabilities.supportedHdrTypes.empty();
     return NO_ERROR;
 }
 
@@ -1256,10 +1259,10 @@
     mQueriedSupportedTimestamps = true;
 
     std::vector<FrameEvent> supportedFrameTimestamps;
-    status_t err = composerService()->getSupportedFrameTimestamps(
-            &supportedFrameTimestamps);
+    binder::Status status =
+            composerServiceAIDL()->getSupportedFrameTimestamps(&supportedFrameTimestamps);
 
-    if (err != NO_ERROR) {
+    if (!status.isOk()) {
         return;
     }
 
@@ -1287,15 +1290,12 @@
                 if (err == NO_ERROR) {
                     return NO_ERROR;
                 }
-                sp<ISurfaceComposer> surfaceComposer = composerService();
+                sp<gui::ISurfaceComposer> surfaceComposer = composerServiceAIDL();
                 if (surfaceComposer == nullptr) {
                     return -EPERM; // likely permissions error
                 }
-                if (surfaceComposer->authenticateSurfaceTexture(mGraphicBufferProducer)) {
-                    *value = 1;
-                } else {
-                    *value = 0;
-                }
+                // ISurfaceComposer no longer supports authenticateSurfaceTexture
+                *value = 0;
                 return NO_ERROR;
             }
             case NATIVE_WINDOW_CONCRETE_TYPE:
@@ -1867,7 +1867,11 @@
     auto startTimeNanos = static_cast<int64_t>(va_arg(args, int64_t));
 
     ALOGV("Surface::%s", __func__);
-    return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId, startTimeNanos});
+    FrameTimelineInfo ftlInfo;
+    ftlInfo.vsyncId = frameTimelineVsyncId;
+    ftlInfo.inputEventId = inputEventId;
+    ftlInfo.startTimeNanos = startTimeNanos;
+    return setFrameTimelineInfo(ftlInfo);
 }
 
 bool Surface::transformToDisplayInverse() const {
@@ -2623,22 +2627,18 @@
     mSurfaceListener->onBuffersDiscarded(discardedBufs);
 }
 
-status_t Surface::setFrameRate(float frameRate, int8_t compatibility,
-                               int8_t changeFrameRateStrategy) {
-    ATRACE_CALL();
-    ALOGV("Surface::setFrameRate");
-
-    if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy,
-                           "Surface::setFrameRate")) {
-        return BAD_VALUE;
-    }
-
-    return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility,
-                                           changeFrameRateStrategy);
+[[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) {
-    return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo);
+status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& /*frameTimelineInfo*/) {
+    // ISurfaceComposer no longer supports setFrameTimelineInfo
+    return BAD_VALUE;
 }
 
 sp<IBinder> Surface::getSurfaceControlHandle() const {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 47d801a..16dbc92 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -19,8 +19,11 @@
 #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>
+#include <android/os/IInputConstants.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/SortedVector.h>
@@ -33,11 +36,11 @@
 
 #include <system/graphics.h>
 
+#include <gui/AidlStatusUtil.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/CpuConsumer.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/ISurfaceComposer.h>
-#include <gui/ISurfaceComposerClient.h>
 #include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
@@ -61,6 +64,7 @@
 using gui::WindowInfo;
 using gui::WindowInfoHandle;
 using gui::WindowInfosListener;
+using gui::aidl_utils::statusTFromBinderStatus;
 using ui::ColorMode;
 // ---------------------------------------------------------------------------
 
@@ -111,7 +115,6 @@
     if (instance.mComposerService == nullptr) {
         if (ComposerService::getInstance().connectLocked()) {
             ALOGD("ComposerService reconnected");
-            WindowInfosListenerReporter::getInstance()->reconnect(instance.mComposerService);
         }
     }
     return instance.mComposerService;
@@ -159,6 +162,7 @@
     if (instance.mComposerService == nullptr) {
         if (ComposerServiceAIDL::getInstance().connectLocked()) {
             ALOGD("ComposerServiceAIDL reconnected");
+            WindowInfosListenerReporter::getInstance()->reconnect(instance.mComposerService);
         }
     }
     return instance.mComposerService;
@@ -632,7 +636,8 @@
         mDesiredPresentTime(other.mDesiredPresentTime),
         mIsAutoTimestamp(other.mIsAutoTimestamp),
         mFrameTimelineInfo(other.mFrameTimelineInfo),
-        mApplyToken(other.mApplyToken) {
+        mApplyToken(other.mApplyToken),
+        mWindowInfosReportedEvent(other.mWindowInfosReportedEvent) {
     mDisplayStates = other.mDisplayStates;
     mComposerStates = other.mComposerStates;
     mInputWindowCommands = other.mInputWindowCommands;
@@ -657,6 +662,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();
@@ -666,7 +672,7 @@
     const int64_t desiredPresentTime = parcel->readInt64();
     const bool isAutoTimestamp = parcel->readBool();
     FrameTimelineInfo frameTimelineInfo;
-    SAFE_PARCEL(frameTimelineInfo.read, *parcel);
+    frameTimelineInfo.readFromParcel(parcel);
 
     sp<IBinder> applyToken;
     parcel->readNullableStrongBinder(&applyToken);
@@ -734,6 +740,7 @@
     inputWindowCommands.read(*parcel);
 
     // Parsing was successful. Update the object.
+    mId = transactionId;
     mForceSynchronous = forceSynchronous;
     mTransactionNestCount = transactionNestCount;
     mAnimation = animation;
@@ -765,6 +772,7 @@
 
     const_cast<SurfaceComposerClient::Transaction*>(this)->cacheBuffers();
 
+    parcel->writeUint64(mId);
     parcel->writeUint32(mForceSynchronous);
     parcel->writeUint32(mTransactionNestCount);
     parcel->writeBool(mAnimation);
@@ -773,7 +781,7 @@
     parcel->writeBool(mContainsBuffer);
     parcel->writeInt64(mDesiredPresentTime);
     parcel->writeBool(mIsAutoTimestamp);
-    SAFE_PARCEL(mFrameTimelineInfo.write, *parcel);
+    mFrameTimelineInfo.writeToParcel(parcel);
     parcel->writeStrongBinder(mApplyToken);
     parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size()));
     for (auto const& displayState : mDisplayStates) {
@@ -873,8 +881,11 @@
     mEarlyWakeupStart = mEarlyWakeupStart || other.mEarlyWakeupStart;
     mEarlyWakeupEnd = mEarlyWakeupEnd || other.mEarlyWakeupEnd;
     mApplyToken = other.mApplyToken;
+    if (other.mWindowInfosReportedEvent) {
+        mWindowInfosReportedEvent = std::move(other.mWindowInfosReportedEvent);
+    }
 
-    mFrameTimelineInfo.merge(other.mFrameTimelineInfo);
+    mergeFrameTimelineInfo(mFrameTimelineInfo, other.mFrameTimelineInfo);
 
     other.clear();
     return *this;
@@ -893,8 +904,13 @@
     mEarlyWakeupEnd = false;
     mDesiredPresentTime = 0;
     mIsAutoTimestamp = true;
-    mFrameTimelineInfo.clear();
+    clearFrameTimelineInfo(mFrameTimelineInfo);
     mApplyToken = nullptr;
+    mWindowInfosReportedEvent = nullptr;
+}
+
+uint64_t SurfaceComposerClient::Transaction::getId() {
+    return mId;
 }
 
 void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
@@ -1037,6 +1053,10 @@
                             hasListenerCallbacks, listenerCallbacks, mId);
     mId = generateId();
 
+    if (mWindowInfosReportedEvent && !mWindowInfosReportedEvent->wait()) {
+        ALOGE("Timed out waiting for window infos to be reported.");
+    }
+
     // Clear the current states and flags
     clear();
 
@@ -1081,7 +1101,7 @@
     if (status.isOk()) {
         *id = *DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
     }
-    return status.transactionError();
+    return statusTFromBinderStatus(status);
 }
 
 std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
@@ -1723,8 +1743,25 @@
     return *this;
 }
 
+class NotifyWindowInfosReported : public gui::BnWindowInfosReportedListener {
+public:
+    NotifyWindowInfosReported(
+            std::shared_ptr<SurfaceComposerClient::Event> windowInfosReportedEvent)
+          : mWindowInfosReportedEvent(windowInfosReportedEvent) {}
+
+    binder::Status onWindowInfosReported() {
+        mWindowInfosReportedEvent->set();
+        return binder::Status::ok();
+    }
+
+private:
+    std::shared_ptr<SurfaceComposerClient::Event> mWindowInfosReportedEvent;
+};
+
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() {
-    mInputWindowCommands.syncInputWindows = true;
+    mWindowInfosReportedEvent = std::make_shared<Event>();
+    mInputWindowCommands.windowInfosReportedListeners.insert(
+            sp<NotifyWindowInfosReported>::make(mWindowInfosReportedEvent));
     return *this;
 }
 
@@ -1831,6 +1868,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);
@@ -1849,7 +1899,7 @@
 
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo(
         const FrameTimelineInfo& frameTimelineInfo) {
-    mFrameTimelineInfo.merge(frameTimelineInfo);
+    mergeFrameTimelineInfo(mFrameTimelineInfo, frameTimelineInfo);
     return *this;
 }
 
@@ -1943,6 +1993,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) {
@@ -2008,6 +2075,31 @@
     s.what |= DisplayState::eDisplaySizeChanged;
 }
 
+// copied from FrameTimelineInfo::merge()
+void SurfaceComposerClient::Transaction::mergeFrameTimelineInfo(FrameTimelineInfo& t,
+                                                                const FrameTimelineInfo& other) {
+    // When merging vsync Ids we take the oldest valid one
+    if (t.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID &&
+        other.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
+        if (other.vsyncId > t.vsyncId) {
+            t.vsyncId = other.vsyncId;
+            t.inputEventId = other.inputEventId;
+            t.startTimeNanos = other.startTimeNanos;
+        }
+    } else if (t.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) {
+        t.vsyncId = other.vsyncId;
+        t.inputEventId = other.inputEventId;
+        t.startTimeNanos = other.startTimeNanos;
+    }
+}
+
+// copied from FrameTimelineInfo::clear()
+void SurfaceComposerClient::Transaction::clearFrameTimelineInfo(FrameTimelineInfo& t) {
+    t.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID;
+    t.inputEventId = os::IInputConstants::INVALID_INPUT_EVENT_ID;
+    t.startTimeNanos = 0;
+}
+
 // ---------------------------------------------------------------------------
 
 SurfaceComposerClient::SurfaceComposerClient() : mStatus(NO_INIT) {}
@@ -2016,11 +2108,11 @@
       : mStatus(NO_ERROR), mClient(client) {}
 
 void SurfaceComposerClient::onFirstRef() {
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
     if (sf != nullptr && mStatus == NO_INIT) {
         sp<ISurfaceComposerClient> conn;
-        conn = sf->createConnection();
-        if (conn != nullptr) {
+        binder::Status status = sf->createConnection(&conn);
+        if (status.isOk() && conn != nullptr) {
             mClient = conn;
             mStatus = NO_ERROR;
         }
@@ -2058,7 +2150,7 @@
 }
 
 sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name, uint32_t w, uint32_t h,
-                                                        PixelFormat format, uint32_t flags,
+                                                        PixelFormat format, int32_t flags,
                                                         const sp<IBinder>& parentHandle,
                                                         LayerMetadata metadata,
                                                         uint32_t* outTransformHint) {
@@ -2068,38 +2160,9 @@
     return s;
 }
 
-sp<SurfaceControl> SurfaceComposerClient::createWithSurfaceParent(const String8& name, uint32_t w,
-                                                                  uint32_t h, PixelFormat format,
-                                                                  uint32_t flags, Surface* parent,
-                                                                  LayerMetadata metadata,
-                                                                  uint32_t* outTransformHint) {
-    sp<SurfaceControl> sur;
-    status_t err = mStatus;
-
-    if (mStatus == NO_ERROR) {
-        sp<IBinder> handle;
-        sp<IGraphicBufferProducer> parentGbp = parent->getIGraphicBufferProducer();
-        sp<IGraphicBufferProducer> gbp;
-
-        uint32_t transformHint = 0;
-        int32_t id = -1;
-        err = mClient->createWithSurfaceParent(name, w, h, format, flags, parentGbp,
-                                               std::move(metadata), &handle, &gbp, &id,
-                                               &transformHint);
-        if (outTransformHint) {
-            *outTransformHint = transformHint;
-        }
-        ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err));
-        if (err == NO_ERROR) {
-            return new SurfaceControl(this, handle, gbp, id, transformHint);
-        }
-    }
-    return nullptr;
-}
-
 status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
                                                      PixelFormat format,
-                                                     sp<SurfaceControl>* outSurface, uint32_t flags,
+                                                     sp<SurfaceControl>* outSurface, int32_t flags,
                                                      const sp<IBinder>& parentHandle,
                                                      LayerMetadata metadata,
                                                      uint32_t* outTransformHint) {
@@ -2107,21 +2170,17 @@
     status_t err = mStatus;
 
     if (mStatus == NO_ERROR) {
-        sp<IBinder> handle;
-        sp<IGraphicBufferProducer> gbp;
-
-        uint32_t transformHint = 0;
-        int32_t id = -1;
-        err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata),
-                                     &handle, &gbp, &id, &transformHint);
-
+        gui::CreateSurfaceResult result;
+        binder::Status status = mClient->createSurface(std::string(name.string()), flags,
+                                                       parentHandle, std::move(metadata), &result);
+        err = statusTFromBinderStatus(status);
         if (outTransformHint) {
-            *outTransformHint = transformHint;
+            *outTransformHint = result.transformHint;
         }
         ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
         if (err == NO_ERROR) {
-            *outSurface =
-                    new SurfaceControl(this, handle, gbp, id, w, h, format, transformHint, flags);
+            *outSurface = new SurfaceControl(this, result.handle, result.layerId, w, h, format,
+                                             result.transformHint, flags);
         }
     }
     return err;
@@ -2132,12 +2191,12 @@
         return nullptr;
     }
 
-    sp<IBinder> handle;
     sp<IBinder> mirrorFromHandle = mirrorFromSurface->getHandle();
-    int32_t layer_id = -1;
-    status_t err = mClient->mirrorSurface(mirrorFromHandle, &handle, &layer_id);
+    gui::MirrorSurfaceResult result;
+    const binder::Status status = mClient->mirrorSurface(mirrorFromHandle, &result);
+    const status_t err = statusTFromBinderStatus(status);
     if (err == NO_ERROR) {
-        return new SurfaceControl(this, handle, nullptr, layer_id, true /* owned */);
+        return new SurfaceControl(this, result.handle, result.layerId);
     }
     return nullptr;
 }
@@ -2146,7 +2205,8 @@
     if (mStatus != NO_ERROR) {
         return mStatus;
     }
-    return mClient->clearLayerFrameStats(token);
+    const binder::Status status = mClient->clearLayerFrameStats(token);
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::getLayerFrameStats(const sp<IBinder>& token,
@@ -2154,19 +2214,38 @@
     if (mStatus != NO_ERROR) {
         return mStatus;
     }
-    return mClient->getLayerFrameStats(token, outStats);
+    gui::FrameStats stats;
+    const binder::Status status = mClient->getLayerFrameStats(token, &stats);
+    if (status.isOk()) {
+        outStats->refreshPeriodNano = stats.refreshPeriodNano;
+        outStats->desiredPresentTimesNano.setCapacity(stats.desiredPresentTimesNano.size());
+        for (const auto& t : stats.desiredPresentTimesNano) {
+            outStats->desiredPresentTimesNano.add(t);
+        }
+        outStats->actualPresentTimesNano.setCapacity(stats.actualPresentTimesNano.size());
+        for (const auto& t : stats.actualPresentTimesNano) {
+            outStats->actualPresentTimesNano.add(t);
+        }
+        outStats->frameReadyTimesNano.setCapacity(stats.frameReadyTimesNano.size());
+        for (const auto& t : stats.frameReadyTimesNano) {
+            outStats->frameReadyTimesNano.add(t);
+        }
+    }
+    return statusTFromBinderStatus(status);
 }
 
 // ----------------------------------------------------------------------------
 
 status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    return sf->enableVSyncInjections(enable);
+    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
+    binder::Status status = sf->enableVSyncInjections(enable);
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::injectVSync(nsecs_t when) {
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    return sf->injectVSync(when);
+    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
+    binder::Status status = sf->injectVSync(when);
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display,
@@ -2180,17 +2259,106 @@
         state->layerStackSpaceRect =
                 ui::Size(ds.layerStackSpaceRect.width, ds.layerStackSpaceRect.height);
     }
-    return status.transactionError();
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::getStaticDisplayInfo(const sp<IBinder>& display,
-                                                     ui::StaticDisplayInfo* info) {
-    return ComposerService::getComposerService()->getStaticDisplayInfo(display, info);
+                                                     ui::StaticDisplayInfo* outInfo) {
+    using Tag = android::gui::DeviceProductInfo::ManufactureOrModelDate::Tag;
+    gui::StaticDisplayInfo ginfo;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getStaticDisplayInfo(display, &ginfo);
+    if (status.isOk()) {
+        // convert gui::StaticDisplayInfo to ui::StaticDisplayInfo
+        outInfo->connectionType = static_cast<ui::DisplayConnectionType>(ginfo.connectionType);
+        outInfo->density = ginfo.density;
+        outInfo->secure = ginfo.secure;
+        outInfo->installOrientation = static_cast<ui::Rotation>(ginfo.installOrientation);
+
+        DeviceProductInfo info;
+        std::optional<gui::DeviceProductInfo> dpi = ginfo.deviceProductInfo;
+        gui::DeviceProductInfo::ManufactureOrModelDate& date = dpi->manufactureOrModelDate;
+        info.name = dpi->name;
+        if (dpi->manufacturerPnpId.size() > 0) {
+            // copid from PnpId = std::array<char, 4> in ui/DeviceProductInfo.h
+            constexpr int kMaxPnpIdSize = 4;
+            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;
+            modelYear.year = static_cast<uint32_t>(date.get<Tag::modelYear>().year);
+            info.manufactureOrModelDate = modelYear;
+        } else if (date.getTag() == Tag::manufactureYear) {
+            DeviceProductInfo::ManufactureYear manufactureYear;
+            manufactureYear.year = date.get<Tag::manufactureYear>().modelYear.year;
+            info.manufactureOrModelDate = manufactureYear;
+        } else if (date.getTag() == Tag::manufactureWeekAndYear) {
+            DeviceProductInfo::ManufactureWeekAndYear weekAndYear;
+            weekAndYear.year =
+                    date.get<Tag::manufactureWeekAndYear>().manufactureYear.modelYear.year;
+            weekAndYear.week = date.get<Tag::manufactureWeekAndYear>().week;
+            info.manufactureOrModelDate = weekAndYear;
+        }
+
+        outInfo->deviceProductInfo = info;
+    }
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::getDynamicDisplayInfo(const sp<IBinder>& display,
-                                                      ui::DynamicDisplayInfo* info) {
-    return ComposerService::getComposerService()->getDynamicDisplayInfo(display, info);
+                                                      ui::DynamicDisplayInfo* outInfo) {
+    gui::DynamicDisplayInfo ginfo;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getDynamicDisplayInfo(display, &ginfo);
+    if (status.isOk()) {
+        // convert gui::DynamicDisplayInfo to ui::DynamicDisplayInfo
+        outInfo->supportedDisplayModes.clear();
+        outInfo->supportedDisplayModes.reserve(ginfo.supportedDisplayModes.size());
+        for (const auto& mode : ginfo.supportedDisplayModes) {
+            ui::DisplayMode outMode;
+            outMode.id = mode.id;
+            outMode.resolution.width = mode.resolution.width;
+            outMode.resolution.height = mode.resolution.height;
+            outMode.xDpi = mode.xDpi;
+            outMode.yDpi = mode.yDpi;
+            outMode.refreshRate = mode.refreshRate;
+            outMode.appVsyncOffset = mode.appVsyncOffset;
+            outMode.sfVsyncOffset = mode.sfVsyncOffset;
+            outMode.presentationDeadline = mode.presentationDeadline;
+            outMode.group = mode.group;
+            outInfo->supportedDisplayModes.push_back(outMode);
+        }
+
+        outInfo->activeDisplayModeId = ginfo.activeDisplayModeId;
+
+        outInfo->supportedColorModes.clear();
+        outInfo->supportedColorModes.reserve(ginfo.supportedColorModes.size());
+        for (const auto& cmode : ginfo.supportedColorModes) {
+            outInfo->supportedColorModes.push_back(static_cast<ui::ColorMode>(cmode));
+        }
+
+        outInfo->activeColorMode = static_cast<ui::ColorMode>(ginfo.activeColorMode);
+
+        std::vector<ui::Hdr> types;
+        types.reserve(ginfo.hdrCapabilities.supportedHdrTypes.size());
+        for (const auto& hdr : ginfo.hdrCapabilities.supportedHdrTypes) {
+            types.push_back(static_cast<ui::Hdr>(hdr));
+        }
+        outInfo->hdrCapabilities = HdrCapabilities(types, ginfo.hdrCapabilities.maxLuminance,
+                                                   ginfo.hdrCapabilities.maxAverageLuminance,
+                                                   ginfo.hdrCapabilities.minLuminance);
+
+        outInfo->autoLowLatencyModeSupported = ginfo.autoLowLatencyModeSupported;
+        outInfo->gameContentTypeSupported = ginfo.gameContentTypeSupported;
+        outInfo->preferredBootDisplayMode = ginfo.preferredBootDisplayMode;
+    }
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::getActiveDisplayMode(const sp<IBinder>& display,
@@ -2214,10 +2382,13 @@
         const sp<IBinder>& displayToken, ui::DisplayModeId defaultMode, bool allowGroupSwitching,
         float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin,
         float appRequestRefreshRateMax) {
-    return ComposerService::getComposerService()
-            ->setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching,
-                                         primaryRefreshRateMin, primaryRefreshRateMax,
-                                         appRequestRefreshRateMin, appRequestRefreshRateMax);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()
+                    ->setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching,
+                                                 primaryRefreshRateMin, primaryRefreshRateMax,
+                                                 appRequestRefreshRateMin,
+                                                 appRequestRefreshRateMax);
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
@@ -2227,41 +2398,81 @@
                                                            float* outPrimaryRefreshRateMax,
                                                            float* outAppRequestRefreshRateMin,
                                                            float* outAppRequestRefreshRateMax) {
-    return ComposerService::getComposerService()
-            ->getDesiredDisplayModeSpecs(displayToken, outDefaultMode, outAllowGroupSwitching,
-                                         outPrimaryRefreshRateMin, outPrimaryRefreshRateMax,
-                                         outAppRequestRefreshRateMin, outAppRequestRefreshRateMax);
+    if (!outDefaultMode || !outAllowGroupSwitching || !outPrimaryRefreshRateMin ||
+        !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
+        return BAD_VALUE;
+    }
+    gui::DisplayModeSpecs specs;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getDesiredDisplayModeSpecs(displayToken,
+                                                                                  &specs);
+    if (status.isOk()) {
+        *outDefaultMode = specs.defaultMode;
+        *outAllowGroupSwitching = specs.allowGroupSwitching;
+        *outPrimaryRefreshRateMin = specs.primaryRefreshRateMin;
+        *outPrimaryRefreshRateMax = specs.primaryRefreshRateMax;
+        *outAppRequestRefreshRateMin = specs.appRequestRefreshRateMin;
+        *outAppRequestRefreshRateMax = specs.appRequestRefreshRateMax;
+    }
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::getDisplayNativePrimaries(const sp<IBinder>& display,
         ui::DisplayPrimaries& outPrimaries) {
-    return ComposerService::getComposerService()->getDisplayNativePrimaries(display, outPrimaries);
+    gui::DisplayPrimaries primaries;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getDisplayNativePrimaries(display,
+                                                                                 &primaries);
+    if (status.isOk()) {
+        outPrimaries.red.X = primaries.red.X;
+        outPrimaries.red.Y = primaries.red.Y;
+        outPrimaries.red.Z = primaries.red.Z;
+
+        outPrimaries.green.X = primaries.green.X;
+        outPrimaries.green.Y = primaries.green.Y;
+        outPrimaries.green.Z = primaries.green.Z;
+
+        outPrimaries.blue.X = primaries.blue.X;
+        outPrimaries.blue.Y = primaries.blue.Y;
+        outPrimaries.blue.Z = primaries.blue.Z;
+
+        outPrimaries.white.X = primaries.white.X;
+        outPrimaries.white.Y = primaries.white.Y;
+        outPrimaries.white.Z = primaries.white.Z;
+    }
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::setActiveColorMode(const sp<IBinder>& display,
         ColorMode colorMode) {
-    return ComposerService::getComposerService()->setActiveColorMode(display, colorMode);
+    binder::Status status = ComposerServiceAIDL::getComposerService()
+                                    ->setActiveColorMode(display, static_cast<int>(colorMode));
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::getBootDisplayModeSupport(bool* support) {
     binder::Status status =
             ComposerServiceAIDL::getComposerService()->getBootDisplayModeSupport(support);
-    return status.transactionError();
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::setBootDisplayMode(const sp<IBinder>& display,
                                                    ui::DisplayModeId displayModeId) {
-    return ComposerService::getComposerService()->setBootDisplayMode(display, displayModeId);
+    binder::Status status = ComposerServiceAIDL::getComposerService()
+                                    ->setBootDisplayMode(display, static_cast<int>(displayModeId));
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::clearBootDisplayMode(const sp<IBinder>& display) {
     binder::Status status =
             ComposerServiceAIDL::getComposerService()->clearBootDisplayMode(display);
-    return status.transactionError();
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) {
-    return ComposerService::getComposerService()->setOverrideFrameRate(uid, frameRate);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->setOverrideFrameRate(uid, frameRate);
+    return statusTFromBinderStatus(status);
 }
 
 void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
@@ -2280,57 +2491,137 @@
 status_t SurfaceComposerClient::getCompositionPreference(
         ui::Dataspace* defaultDataspace, ui::PixelFormat* defaultPixelFormat,
         ui::Dataspace* wideColorGamutDataspace, ui::PixelFormat* wideColorGamutPixelFormat) {
-    return ComposerService::getComposerService()
-            ->getCompositionPreference(defaultDataspace, defaultPixelFormat,
-                                       wideColorGamutDataspace, wideColorGamutPixelFormat);
+    gui::CompositionPreference pref;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getCompositionPreference(&pref);
+    if (status.isOk()) {
+        *defaultDataspace = static_cast<ui::Dataspace>(pref.defaultDataspace);
+        *defaultPixelFormat = static_cast<ui::PixelFormat>(pref.defaultPixelFormat);
+        *wideColorGamutDataspace = static_cast<ui::Dataspace>(pref.wideColorGamutDataspace);
+        *wideColorGamutPixelFormat = static_cast<ui::PixelFormat>(pref.wideColorGamutPixelFormat);
+    }
+    return statusTFromBinderStatus(status);
 }
 
 bool SurfaceComposerClient::getProtectedContentSupport() {
     bool supported = false;
-    ComposerService::getComposerService()->getProtectedContentSupport(&supported);
+    ComposerServiceAIDL::getComposerService()->getProtectedContentSupport(&supported);
     return supported;
 }
 
 status_t SurfaceComposerClient::clearAnimationFrameStats() {
-    return ComposerService::getComposerService()->clearAnimationFrameStats();
+    binder::Status status = ComposerServiceAIDL::getComposerService()->clearAnimationFrameStats();
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::getAnimationFrameStats(FrameStats* outStats) {
-    return ComposerService::getComposerService()->getAnimationFrameStats(outStats);
+    gui::FrameStats stats;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getAnimationFrameStats(&stats);
+    if (status.isOk()) {
+        outStats->refreshPeriodNano = stats.refreshPeriodNano;
+        outStats->desiredPresentTimesNano.setCapacity(stats.desiredPresentTimesNano.size());
+        for (const auto& t : stats.desiredPresentTimesNano) {
+            outStats->desiredPresentTimesNano.add(t);
+        }
+        outStats->actualPresentTimesNano.setCapacity(stats.actualPresentTimesNano.size());
+        for (const auto& t : stats.actualPresentTimesNano) {
+            outStats->actualPresentTimesNano.add(t);
+        }
+        outStats->frameReadyTimesNano.setCapacity(stats.frameReadyTimesNano.size());
+        for (const auto& t : stats.frameReadyTimesNano) {
+            outStats->frameReadyTimesNano.add(t);
+        }
+    }
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::overrideHdrTypes(const sp<IBinder>& display,
                                                  const std::vector<ui::Hdr>& hdrTypes) {
-    return ComposerService::getComposerService()->overrideHdrTypes(display, hdrTypes);
+    std::vector<int32_t> hdrTypesVector;
+    hdrTypesVector.reserve(hdrTypes.size());
+    for (auto t : hdrTypes) {
+        hdrTypesVector.push_back(static_cast<int32_t>(t));
+    }
+
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->overrideHdrTypes(display, hdrTypesVector);
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::onPullAtom(const int32_t atomId, std::string* outData,
                                            bool* success) {
-    return ComposerService::getComposerService()->onPullAtom(atomId, outData, success);
+    gui::PullAtomData pad;
+    binder::Status status = ComposerServiceAIDL::getComposerService()->onPullAtom(atomId, &pad);
+    if (status.isOk()) {
+        outData->assign((const char*)pad.data.data(), pad.data.size());
+        *success = pad.success;
+    }
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
                                                                       ui::PixelFormat* outFormat,
                                                                       ui::Dataspace* outDataspace,
                                                                       uint8_t* outComponentMask) {
-    return ComposerService::getComposerService()
-            ->getDisplayedContentSamplingAttributes(display, outFormat, outDataspace,
-                                                    outComponentMask);
+    if (!outFormat || !outDataspace || !outComponentMask) {
+        return BAD_VALUE;
+    }
+
+    gui::ContentSamplingAttributes attrs;
+    binder::Status status = ComposerServiceAIDL::getComposerService()
+                                    ->getDisplayedContentSamplingAttributes(display, &attrs);
+    if (status.isOk()) {
+        *outFormat = static_cast<ui::PixelFormat>(attrs.format);
+        *outDataspace = static_cast<ui::Dataspace>(attrs.dataspace);
+        *outComponentMask = static_cast<uint8_t>(attrs.componentMask);
+    }
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::setDisplayContentSamplingEnabled(const sp<IBinder>& display,
                                                                  bool enable, uint8_t componentMask,
                                                                  uint64_t maxFrames) {
-    return ComposerService::getComposerService()->setDisplayContentSamplingEnabled(display, enable,
-                                                                                   componentMask,
-                                                                                   maxFrames);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()
+                    ->setDisplayContentSamplingEnabled(display, enable,
+                                                       static_cast<int8_t>(componentMask),
+                                                       static_cast<int64_t>(maxFrames));
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::getDisplayedContentSample(const sp<IBinder>& display,
                                                           uint64_t maxFrames, uint64_t timestamp,
                                                           DisplayedFrameStats* outStats) {
-    return ComposerService::getComposerService()->getDisplayedContentSample(display, maxFrames,
-                                                                            timestamp, outStats);
+    if (!outStats) {
+        return BAD_VALUE;
+    }
+
+    gui::DisplayedFrameStats stats;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getDisplayedContentSample(display, maxFrames,
+                                                                                 timestamp, &stats);
+    if (status.isOk()) {
+        // convert gui::DisplayedFrameStats to ui::DisplayedFrameStats
+        outStats->numFrames = static_cast<uint64_t>(stats.numFrames);
+        outStats->component_0_sample.reserve(stats.component_0_sample.size());
+        for (const auto& s : stats.component_0_sample) {
+            outStats->component_0_sample.push_back(static_cast<uint64_t>(s));
+        }
+        outStats->component_1_sample.reserve(stats.component_1_sample.size());
+        for (const auto& s : stats.component_1_sample) {
+            outStats->component_1_sample.push_back(static_cast<uint64_t>(s));
+        }
+        outStats->component_2_sample.reserve(stats.component_2_sample.size());
+        for (const auto& s : stats.component_2_sample) {
+            outStats->component_2_sample.push_back(static_cast<uint64_t>(s));
+        }
+        outStats->component_3_sample.reserve(stats.component_3_sample.size());
+        for (const auto& s : stats.component_3_sample) {
+            outStats->component_3_sample.push_back(static_cast<uint64_t>(s));
+        }
+    }
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::isWideColorDisplay(const sp<IBinder>& display,
@@ -2338,39 +2629,55 @@
     binder::Status status =
             ComposerServiceAIDL::getComposerService()->isWideColorDisplay(display,
                                                                           outIsWideColorDisplay);
-    return status.transactionError();
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::addRegionSamplingListener(
         const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
         const sp<IRegionSamplingListener>& listener) {
-    return ComposerService::getComposerService()->addRegionSamplingListener(samplingArea,
-                                                                            stopLayerHandle,
-                                                                            listener);
+    gui::ARect rect;
+    rect.left = samplingArea.left;
+    rect.top = samplingArea.top;
+    rect.right = samplingArea.right;
+    rect.bottom = samplingArea.bottom;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->addRegionSamplingListener(rect,
+                                                                                 stopLayerHandle,
+                                                                                 listener);
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::removeRegionSamplingListener(
         const sp<IRegionSamplingListener>& listener) {
-    return ComposerService::getComposerService()->removeRegionSamplingListener(listener);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->removeRegionSamplingListener(listener);
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::addFpsListener(int32_t taskId,
                                                const sp<gui::IFpsListener>& listener) {
-    return ComposerService::getComposerService()->addFpsListener(taskId, listener);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->addFpsListener(taskId, listener);
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::removeFpsListener(const sp<gui::IFpsListener>& listener) {
-    return ComposerService::getComposerService()->removeFpsListener(listener);
+    binder::Status status = ComposerServiceAIDL::getComposerService()->removeFpsListener(listener);
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::addTunnelModeEnabledListener(
         const sp<gui::ITunnelModeEnabledListener>& listener) {
-    return ComposerService::getComposerService()->addTunnelModeEnabledListener(listener);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->addTunnelModeEnabledListener(listener);
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::removeTunnelModeEnabledListener(
         const sp<gui::ITunnelModeEnabledListener>& listener) {
-    return ComposerService::getComposerService()->removeTunnelModeEnabledListener(listener);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->removeTunnelModeEnabledListener(listener);
+    return statusTFromBinderStatus(status);
 }
 
 bool SurfaceComposerClient::getDisplayBrightnessSupport(const sp<IBinder>& displayToken) {
@@ -2386,7 +2693,7 @@
     binder::Status status =
             ComposerServiceAIDL::getComposerService()->setDisplayBrightness(displayToken,
                                                                             brightness);
-    return status.transactionError();
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::addHdrLayerInfoListener(
@@ -2394,7 +2701,7 @@
     binder::Status status =
             ComposerServiceAIDL::getComposerService()->addHdrLayerInfoListener(displayToken,
                                                                                listener);
-    return status.transactionError();
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::removeHdrLayerInfoListener(
@@ -2402,45 +2709,76 @@
     binder::Status status =
             ComposerServiceAIDL::getComposerService()->removeHdrLayerInfoListener(displayToken,
                                                                                   listener);
-    return status.transactionError();
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::notifyPowerBoost(int32_t boostId) {
     binder::Status status = ComposerServiceAIDL::getComposerService()->notifyPowerBoost(boostId);
-    return status.transactionError();
+    return statusTFromBinderStatus(status);
 }
 
 status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColor,
                                                         const half4& spotColor, float lightPosY,
                                                         float lightPosZ, float lightRadius) {
-    return ComposerService::getComposerService()->setGlobalShadowSettings(ambientColor, spotColor,
-                                                                          lightPosY, lightPosZ,
-                                                                          lightRadius);
+    gui::Color ambientColorG, spotColorG;
+    ambientColorG.r = ambientColor.r;
+    ambientColorG.g = ambientColor.g;
+    ambientColorG.b = ambientColor.b;
+    ambientColorG.a = ambientColor.a;
+    spotColorG.r = spotColor.r;
+    spotColorG.g = spotColor.g;
+    spotColorG.b = spotColor.b;
+    spotColorG.a = spotColor.a;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->setGlobalShadowSettings(ambientColorG,
+                                                                               spotColorG,
+                                                                               lightPosY, lightPosZ,
+                                                                               lightRadius);
+    return statusTFromBinderStatus(status);
 }
 
 std::optional<DisplayDecorationSupport> SurfaceComposerClient::getDisplayDecorationSupport(
         const sp<IBinder>& displayToken) {
+    std::optional<gui::DisplayDecorationSupport> gsupport;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getDisplayDecorationSupport(displayToken,
+                                                                                   &gsupport);
     std::optional<DisplayDecorationSupport> support;
-    ComposerService::getComposerService()->getDisplayDecorationSupport(displayToken, &support);
+    if (status.isOk() && gsupport.has_value()) {
+        support->format = static_cast<aidl::android::hardware::graphics::common::PixelFormat>(
+                gsupport->format);
+        support->alphaInterpretation =
+                static_cast<aidl::android::hardware::graphics::common::AlphaInterpretation>(
+                        gsupport->alphaInterpretation);
+    }
     return support;
 }
 
-int SurfaceComposerClient::getGPUContextPriority() {
-    return ComposerService::getComposerService()->getGPUContextPriority();
+int SurfaceComposerClient::getGpuContextPriority() {
+    int priority;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getGpuContextPriority(&priority);
+    if (!status.isOk()) {
+        status_t err = statusTFromBinderStatus(status);
+        ALOGE("getGpuContextPriority failed to read data:  %s (%d)", strerror(-err), err);
+        return 0;
+    }
+    return priority;
 }
 
 status_t SurfaceComposerClient::addWindowInfosListener(
         const sp<WindowInfosListener>& windowInfosListener,
         std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo) {
     return WindowInfosListenerReporter::getInstance()
-            ->addWindowInfosListener(windowInfosListener, ComposerService::getComposerService(),
+            ->addWindowInfosListener(windowInfosListener, ComposerServiceAIDL::getComposerService(),
                                      outInitialInfo);
 }
 
 status_t SurfaceComposerClient::removeWindowInfosListener(
         const sp<WindowInfosListener>& windowInfosListener) {
     return WindowInfosListenerReporter::getInstance()
-            ->removeWindowInfosListener(windowInfosListener, ComposerService::getComposerService());
+            ->removeWindowInfosListener(windowInfosListener,
+                                        ComposerServiceAIDL::getComposerService());
 }
 
 // ----------------------------------------------------------------------------
@@ -2451,7 +2789,7 @@
     if (s == nullptr) return NO_INIT;
 
     binder::Status status = s->captureDisplay(captureArgs, captureListener);
-    return status.transactionError();
+    return statusTFromBinderStatus(status);
 }
 
 status_t ScreenshotClient::captureDisplay(DisplayId displayId,
@@ -2460,7 +2798,7 @@
     if (s == nullptr) return NO_INIT;
 
     binder::Status status = s->captureDisplayById(displayId.value, captureListener);
-    return status.transactionError();
+    return statusTFromBinderStatus(status);
 }
 
 status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs,
@@ -2469,7 +2807,7 @@
     if (s == nullptr) return NO_INIT;
 
     binder::Status status = s->captureLayers(captureArgs, captureListener);
-    return status.transactionError();
+    return statusTFromBinderStatus(status);
 }
 
 // ---------------------------------------------------------------------------------
@@ -2511,4 +2849,17 @@
     }
 }
 
+// ---------------------------------------------------------------------------------
+
+void SurfaceComposerClient::Event::set() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mComplete = true;
+    mConditionVariable.notify_all();
+}
+
+bool SurfaceComposerClient::Event::wait() {
+    std::unique_lock<std::mutex> lock(mMutex);
+    return mConditionVariable.wait_for(lock, sTimeout, [this] { return mComplete; });
+}
+
 } // namespace android
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 654fb33..84257de 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -49,12 +49,10 @@
 // ============================================================================
 
 SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
-                               const sp<IGraphicBufferProducer>& gbp, int32_t layerId,
-                               uint32_t w, uint32_t h, PixelFormat format, uint32_t transform,
-                               uint32_t flags)
+                               int32_t layerId, uint32_t w, uint32_t h, PixelFormat format,
+                               uint32_t transform, uint32_t flags)
       : mClient(client),
         mHandle(handle),
-        mGraphicBufferProducer(gbp),
         mLayerId(layerId),
         mTransformHint(transform),
         mWidth(w),
@@ -65,7 +63,6 @@
 SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) {
     mClient = other->mClient;
     mHandle = other->mHandle;
-    mGraphicBufferProducer = other->mGraphicBufferProducer;
     mTransformHint = other->mTransformHint;
     mLayerId = other->mLayerId;
     mWidth = other->mWidth;
@@ -165,11 +162,11 @@
 
 void SurfaceControl::updateDefaultBufferSize(uint32_t width, uint32_t height) {
     Mutex::Autolock _l(mLock);
-    mWidth = width; mHeight = height;
+    mWidth = width;
+    mHeight = height;
     if (mBbq) {
         mBbq->update(mBbqChild, width, height, mFormat);
     }
-
 }
 
 sp<IBinder> SurfaceControl::getLayerStateHandle() const
@@ -245,9 +242,7 @@
     *outSurfaceControl =
             new SurfaceControl(new SurfaceComposerClient(
                                        interface_cast<ISurfaceComposerClient>(client)),
-                               handle.get(), nullptr, layerId,
-                               width, height, format,
-                               transformHint);
+                               handle.get(), layerId, width, height, format, transformHint);
 
     return NO_ERROR;
 }
diff --git a/libs/gui/TransactionTracing.cpp b/libs/gui/TransactionTracing.cpp
index eedc3df..59450fb 100644
--- a/libs/gui/TransactionTracing.cpp
+++ b/libs/gui/TransactionTracing.cpp
@@ -15,9 +15,9 @@
  */
 
 #include "gui/TransactionTracing.h"
-#include "gui/ISurfaceComposer.h"
+#include "android/gui/ISurfaceComposer.h"
 
-#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 
 namespace android {
 
@@ -32,7 +32,7 @@
     if (sInstance == nullptr) {
         sInstance = new TransactionTraceListener;
 
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
         sf->addTransactionTraceListener(sInstance);
     }
 
@@ -50,4 +50,4 @@
     return mTracingEnabled;
 }
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 4e966d1..804ce4f 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -76,7 +76,7 @@
             info.inputConfig == inputConfig && info.displayId == displayId &&
             info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
             info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType &&
-            info.layoutParamsFlags == layoutParamsFlags && info.isClone == isClone;
+            info.layoutParamsFlags == layoutParamsFlags;
 }
 
 status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
@@ -124,8 +124,7 @@
         parcel->write(touchableRegion) ?:
         parcel->writeBool(replaceTouchableRegionWithCrop) ?:
         parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?:
-        parcel->writeStrongBinder(windowToken) ?:
-        parcel->writeBool(isClone);
+        parcel->writeStrongBinder(windowToken);
     // clang-format on
     return status;
 }
@@ -176,8 +175,7 @@
         parcel->read(touchableRegion) ?:
         parcel->readBool(&replaceTouchableRegionWithCrop) ?:
         parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?:
-        parcel->readNullableStrongBinder(&windowToken) ?:
-        parcel->readBool(&isClone);
+        parcel->readNullableStrongBinder(&windowToken);
     // clang-format on
 
     if (status != OK) {
diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp
index cfc7dbc..01e865d 100644
--- a/libs/gui/WindowInfosListenerReporter.cpp
+++ b/libs/gui/WindowInfosListenerReporter.cpp
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#include <gui/ISurfaceComposer.h>
+#include <android/gui/ISurfaceComposer.h>
+#include <gui/AidlStatusUtil.h>
 #include <gui/WindowInfosListenerReporter.h>
 
 namespace android {
@@ -23,6 +24,7 @@
 using gui::IWindowInfosReportedListener;
 using gui::WindowInfo;
 using gui::WindowInfosListener;
+using gui::aidl_utils::statusTFromBinderStatus;
 
 sp<WindowInfosListenerReporter> WindowInfosListenerReporter::getInstance() {
     static sp<WindowInfosListenerReporter> sInstance = new WindowInfosListenerReporter;
@@ -31,13 +33,14 @@
 
 status_t WindowInfosListenerReporter::addWindowInfosListener(
         const sp<WindowInfosListener>& windowInfosListener,
-        const sp<ISurfaceComposer>& surfaceComposer,
+        const sp<gui::ISurfaceComposer>& surfaceComposer,
         std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo) {
     status_t status = OK;
     {
         std::scoped_lock lock(mListenersMutex);
         if (mWindowInfosListeners.empty()) {
-            status = surfaceComposer->addWindowInfosListener(this);
+            binder::Status s = surfaceComposer->addWindowInfosListener(this);
+            status = statusTFromBinderStatus(s);
         }
 
         if (status == OK) {
@@ -55,12 +58,13 @@
 
 status_t WindowInfosListenerReporter::removeWindowInfosListener(
         const sp<WindowInfosListener>& windowInfosListener,
-        const sp<ISurfaceComposer>& surfaceComposer) {
+        const sp<gui::ISurfaceComposer>& surfaceComposer) {
     status_t status = OK;
     {
         std::scoped_lock lock(mListenersMutex);
         if (mWindowInfosListeners.size() == 1) {
-            status = surfaceComposer->removeWindowInfosListener(this);
+            binder::Status s = surfaceComposer->removeWindowInfosListener(this);
+            status = statusTFromBinderStatus(s);
             // Clear the last stored state since we're disabling updates and don't want to hold
             // stale values
             mLastWindowInfos.clear();
@@ -78,7 +82,8 @@
 binder::Status WindowInfosListenerReporter::onWindowInfosChanged(
         const std::vector<WindowInfo>& windowInfos, const std::vector<DisplayInfo>& displayInfos,
         const sp<IWindowInfosReportedListener>& windowInfosReportedListener) {
-    std::unordered_set<sp<WindowInfosListener>, SpHash<WindowInfosListener>> windowInfosListeners;
+    std::unordered_set<sp<WindowInfosListener>, gui::SpHash<WindowInfosListener>>
+            windowInfosListeners;
 
     {
         std::scoped_lock lock(mListenersMutex);
@@ -101,7 +106,7 @@
     return binder::Status::ok();
 }
 
-void WindowInfosListenerReporter::reconnect(const sp<ISurfaceComposer>& composerService) {
+void WindowInfosListenerReporter::reconnect(const sp<gui::ISurfaceComposer>& composerService) {
     std::scoped_lock lock(mListenersMutex);
     if (!mWindowInfosListeners.empty()) {
         composerService->addWindowInfosListener(this);
diff --git a/libs/gui/aidl/android/gui/Rect.aidl b/libs/gui/aidl/android/gui/ARect.aidl
similarity index 98%
rename from libs/gui/aidl/android/gui/Rect.aidl
rename to libs/gui/aidl/android/gui/ARect.aidl
index 1b13761..5785907 100644
--- a/libs/gui/aidl/android/gui/Rect.aidl
+++ b/libs/gui/aidl/android/gui/ARect.aidl
@@ -20,7 +20,7 @@
 // TODO(b/221473398):
 // use hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
 /** @hide */
-parcelable Rect {
+parcelable ARect {
     /// Minimum X coordinate of the rectangle.
     int left;
 
diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/Color.aidl
similarity index 64%
copy from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
copy to libs/gui/aidl/android/gui/Color.aidl
index 6929a6c..12af066 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/gui/aidl/android/gui/Color.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,12 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.gui;
 
-import android.content.pm.PackageChangeEvent;
-
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
+/** @hide */
+parcelable Color {
+    float r;
+    float g;
+    float b;
+    float a;
 }
diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/CompositionPreference.aidl
similarity index 63%
copy from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
copy to libs/gui/aidl/android/gui/CompositionPreference.aidl
index 6929a6c..b615824 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/gui/aidl/android/gui/CompositionPreference.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,12 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.gui;
 
-import android.content.pm.PackageChangeEvent;
-
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
+/** @hide */
+parcelable CompositionPreference {
+    int /*ui::Dataspace*/   defaultDataspace;
+    int /*ui::PixelFormat*/ defaultPixelFormat;
+    int /*ui::Dataspace*/   wideColorGamutDataspace;
+    int /*ui::PixelFormat*/ wideColorGamutPixelFormat;
 }
diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/ContentSamplingAttributes.aidl
similarity index 64%
copy from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
copy to libs/gui/aidl/android/gui/ContentSamplingAttributes.aidl
index 6929a6c..5d913b1 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/gui/aidl/android/gui/ContentSamplingAttributes.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,11 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.gui;
 
-import android.content.pm.PackageChangeEvent;
-
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
+/** @hide */
+parcelable ContentSamplingAttributes {
+    int /*ui::PixelFormat*/ format;
+    int /*ui::Dataspace*/ dataspace;
+    byte componentMask;
 }
diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/CreateSurfaceResult.aidl
similarity index 64%
rename from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
rename to libs/gui/aidl/android/gui/CreateSurfaceResult.aidl
index 6929a6c..39e4916 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/gui/aidl/android/gui/CreateSurfaceResult.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,11 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.gui;
 
-import android.content.pm.PackageChangeEvent;
-
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
+/** @hide */
+parcelable CreateSurfaceResult {
+    IBinder handle;
+    int layerId;
+    int transformHint;
 }
diff --git a/libs/gui/aidl/android/gui/DeviceProductInfo.aidl b/libs/gui/aidl/android/gui/DeviceProductInfo.aidl
new file mode 100644
index 0000000..98404cf
--- /dev/null
+++ b/libs/gui/aidl/android/gui/DeviceProductInfo.aidl
@@ -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.
+ */
+
+package android.gui;
+
+// Product-specific information about the display or the directly connected device on the
+// display chain. For example, if the display is transitively connected, this field may contain
+// product information about the intermediate device.
+
+/** @hide */
+parcelable DeviceProductInfo {
+    parcelable ModelYear {
+        int year;
+    }
+
+    parcelable ManufactureYear {
+        ModelYear modelYear;
+    }
+
+    parcelable ManufactureWeekAndYear {
+        ManufactureYear manufactureYear;
+
+        // 1-base week number. Week numbering may not be consistent between manufacturers.
+        int week;
+    }
+
+    union ManufactureOrModelDate {
+        ModelYear modelYear;
+        ManufactureYear manufactureYear;
+        ManufactureWeekAndYear manufactureWeekAndYear;
+    }
+
+    // Display name.
+    @utf8InCpp String name;
+
+    // NULL-terminated Manufacturer plug and play ID.
+    byte[] manufacturerPnpId;
+
+    // Manufacturer product ID.
+    @utf8InCpp String productId;
+
+    ManufactureOrModelDate manufactureOrModelDate;
+
+    byte[] relativeAddress;
+}
diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/DisplayConnectionType.aidl
similarity index 64%
copy from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
copy to libs/gui/aidl/android/gui/DisplayConnectionType.aidl
index 6929a6c..72c4ede 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/gui/aidl/android/gui/DisplayConnectionType.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,11 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.gui;
 
-import android.content.pm.PackageChangeEvent;
-
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
+/** @hide */
+@Backing(type="int")
+enum DisplayConnectionType {
+   Internal = 0,
+   External = 1
 }
diff --git a/libs/input/android/os/BlockUntrustedTouchesMode.aidl b/libs/gui/aidl/android/gui/DisplayDecorationSupport.aidl
similarity index 60%
rename from libs/input/android/os/BlockUntrustedTouchesMode.aidl
rename to libs/gui/aidl/android/gui/DisplayDecorationSupport.aidl
index 9504e99..0230496 100644
--- a/libs/input/android/os/BlockUntrustedTouchesMode.aidl
+++ b/libs/gui/aidl/android/gui/DisplayDecorationSupport.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2020, The Android Open Source Project
+ * 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.
@@ -14,22 +14,12 @@
  * limitations under the License.
  */
 
-package android.os;
+package android.gui;
 
-
-/**
-  * 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
+// TODO(b/222607970):
+// remove this aidl and use android.hardware.graphics.common.DisplayDecorationSupport
+/** @hide */
+parcelable DisplayDecorationSupport {
+    int format;
+    int alphaInterpretation;
 }
diff --git a/libs/gui/aidl/android/gui/Rect.aidl b/libs/gui/aidl/android/gui/DisplayMode.aidl
similarity index 60%
copy from libs/gui/aidl/android/gui/Rect.aidl
copy to libs/gui/aidl/android/gui/DisplayMode.aidl
index 1b13761..3cd77f8 100644
--- a/libs/gui/aidl/android/gui/Rect.aidl
+++ b/libs/gui/aidl/android/gui/DisplayMode.aidl
@@ -16,20 +16,21 @@
 
 package android.gui;
 
-// copied from libs/arect/include/android/rect.h
-// TODO(b/221473398):
-// use hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
+import android.gui.Size;
+
+// Mode supported by physical display.
+// Make sure to sync with libui DisplayMode.h
+
 /** @hide */
-parcelable Rect {
-    /// Minimum X coordinate of the rectangle.
-    int left;
+parcelable DisplayMode {
+    int id;
+    Size resolution;
+    float xDpi = 0.0f;
+    float yDpi = 0.0f;
 
-    /// Minimum Y coordinate of the rectangle.
-    int top;
-
-    /// Maximum X coordinate of the rectangle.
-    int right;
-
-    /// Maximum Y coordinate of the rectangle.
-    int bottom;
+    float refreshRate = 0.0f;
+    long appVsyncOffset = 0;
+    long sfVsyncOffset = 0;
+    long presentationDeadline = 0;
+    int group = -1;
 }
diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/DisplayModeSpecs.aidl
similarity index 64%
copy from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
copy to libs/gui/aidl/android/gui/DisplayModeSpecs.aidl
index 6929a6c..fb4fcdf 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/gui/aidl/android/gui/DisplayModeSpecs.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.gui;
 
-import android.content.pm.PackageChangeEvent;
-
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
+/** @hide */
+parcelable DisplayModeSpecs {
+    int defaultMode;
+    boolean allowGroupSwitching;
+    float primaryRefreshRateMin;
+    float primaryRefreshRateMax;
+    float appRequestRefreshRateMin;
+    float appRequestRefreshRateMax;
 }
diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/DisplayPrimaries.aidl
similarity index 64%
copy from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
copy to libs/gui/aidl/android/gui/DisplayPrimaries.aidl
index 6929a6c..dbf668c 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/gui/aidl/android/gui/DisplayPrimaries.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,20 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.gui;
 
-import android.content.pm.PackageChangeEvent;
+// copied from libui ConfigStoreTypes.h
 
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
+/** @hide */
+parcelable DisplayPrimaries {
+    parcelable CieXyz {
+        float X;
+        float Y;
+        float Z;
+    }
+
+    CieXyz red;
+    CieXyz green;
+    CieXyz blue;
+    CieXyz white;
 }
diff --git a/libs/gui/aidl/android/gui/DisplayedFrameStats.aidl b/libs/gui/aidl/android/gui/DisplayedFrameStats.aidl
new file mode 100644
index 0000000..f4b6dad
--- /dev/null
+++ b/libs/gui/aidl/android/gui/DisplayedFrameStats.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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 android.gui;
+
+/** @hide */
+parcelable DisplayedFrameStats {
+    /* The number of frames represented by this sample. */
+    long numFrames = 0;
+
+    /* A histogram counting how many times a pixel of a given value was displayed onscreen for
+     * FORMAT_COMPONENT_0. The buckets of the histogram are evenly weighted, the number of buckets
+     * is device specific. eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that
+     * 10 red pixels were displayed onscreen in range 0x00->0x3F, 6 red pixels
+     * were displayed onscreen in range 0x40->0x7F, etc.
+     */
+    long[] component_0_sample;
+
+    /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_1. */
+    long[] component_1_sample;
+
+    /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_2. */
+    long[] component_2_sample;
+
+    /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_3. */
+    long[] component_3_sample;
+}
diff --git a/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl
new file mode 100644
index 0000000..57e6081
--- /dev/null
+++ b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl
@@ -0,0 +1,45 @@
+/*
+ * 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 android.gui;
+
+import android.gui.DisplayMode;
+import android.gui.HdrCapabilities;
+
+// Information about a physical display which may change on hotplug reconnect.
+// Make sure to sync with libui DynamicDisplayInfo.h
+
+/** @hide */
+parcelable DynamicDisplayInfo {
+    List<DisplayMode> supportedDisplayModes;
+
+    int activeDisplayModeId;
+
+    int[] supportedColorModes;
+    int activeColorMode;
+    HdrCapabilities hdrCapabilities;
+
+    // True if the display reports support for HDMI 2.1 Auto Low Latency Mode.
+    // For more information, see the HDMI 2.1 specification.
+    boolean autoLowLatencyModeSupported;
+
+    // True if the display reports support for Game Content Type.
+    // For more information, see the HDMI 1.4 specification.
+    boolean gameContentTypeSupported;
+
+    // The boot display mode preferred by the implementation.
+    int preferredBootDisplayMode;
+}
diff --git a/libs/gui/aidl/android/gui/Rect.aidl b/libs/gui/aidl/android/gui/FrameEvent.aidl
similarity index 60%
copy from libs/gui/aidl/android/gui/Rect.aidl
copy to libs/gui/aidl/android/gui/FrameEvent.aidl
index 1b13761..aaabdb5 100644
--- a/libs/gui/aidl/android/gui/Rect.aidl
+++ b/libs/gui/aidl/android/gui/FrameEvent.aidl
@@ -16,20 +16,20 @@
 
 package android.gui;
 
-// copied from libs/arect/include/android/rect.h
-// TODO(b/221473398):
-// use hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
+// Identifiers for all the events that may be recorded or reported.
+
 /** @hide */
-parcelable Rect {
-    /// Minimum X coordinate of the rectangle.
-    int left;
-
-    /// Minimum Y coordinate of the rectangle.
-    int top;
-
-    /// Maximum X coordinate of the rectangle.
-    int right;
-
-    /// Maximum Y coordinate of the rectangle.
-    int bottom;
+@Backing(type="int")
+enum FrameEvent {
+    POSTED = 0,
+    REQUESTED_PRESENT = 1,
+    LATCH = 2,
+    ACQUIRE = 3,
+    FIRST_REFRESH_START = 4,
+    LAST_REFRESH_START = 5,
+    GPU_COMPOSITION_DONE = 6,
+    DISPLAY_PRESENT = 7,
+    DEQUEUE_READY = 8,
+    RELEASE = 9,
+    EVENT_COUNT = 10 // Not an actual event.
 }
diff --git a/libs/gui/aidl/android/gui/FrameStats.aidl b/libs/gui/aidl/android/gui/FrameStats.aidl
new file mode 100644
index 0000000..a145e74
--- /dev/null
+++ b/libs/gui/aidl/android/gui/FrameStats.aidl
@@ -0,0 +1,47 @@
+/*
+ * 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 android.gui;
+
+// Make sure to sync with libui FrameStats.h
+
+/** @hide */
+parcelable FrameStats {
+    /*
+     * Approximate refresh time, in nanoseconds.
+     */
+    long refreshPeriodNano;
+
+    /*
+     * The times in nanoseconds for when the frame contents were posted by the producer (e.g.
+     * the application). They are either explicitly set or defaulted to the time when
+     * Surface::queueBuffer() was called.
+     */
+    long[] desiredPresentTimesNano;
+
+    /*
+     * The times in milliseconds for when the frame contents were presented on the screen.
+     */
+    long[] actualPresentTimesNano;
+
+    /*
+     * The times in nanoseconds for when the frame contents were ready to be presented. Note that
+     * a frame can be posted and still it contents being rendered asynchronously in GL. In such a
+     * case these are the times when the frame contents were completely rendered (i.e. their fences
+     * signaled).
+     */
+    long[] frameReadyTimesNano;
+}
diff --git a/libs/gui/include/gui/FrameTimelineInfo.h b/libs/gui/aidl/android/gui/FrameTimelineInfo.aidl
similarity index 69%
rename from libs/gui/include/gui/FrameTimelineInfo.h
rename to libs/gui/aidl/android/gui/FrameTimelineInfo.aidl
index 255ce56..6ffe466 100644
--- a/libs/gui/include/gui/FrameTimelineInfo.h
+++ b/libs/gui/aidl/android/gui/FrameTimelineInfo.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 The Android Open Source Project
+ * 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.
@@ -14,36 +14,23 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.gui;
 
-#include <stdint.h>
-
-#include <binder/Parcel.h>
-
-namespace android {
-
-struct FrameTimelineInfo {
+/** @hide */
+parcelable FrameTimelineInfo {
     // Needs to be in sync with android.graphics.FrameInfo.INVALID_VSYNC_ID in java
-    static constexpr int64_t INVALID_VSYNC_ID = -1;
+    const long INVALID_VSYNC_ID = -1;
 
     // The vsync id that was used to start the transaction
-    int64_t vsyncId = INVALID_VSYNC_ID;
+    long vsyncId = INVALID_VSYNC_ID;
 
     // The id of the input event that caused this buffer
     // Default is android::os::IInputConstants::INVALID_INPUT_EVENT_ID = 0
     // We copy the value of the input event ID instead of including the header, because libgui
     // header libraries containing FrameTimelineInfo must be available to vendors, but libinput is
     // not directly vendor available.
-    int32_t inputEventId = 0;
+    int inputEventId = 0;
 
     // The current time in nanoseconds the application started to render the frame.
-    int64_t startTimeNanos = 0;
-
-    status_t write(Parcel& output) const;
-    status_t read(const Parcel& input);
-
-    void merge(const FrameTimelineInfo& other);
-    void clear();
-};
-
-} // namespace android
+    long startTimeNanos = 0;
+}
diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/HdrCapabilities.aidl
similarity index 64%
copy from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
copy to libs/gui/aidl/android/gui/HdrCapabilities.aidl
index 6929a6c..9d06da9 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/gui/aidl/android/gui/HdrCapabilities.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.gui;
 
-import android.content.pm.PackageChangeEvent;
+// Make sure to sync with libui HdrCapabilities.h
 
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
+/** @hide */
+parcelable HdrCapabilities {
+    int[] supportedHdrTypes;
+    float maxLuminance;
+    float maxAverageLuminance;
+    float minLuminance;
 }
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index b31b37b..730d758 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -16,39 +16,99 @@
 
 package android.gui;
 
-import android.gui.DisplayCaptureArgs;
+import android.gui.Color;
+import android.gui.CompositionPreference;
+import android.gui.ContentSamplingAttributes;
 import android.gui.DisplayBrightness;
+import android.gui.DisplayCaptureArgs;
+import android.gui.DisplayDecorationSupport;
+import android.gui.DisplayedFrameStats;
+import android.gui.DisplayModeSpecs;
+import android.gui.DisplayPrimaries;
 import android.gui.DisplayState;
 import android.gui.DisplayStatInfo;
+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.LayerCaptureArgs;
+import android.gui.IRegionSamplingListener;
 import android.gui.IScreenCaptureListener;
+import android.gui.ISurfaceComposerClient;
+import android.gui.ITransactionTraceListener;
+import android.gui.ITunnelModeEnabledListener;
+import android.gui.IWindowInfosListener;
+import android.gui.LayerCaptureArgs;
+import android.gui.LayerDebugInfo;
+import android.gui.PullAtomData;
+import android.gui.ARect;
+import android.gui.StaticDisplayInfo;
 
 /** @hide */
 interface ISurfaceComposer {
 
-    /* create a virtual display
+    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.
+     */
+    @nullable ISurfaceComposerClient createConnection();
+
+    /**
+     * Create a virtual display
      * requires ACCESS_SURFACE_FLINGER permission.
      */
     @nullable IBinder createDisplay(@utf8InCpp String displayName, boolean secure);
 
-    /* destroy a virtual display
+    /**
+     * Destroy a virtual display
      * requires ACCESS_SURFACE_FLINGER permission.
      */
     void destroyDisplay(IBinder display);
 
-    /* get stable IDs for connected physical displays.
+    /**
+     * Get stable IDs for connected physical displays.
      */
     long[] getPhysicalDisplayIds();
 
     long getPrimaryPhysicalDisplayId();
 
-    /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
-     * DisplayEventReceiver hotplug event.
+    /**
+     * Get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or
+     * a DisplayEventReceiver hotplug event.
      */
     @nullable IBinder getPhysicalDisplayToken(long displayId);
 
-    /* set display power mode. depending on the mode, it can either trigger
+    /**
+     * Returns the frame timestamps supported by SurfaceFlinger.
+     */
+    FrameEvent[] getSupportedFrameTimestamps();
+
+    /**
+     * Set display power mode. depending on the mode, it can either trigger
      * screen on, off or low power mode and wait for it to complete.
      * requires ACCESS_SURFACE_FLINGER permission.
      */
@@ -60,12 +120,31 @@
      * video frames */
     DisplayStatInfo getDisplayStats(@nullable IBinder display);
 
-     /**
+    /**
      * Get transactional state of given display.
      */
     DisplayState getDisplayState(IBinder display);
 
     /**
+     * Gets immutable information about given physical display.
+     */
+    StaticDisplayInfo getStaticDisplayInfo(IBinder display);
+
+    /**
+     * Gets dynamic information about given physical display.
+     */
+    DynamicDisplayInfo getDynamicDisplayInfo(IBinder display);
+
+    DisplayPrimaries getDisplayNativePrimaries(IBinder display);
+
+    void setActiveColorMode(IBinder display, int colorMode);
+
+    /**
+     * Sets the user-preferred display mode that a device should boot in.
+     */
+    void setBootDisplayMode(IBinder display, int displayModeId);
+
+    /**
      * Clears the user-preferred display mode. The device should now boot in system preferred
      * display mode.
      */
@@ -110,7 +189,9 @@
      * match the size of the output buffer.
      */
     void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener);
+
     void captureDisplayById(long displayId, IScreenCaptureListener listener);
+
     /**
      * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
      * This requires READ_FRAME_BUFFER permission. This function will fail if there
@@ -118,13 +199,163 @@
      */
     void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener);
 
-    /*
+    /**
+     * Clears the frame statistics for animations.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    void clearAnimationFrameStats();
+
+    /**
+     * Gets the frame statistics for animations.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    FrameStats getAnimationFrameStats();
+
+    /**
+     * Overrides the supported HDR modes for the given display device.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    void overrideHdrTypes(IBinder display, in int[] hdrTypes);
+
+    /**
+     * Pulls surfaceflinger atoms global stats and layer stats to pipe to statsd.
+     *
+     * Requires the calling uid be from system server.
+     */
+    PullAtomData onPullAtom(int atomId);
+
+    oneway void enableVSyncInjections(boolean enable);
+
+    oneway void injectVSync(long when);
+
+    /**
+     * Gets the list of active layers in Z order for debugging purposes
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    List<LayerDebugInfo> getLayerDebugInfo();
+
+    boolean getColorManagement();
+
+    /**
+     * Gets the composition preference of the default data space and default pixel format,
+     * as well as the wide color gamut data space and wide color gamut pixel format.
+     * If the wide color gamut data space is V0_SRGB, then it implies that the platform
+     * has no wide color gamut support.
+     *
+     */
+    CompositionPreference getCompositionPreference();
+
+    /**
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    ContentSamplingAttributes getDisplayedContentSamplingAttributes(IBinder display);
+
+    /**
+     * Turns on the color sampling engine on the display.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    void setDisplayContentSamplingEnabled(IBinder display, boolean enable, byte componentMask, long maxFrames);
+
+    /**
+     * Returns statistics on the color profile of the last frame displayed for a given display
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    DisplayedFrameStats getDisplayedContentSample(IBinder display, long maxFrames, long timestamp);
+
+    /**
+     * Gets whether SurfaceFlinger can support protected content in GPU composition.
+     */
+    boolean getProtectedContentSupport();
+
+    /**
      * Queries whether the given display is a wide color display.
      * Requires the ACCESS_SURFACE_FLINGER permission.
      */
     boolean isWideColorDisplay(IBinder token);
 
-    /*
+    /**
+     * Registers a listener to stream median luma updates from SurfaceFlinger.
+     *
+     * The sampling area is bounded by both samplingArea and the given stopLayerHandle
+     * (i.e., only layers behind the stop layer will be captured and sampled).
+     *
+     * Multiple listeners may be provided so long as they have independent listeners.
+     * If multiple listeners are provided, the effective sampling region for each listener will
+     * be bounded by whichever stop layer has a lower Z value.
+     *
+     * Requires the same permissions as captureLayers and captureScreen.
+     */
+    void addRegionSamplingListener(in ARect samplingArea, @nullable IBinder stopLayerHandle, IRegionSamplingListener listener);
+
+    /**
+     * Removes a listener that was streaming median luma updates from SurfaceFlinger.
+     */
+    void removeRegionSamplingListener(IRegionSamplingListener listener);
+
+    /**
+     * Registers a listener that streams fps updates from SurfaceFlinger.
+     *
+     * The listener will stream fps updates for the layer tree rooted at the layer denoted by the
+     * task ID, i.e., the layer must have the task ID as part of its layer metadata with key
+     * METADATA_TASK_ID. If there is no such layer, then no fps is expected to be reported.
+     *
+     * Multiple listeners may be supported.
+     *
+     * Requires the READ_FRAME_BUFFER permission.
+     */
+    void addFpsListener(int taskId, IFpsListener listener);
+
+    /**
+     * Removes a listener that was streaming fps updates from SurfaceFlinger.
+     */
+    void removeFpsListener(IFpsListener listener);
+
+    /**
+     * Registers a listener to receive tunnel mode enabled updates from SurfaceFlinger.
+     *
+     * Requires ACCESS_SURFACE_FLINGER permission.
+     */
+    void addTunnelModeEnabledListener(ITunnelModeEnabledListener listener);
+
+    /**
+     * Removes a listener that was receiving tunnel mode enabled updates from SurfaceFlinger.
+     *
+     * Requires ACCESS_SURFACE_FLINGER permission.
+     */
+    void removeTunnelModeEnabledListener(ITunnelModeEnabledListener listener);
+
+    /**
+     * Sets the refresh rate boundaries for the display.
+     *
+     * The primary refresh rate range represents display manager's general guidance on the display
+     * modes we'll consider when switching refresh rates. Unless we get an explicit signal from an
+     * app, we should stay within this range.
+     *
+     * The app request refresh rate range allows us to consider more display modes when switching
+     * refresh rates. Although we should generally stay within the primary range, specific
+     * considerations, such as layer frame rate settings specified via the setFrameRate() api, may
+     * cause us to go outside the primary range. We never go outside the app request range. The app
+     * request range will be greater than or equal to the primary refresh rate range, never smaller.
+     *
+     * defaultMode is used to narrow the list of display modes SurfaceFlinger will consider
+     * switching between. Only modes with a mode group and resolution matching defaultMode
+     * will be considered for switching. The defaultMode corresponds to an ID of mode in the list
+     * of supported modes returned from getDynamicDisplayInfo().
+     */
+    void setDesiredDisplayModeSpecs(
+            IBinder displayToken, int defaultMode,
+            boolean allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax,
+            float appRequestRefreshRateMin, float appRequestRefreshRateMax);
+
+    DisplayModeSpecs getDesiredDisplayModeSpecs(IBinder displayToken);
+
+    /**
      * Gets whether brightness operations are supported on a display.
      *
      * displayToken
@@ -138,7 +369,7 @@
      */
     boolean getDisplayBrightnessSupport(IBinder displayToken);
 
-    /*
+    /**
      * Sets the brightness of a display.
      *
      * displayToken
@@ -153,7 +384,7 @@
      */
     void setDisplayBrightness(IBinder displayToken, in DisplayBrightness brightness);
 
-    /*
+    /**
      * Adds a listener that receives HDR layer information. This is used in combination
      * with setDisplayBrightness to adjust the display brightness depending on factors such
      * as whether or not HDR is in use.
@@ -162,7 +393,7 @@
      */
     void addHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
 
-    /*
+    /**
      * Removes a listener that was added with addHdrLayerInfoListener.
      *
      * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if
@@ -171,7 +402,7 @@
      */
     void removeHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
 
-    /*
+    /**
      * Sends a power boost to the composer. This function is asynchronous.
      *
      * boostId
@@ -179,5 +410,78 @@
      *
      * Returns NO_ERROR upon success.
      */
-    void notifyPowerBoost(int boostId);
+    oneway void notifyPowerBoost(int boostId);
+
+    /*
+     * Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows
+     * material design guidelines.
+     *
+     * ambientColor
+     *      Color to the ambient shadow. The alpha is premultiplied.
+     *
+     * spotColor
+     *      Color to the spot shadow. The alpha is premultiplied. The position of the spot shadow
+     *      depends on the light position.
+     *
+     * lightPosY/lightPosZ
+     *      Position of the light used to cast the spot shadow. The X value is always the display
+     *      width / 2.
+     *
+     * lightRadius
+     *      Radius of the light casting the shadow.
+     */
+    oneway void setGlobalShadowSettings(in Color ambientColor, in Color spotColor, float lightPosY, float lightPosZ, float lightRadius);
+
+    /**
+     * Gets whether a display supports DISPLAY_DECORATION layers.
+     *
+     * displayToken
+     *      The token of the display.
+     * outSupport
+     *      An output parameter for whether/how the display supports
+     *      DISPLAY_DECORATION layers.
+     *
+     * Returns NO_ERROR upon success. Otherwise,
+     *      NAME_NOT_FOUND if the display is invalid, or
+     *      BAD_VALUE      if the output parameter is invalid.
+     */
+    @nullable DisplayDecorationSupport getDisplayDecorationSupport(IBinder displayToken);
+
+    /**
+     * Set the override frame rate for a specified uid by GameManagerService.
+     * Passing the frame rate and uid to SurfaceFlinger to update the override mapping
+     * in the scheduler.
+     */
+    void setOverrideFrameRate(int uid, float frameRate);
+
+    /**
+     * Adds a TransactionTraceListener to listen for transaction tracing state updates.
+     */
+    void addTransactionTraceListener(ITransactionTraceListener listener);
+
+    /**
+     * Gets priority of the RenderEngine in SurfaceFlinger.
+     */
+    int getGpuContextPriority();
+
+    /**
+     * Gets the number of buffers SurfaceFlinger would need acquire. This number
+     * would be propagated to the client via MIN_UNDEQUEUED_BUFFERS so that the
+     * client could allocate enough buffers to match SF expectations of the
+     * pipeline depth. SurfaceFlinger will make sure that it will give the app at
+     * least the time configured as the 'appDuration' before trying to latch
+     * the buffer.
+     *
+     * The total buffers needed for a given configuration is basically the
+     * numbers of vsyncs a single buffer is used across the stack. For the default
+     * configuration a buffer is held ~1 vsync by the app, ~1 vsync by SurfaceFlinger
+     * and 1 vsync by the display. The extra buffers are calculated as the
+     * number of additional buffers on top of the 2 buffers already present
+     * in MIN_UNDEQUEUED_BUFFERS.
+     */
+    int getMaxAcquiredBufferCount();
+
+    void addWindowInfosListener(IWindowInfosListener windowInfosListener);
+
+    void removeWindowInfosListener(IWindowInfosListener windowInfosListener);
 }
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl
new file mode 100644
index 0000000..71933aa
--- /dev/null
+++ b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl
@@ -0,0 +1,62 @@
+/*
+ * 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 android.gui;
+
+import android.gui.CreateSurfaceResult;
+import android.gui.FrameStats;
+import android.gui.LayerMetadata;
+import android.gui.MirrorSurfaceResult;
+
+/** @hide */
+interface ISurfaceComposerClient {
+
+    // flags for createSurface()
+    // (keep in sync with SurfaceControl.java)
+    const int eHidden = 0x00000004;
+    const int eDestroyBackbuffer = 0x00000020;
+    const int eSkipScreenshot = 0x00000040;
+    const int eSecure = 0x00000080;
+    const int eNonPremultiplied = 0x00000100;
+    const int eOpaque = 0x00000400;
+    const int eProtectedByApp = 0x00000800;
+    const int eProtectedByDRM = 0x00001000;
+    const int eCursorWindow = 0x00002000;
+    const int eNoColorFill = 0x00004000;
+
+    const int eFXSurfaceBufferQueue = 0x00000000;
+    const int eFXSurfaceEffect = 0x00020000;
+    const int eFXSurfaceBufferState = 0x00040000;
+    const int eFXSurfaceContainer = 0x00080000;
+    const int eFXSurfaceMask = 0x000F0000;
+
+    /**
+     * Requires ACCESS_SURFACE_FLINGER permission
+     */
+    CreateSurfaceResult createSurface(@utf8InCpp String name, int flags, @nullable IBinder parent, in LayerMetadata metadata);
+
+    /**
+     * Requires ACCESS_SURFACE_FLINGER permission
+     */
+    void clearLayerFrameStats(IBinder handle);
+
+    /**
+     * Requires ACCESS_SURFACE_FLINGER permission
+     */
+    FrameStats getLayerFrameStats(IBinder handle);
+
+    MirrorSurfaceResult mirrorSurface(IBinder mirrorFromHandle);
+}
diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/LayerDebugInfo.aidl
similarity index 63%
copy from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
copy to libs/gui/aidl/android/gui/LayerDebugInfo.aidl
index 6929a6c..faca980 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/gui/aidl/android/gui/LayerDebugInfo.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.gui;
 
-import android.content.pm.PackageChangeEvent;
-
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
-}
+parcelable LayerDebugInfo cpp_header "gui/LayerDebugInfo.h";
diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/LayerMetadata.aidl
similarity index 63%
copy from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
copy to libs/gui/aidl/android/gui/LayerMetadata.aidl
index 6929a6c..1368ac5 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/gui/aidl/android/gui/LayerMetadata.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.gui;
 
-import android.content.pm.PackageChangeEvent;
-
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
-}
+parcelable LayerMetadata cpp_header "gui/LayerMetadata.h";
diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl
similarity index 64%
copy from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
copy to libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl
index 6929a6c..9fac3e8 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,10 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.gui;
 
-import android.content.pm.PackageChangeEvent;
-
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
+/** @hide */
+parcelable MirrorSurfaceResult {
+    IBinder handle;
+    int layerId;
 }
diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/PullAtomData.aidl
similarity index 64%
copy from libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
copy to libs/gui/aidl/android/gui/PullAtomData.aidl
index 6929a6c..14d33c6 100644
--- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl
+++ b/libs/gui/aidl/android/gui/PullAtomData.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,10 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.gui;
 
-import android.content.pm.PackageChangeEvent;
-
-/**
- * This is a non-blocking notification when a package has changed.
- *
- * @hide
- */
-oneway interface IPackageChangeObserver {
-  void onPackageChanged(in PackageChangeEvent event);
+/** @hide */
+parcelable PullAtomData {
+    @utf8InCpp String data;
+    boolean success;
 }
diff --git a/libs/gui/aidl/android/gui/Rect.aidl b/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl
similarity index 60%
copy from libs/gui/aidl/android/gui/Rect.aidl
copy to libs/gui/aidl/android/gui/StaticDisplayInfo.aidl
index 1b13761..0ccda56 100644
--- a/libs/gui/aidl/android/gui/Rect.aidl
+++ b/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl
@@ -16,20 +16,15 @@
 
 package android.gui;
 
-// copied from libs/arect/include/android/rect.h
-// TODO(b/221473398):
-// use hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
+import android.gui.DisplayConnectionType;
+import android.gui.DeviceProductInfo;
+import android.gui.Rotation;
+
 /** @hide */
-parcelable Rect {
-    /// Minimum X coordinate of the rectangle.
-    int left;
-
-    /// Minimum Y coordinate of the rectangle.
-    int top;
-
-    /// Maximum X coordinate of the rectangle.
-    int right;
-
-    /// Maximum Y coordinate of the rectangle.
-    int bottom;
+parcelable StaticDisplayInfo {
+    DisplayConnectionType connectionType = DisplayConnectionType.Internal;
+    float density;
+    boolean secure;
+    @nullable DeviceProductInfo deviceProductInfo;
+    Rotation installOrientation = Rotation.Rotation0;
 }
diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp
new file mode 100644
index 0000000..952b6a9
--- /dev/null
+++ b/libs/gui/fuzzer/Android.bp
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+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",
+    ],
+}
diff --git a/libs/gui/fuzzer/README.md b/libs/gui/fuzzer/README.md
new file mode 100644
index 0000000..c9e8b65
--- /dev/null
+++ b/libs/gui/fuzzer/README.md
@@ -0,0 +1,42 @@
+# Fuzzers for Libgui
+
+## Table of contents
++ [libgui_surfaceComposer_fuzzer](#SurfaceComposer)
+
+# <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
+```
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
new file mode 100644
index 0000000..98e2ea3
--- /dev/null
+++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h
@@ -0,0 +1,311 @@
+/*
+ * 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, getPrimaryPhysicalDisplayId, (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));
+};
+
+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_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/AidlStatusUtil.h b/libs/gui/include/gui/AidlStatusUtil.h
new file mode 100644
index 0000000..55be27b
--- /dev/null
+++ b/libs/gui/include/gui/AidlStatusUtil.h
@@ -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.
+ */
+
+#pragma once
+
+#include <binder/Status.h>
+
+// Extracted from frameworks/av/media/libaudioclient/include/media/AidlConversionUtil.h
+namespace android::gui::aidl_utils {
+
+/**
+ * Return the equivalent Android status_t from a binder exception code.
+ *
+ * Generally one should use statusTFromBinderStatus() instead.
+ *
+ * Exception codes can be generated from a remote Java service exception, translate
+ * them for use on the Native side.
+ *
+ * Note: for EX_TRANSACTION_FAILED and EX_SERVICE_SPECIFIC a more detailed error code
+ * can be found from transactionError() or serviceSpecificErrorCode().
+ */
+static inline status_t statusTFromExceptionCode(int32_t exceptionCode) {
+    using namespace ::android::binder;
+    switch (exceptionCode) {
+        case Status::EX_NONE:
+            return OK;
+        case Status::EX_SECURITY: // Java SecurityException, rethrows locally in Java
+            return PERMISSION_DENIED;
+        case Status::EX_BAD_PARCELABLE:   // Java BadParcelableException, rethrows in Java
+        case Status::EX_ILLEGAL_ARGUMENT: // Java IllegalArgumentException, rethrows in Java
+        case Status::EX_NULL_POINTER:     // Java NullPointerException, rethrows in Java
+            return BAD_VALUE;
+        case Status::EX_ILLEGAL_STATE:         // Java IllegalStateException, rethrows in Java
+        case Status::EX_UNSUPPORTED_OPERATION: // Java UnsupportedOperationException, rethrows
+            return INVALID_OPERATION;
+        case Status::EX_HAS_REPLY_HEADER: // Native strictmode violation
+        case Status::EX_PARCELABLE: // Java bootclass loader (not standard exception), rethrows
+        case Status::EX_NETWORK_MAIN_THREAD: // Java NetworkOnMainThreadException, rethrows
+        case Status::EX_TRANSACTION_FAILED:  // Native - see error code
+        case Status::EX_SERVICE_SPECIFIC:    // Java ServiceSpecificException,
+                                             // rethrows in Java with integer error code
+            return UNKNOWN_ERROR;
+    }
+    return UNKNOWN_ERROR;
+}
+
+/**
+ * Return the equivalent Android status_t from a binder status.
+ *
+ * Used to handle errors from a AIDL method declaration
+ *
+ * [oneway] void method(type0 param0, ...)
+ *
+ * or the following (where return_type is not a status_t)
+ *
+ * return_type method(type0 param0, ...)
+ */
+static inline status_t statusTFromBinderStatus(const ::android::binder::Status &status) {
+    return status.isOk() ? OK // check OK,
+        : status.serviceSpecificErrorCode() // service-side error, not standard Java exception
+                                            // (fromServiceSpecificError)
+        ?: status.transactionError() // a native binder transaction error (fromStatusT)
+        ?: statusTFromExceptionCode(status.exceptionCode()); // a service-side error with a
+                                                    // standard Java exception (fromExceptionCode)
+}
+
+/**
+ * Return a binder::Status from native service status.
+ *
+ * This is used for methods not returning an explicit status_t,
+ * where Java callers expect an exception, not an integer return value.
+ */
+static inline ::android::binder::Status binderStatusFromStatusT(
+        status_t status, const char *optionalMessage = nullptr) {
+    const char *const emptyIfNull = optionalMessage == nullptr ? "" : optionalMessage;
+    // From binder::Status instructions:
+    //  Prefer a generic exception code when possible, then a service specific
+    //  code, and finally a status_t for low level failures or legacy support.
+    //  Exception codes and service specific errors map to nicer exceptions for
+    //  Java clients.
+
+    using namespace ::android::binder;
+    switch (status) {
+        case OK:
+            return Status::ok();
+        case PERMISSION_DENIED: // throw SecurityException on Java side
+            return Status::fromExceptionCode(Status::EX_SECURITY, emptyIfNull);
+        case BAD_VALUE: // throw IllegalArgumentException on Java side
+            return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, emptyIfNull);
+        case INVALID_OPERATION: // throw IllegalStateException on Java side
+            return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, emptyIfNull);
+    }
+
+    // A service specific error will not show on status.transactionError() so
+    // be sure to use statusTFromBinderStatus() for reliable error handling.
+
+    // throw a ServiceSpecificException.
+    return Status::fromServiceSpecificError(status, emptyIfNull);
+}
+
+} // namespace android::gui::aidl_utils
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 9328a54..2ed5260 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;
@@ -251,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
@@ -279,6 +275,8 @@
     uint64_t mLastAppliedFrameNumber = 0;
 
     std::function<void(bool)> mTransactionHangCallback;
+
+    std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex);
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/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 dd3de58..f73bc3b 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_GUI_FRAMETIMESTAMPS_H
 #define ANDROID_GUI_FRAMETIMESTAMPS_H
 
+#include <android/gui/FrameEvent.h>
+
 #include <ui/FenceTime.h>
 #include <utils/Flattenable.h>
 #include <utils/StrongPointer.h>
@@ -31,22 +33,7 @@
 struct FrameEvents;
 class FrameEventHistoryDelta;
 
-
-// Identifiers for all the events that may be recorded or reported.
-enum class FrameEvent {
-    POSTED,
-    REQUESTED_PRESENT,
-    LATCH,
-    ACQUIRE,
-    FIRST_REFRESH_START,
-    LAST_REFRESH_START,
-    GPU_COMPOSITION_DONE,
-    DISPLAY_PRESENT,
-    DEQUEUE_READY,
-    RELEASE,
-    EVENT_COUNT, // Not an actual event.
-};
-
+using gui::FrameEvent;
 
 // A collection of timestamps corresponding to a single frame.
 struct FrameEvents {
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 a610e94..1e85131 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <android/gui/DisplayBrightness.h>
+#include <android/gui/FrameTimelineInfo.h>
 #include <android/gui/IDisplayEventConnection.h>
 #include <android/gui/IFpsListener.h>
 #include <android/gui/IHdrLayerInfoListener.h>
@@ -27,8 +28,6 @@
 #include <android/gui/IWindowInfosListener.h>
 #include <binder/IBinder.h>
 #include <binder/IInterface.h>
-#include <ftl/flags.h>
-#include <gui/FrameTimelineInfo.h>
 #include <gui/ITransactionCompletedListener.h>
 #include <gui/SpHash.h>
 #include <math/vec4.h>
@@ -61,13 +60,10 @@
 struct DisplayStatInfo;
 struct DisplayState;
 struct InputWindowCommands;
-class LayerDebugInfo;
 class HdrCapabilities;
-class IGraphicBufferProducer;
-class ISurfaceComposerClient;
 class Rect;
-enum class FrameEvent;
 
+using gui::FrameTimelineInfo;
 using gui::IDisplayEventConnection;
 using gui::IRegionSamplingListener;
 using gui::IScreenCaptureListener;
@@ -77,6 +73,7 @@
 
 struct DisplayCaptureArgs;
 struct LayerCaptureArgs;
+class LayerDebugInfo;
 
 } // namespace gui
 
@@ -85,7 +82,6 @@
 struct DisplayMode;
 struct DisplayState;
 struct DynamicDisplayInfo;
-struct StaticDisplayInfo;
 
 } // namespace ui
 
@@ -97,8 +93,6 @@
 public:
     DECLARE_META_INTERFACE(SurfaceComposer)
 
-    static constexpr size_t MAX_LAYERS = 4096;
-
     // flags for setTransactionState()
     enum {
         eSynchronous = 0x01,
@@ -116,28 +110,6 @@
         eOneWay = 0x20
     };
 
-    enum VsyncSource {
-        eVsyncSourceApp = 0,
-        eVsyncSourceSurfaceFlinger = 1
-    };
-
-    enum class EventRegistration {
-        modeChanged = 1 << 0,
-        frameRateOverride = 1 << 1,
-    };
-
-    using EventRegistrationFlags = ftl::Flags<EventRegistration>;
-
-    /*
-     * Create a connection with SurfaceFlinger.
-     */
-    virtual sp<ISurfaceComposerClient> createConnection() = 0;
-
-    /* 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,
@@ -145,293 +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;
-
-    /* verify that an IGraphicBufferProducer was created by SurfaceFlinger.
-     */
-    virtual bool authenticateSurfaceTexture(
-            const sp<IGraphicBufferProducer>& surface) const = 0;
-
-    /* Returns the frame timestamps supported by SurfaceFlinger.
-     */
-    virtual status_t getSupportedFrameTimestamps(
-            std::vector<FrameEvent>* outSupported) const = 0;
-
-    /**
-     * Gets immutable information about given physical display.
-     */
-    virtual status_t getStaticDisplayInfo(const sp<IBinder>& display, ui::StaticDisplayInfo*) = 0;
-
-    /**
-     * Gets dynamic information about given physical display.
-     */
-    virtual status_t getDynamicDisplayInfo(const sp<IBinder>& display, ui::DynamicDisplayInfo*) = 0;
-
-    virtual status_t getDisplayNativePrimaries(const sp<IBinder>& display,
-            ui::DisplayPrimaries& primaries) = 0;
-    virtual status_t setActiveColorMode(const sp<IBinder>& display,
-            ui::ColorMode colorMode) = 0;
-
-    /**
-     * Sets the user-preferred display mode that a device should boot in.
-     */
-    virtual status_t setBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId) = 0;
-
-    /* Clears the frame statistics for animations.
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t clearAnimationFrameStats() = 0;
-
-    /* Gets the frame statistics for animations.
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0;
-
-    /* Overrides the supported HDR modes for the given display device.
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t overrideHdrTypes(const sp<IBinder>& display,
-                                      const std::vector<ui::Hdr>& hdrTypes) = 0;
-
-    /* Pulls surfaceflinger atoms global stats and layer stats to pipe to statsd.
-     *
-     * Requires the calling uid be from system server.
-     */
-    virtual status_t onPullAtom(const int32_t atomId, std::string* outData, bool* success) = 0;
-
-    virtual status_t enableVSyncInjections(bool enable) = 0;
-
-    virtual status_t injectVSync(nsecs_t when) = 0;
-
-    /* Gets the list of active layers in Z order for debugging purposes
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) = 0;
-
-    virtual status_t getColorManagement(bool* outGetColorManagement) const = 0;
-
-    /* Gets the composition preference of the default data space and default pixel format,
-     * as well as the wide color gamut data space and wide color gamut pixel format.
-     * If the wide color gamut data space is V0_SRGB, then it implies that the platform
-     * has no wide color gamut support.
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
-                                              ui::PixelFormat* defaultPixelFormat,
-                                              ui::Dataspace* wideColorGamutDataspace,
-                                              ui::PixelFormat* wideColorGamutPixelFormat) const = 0;
-    /*
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
-                                                           ui::PixelFormat* outFormat,
-                                                           ui::Dataspace* outDataspace,
-                                                           uint8_t* outComponentMask) const = 0;
-
-    /* Turns on the color sampling engine on the display.
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
-                                                      uint8_t componentMask,
-                                                      uint64_t maxFrames) = 0;
-
-    /* Returns statistics on the color profile of the last frame displayed for a given display
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
-                                               uint64_t timestamp,
-                                               DisplayedFrameStats* outStats) const = 0;
-
-    /*
-     * Gets whether SurfaceFlinger can support protected content in GPU composition.
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
-
-    /* Registers a listener to stream median luma updates from SurfaceFlinger.
-     *
-     * The sampling area is bounded by both samplingArea and the given stopLayerHandle
-     * (i.e., only layers behind the stop layer will be captured and sampled).
-     *
-     * Multiple listeners may be provided so long as they have independent listeners.
-     * If multiple listeners are provided, the effective sampling region for each listener will
-     * be bounded by whichever stop layer has a lower Z value.
-     *
-     * Requires the same permissions as captureLayers and captureScreen.
-     */
-    virtual status_t addRegionSamplingListener(const Rect& samplingArea,
-                                               const sp<IBinder>& stopLayerHandle,
-                                               const sp<IRegionSamplingListener>& listener) = 0;
-
-    /*
-     * Removes a listener that was streaming median luma updates from SurfaceFlinger.
-     */
-    virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0;
-
-    /* Registers a listener that streams fps updates from SurfaceFlinger.
-     *
-     * The listener will stream fps updates for the layer tree rooted at the layer denoted by the
-     * task ID, i.e., the layer must have the task ID as part of its layer metadata with key
-     * METADATA_TASK_ID. If there is no such layer, then no fps is expected to be reported.
-     *
-     * Multiple listeners may be supported.
-     *
-     * Requires the READ_FRAME_BUFFER permission.
-     */
-    virtual status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) = 0;
-    /*
-     * Removes a listener that was streaming fps updates from SurfaceFlinger.
-     */
-    virtual status_t removeFpsListener(const sp<gui::IFpsListener>& listener) = 0;
-
-    /* Registers a listener to receive tunnel mode enabled updates from SurfaceFlinger.
-     *
-     * Requires ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t addTunnelModeEnabledListener(
-            const sp<gui::ITunnelModeEnabledListener>& listener) = 0;
-
-    /*
-     * Removes a listener that was receiving tunnel mode enabled updates from SurfaceFlinger.
-     *
-     * Requires ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t removeTunnelModeEnabledListener(
-            const sp<gui::ITunnelModeEnabledListener>& listener) = 0;
-
-    /* Sets the refresh rate boundaries for the display.
-     *
-     * The primary refresh rate range represents display manager's general guidance on the display
-     * modes we'll consider when switching refresh rates. Unless we get an explicit signal from an
-     * app, we should stay within this range.
-     *
-     * The app request refresh rate range allows us to consider more display modes when switching
-     * refresh rates. Although we should generally stay within the primary range, specific
-     * considerations, such as layer frame rate settings specified via the setFrameRate() api, may
-     * cause us to go outside the primary range. We never go outside the app request range. The app
-     * request range will be greater than or equal to the primary refresh rate range, never smaller.
-     *
-     * defaultMode is used to narrow the list of display modes SurfaceFlinger will consider
-     * switching between. Only modes with a mode group and resolution matching defaultMode
-     * will be considered for switching. The defaultMode corresponds to an ID of mode in the list
-     * of supported modes returned from getDynamicDisplayInfo().
-     */
-    virtual status_t setDesiredDisplayModeSpecs(
-            const sp<IBinder>& displayToken, ui::DisplayModeId defaultMode,
-            bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax,
-            float appRequestRefreshRateMin, float appRequestRefreshRateMax) = 0;
-
-    virtual status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
-                                                ui::DisplayModeId* outDefaultMode,
-                                                bool* outAllowGroupSwitching,
-                                                float* outPrimaryRefreshRateMin,
-                                                float* outPrimaryRefreshRateMax,
-                                                float* outAppRequestRefreshRateMin,
-                                                float* outAppRequestRefreshRateMax) = 0;
-
-    /*
-     * Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows
-     * material design guidelines.
-     *
-     * ambientColor
-     *      Color to the ambient shadow. The alpha is premultiplied.
-     *
-     * spotColor
-     *      Color to the spot shadow. The alpha is premultiplied. The position of the spot shadow
-     *      depends on the light position.
-     *
-     * lightPosY/lightPosZ
-     *      Position of the light used to cast the spot shadow. The X value is always the display
-     *      width / 2.
-     *
-     * lightRadius
-     *      Radius of the light casting the shadow.
-     */
-    virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
-                                             float lightPosY, float lightPosZ,
-                                             float lightRadius) = 0;
-
-    /*
-     * Gets whether a display supports DISPLAY_DECORATION layers.
-     *
-     * displayToken
-     *      The token of the display.
-     * outSupport
-     *      An output parameter for whether/how the display supports
-     *      DISPLAY_DECORATION layers.
-     *
-     * Returns NO_ERROR upon success. Otherwise,
-     *      NAME_NOT_FOUND if the display is invalid, or
-     *      BAD_VALUE      if the output parameter is invalid.
-     */
-    virtual status_t getDisplayDecorationSupport(
-            const sp<IBinder>& displayToken,
-            std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
-                    outSupport) const = 0;
-
-    /*
-     * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info.
-     */
-    virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
-                                  int8_t compatibility, int8_t changeFrameRateStrategy) = 0;
-
-    /*
-     * Set the override frame rate for a specified uid by GameManagerService.
-     * Passing the frame rate and uid to SurfaceFlinger to update the override mapping
-     * in the scheduler.
-     */
-    virtual status_t setOverrideFrameRate(uid_t uid, float frameRate) = 0;
-
-    /*
-     * Sets the frame timeline vsync info received from choreographer that corresponds to next
-     * buffer submitted on that surface.
-     */
-    virtual status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface,
-                                          const FrameTimelineInfo& frameTimelineInfo) = 0;
-
-    /*
-     * Adds a TransactionTraceListener to listen for transaction tracing state updates.
-     */
-    virtual status_t addTransactionTraceListener(
-            const sp<gui::ITransactionTraceListener>& listener) = 0;
-
-    /**
-     * Gets priority of the RenderEngine in SurfaceFlinger.
-     */
-    virtual int getGPUContextPriority() = 0;
-
-    /**
-     * Gets the number of buffers SurfaceFlinger would need acquire. This number
-     * would be propagated to the client via MIN_UNDEQUEUED_BUFFERS so that the
-     * client could allocate enough buffers to match SF expectations of the
-     * pipeline depth. SurfaceFlinger will make sure that it will give the app at
-     * least the time configured as the 'appDuration' before trying to latch
-     * the buffer.
-     *
-     * The total buffers needed for a given configuration is basically the
-     * numbers of vsyncs a single buffer is used across the stack. For the default
-     * configuration a buffer is held ~1 vsync by the app, ~1 vsync by SurfaceFlinger
-     * and 1 vsync by the display. The extra buffers are calculated as the
-     * number of additional buffers on top of the 2 buffers already present
-     * in MIN_UNDEQUEUED_BUFFERS.
-     */
-    virtual status_t getMaxAcquiredBufferCount(int* buffers) const = 0;
-
-    virtual status_t addWindowInfosListener(
-            const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0;
-    virtual status_t removeWindowInfosListener(
-            const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -442,77 +127,77 @@
         // Note: BOOT_FINISHED must remain this value, it is called from
         // Java by ActivityManagerService.
         BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
-        CREATE_CONNECTION,
-        GET_STATIC_DISPLAY_INFO,
-        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,
-        GET_SUPPORTED_FRAME_TIMESTAMPS,
-        GET_DISPLAY_MODES,       // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
-        GET_ACTIVE_DISPLAY_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        AUTHENTICATE_SURFACE,           // Deprecated. Autogenerated by .aidl now.
+        GET_SUPPORTED_FRAME_TIMESTAMPS, // Deprecated. Autogenerated by .aidl now.
+        GET_DISPLAY_MODES,              // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        GET_ACTIVE_DISPLAY_MODE,        // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
         GET_DISPLAY_STATE,
-        CAPTURE_DISPLAY, // Deprecated. Autogenerated by .aidl now.
-        CAPTURE_LAYERS,  // Deprecated. Autogenerated by .aidl now.
-        CLEAR_ANIMATION_FRAME_STATS,
-        GET_ANIMATION_FRAME_STATS,
-        SET_POWER_MODE, // Deprecated. Autogenerated by .aidl now.
+        CAPTURE_DISPLAY,             // Deprecated. Autogenerated by .aidl now.
+        CAPTURE_LAYERS,              // Deprecated. Autogenerated by .aidl now.
+        CLEAR_ANIMATION_FRAME_STATS, // Deprecated. Autogenerated by .aidl now.
+        GET_ANIMATION_FRAME_STATS,   // Deprecated. Autogenerated by .aidl now.
+        SET_POWER_MODE,              // Deprecated. Autogenerated by .aidl now.
         GET_DISPLAY_STATS,
-        GET_HDR_CAPABILITIES,    // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
-        GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
-        GET_ACTIVE_COLOR_MODE,   // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
-        SET_ACTIVE_COLOR_MODE,
-        ENABLE_VSYNC_INJECTIONS,
-        INJECT_VSYNC,
-        GET_LAYER_DEBUG_INFO,
-        GET_COMPOSITION_PREFERENCE,
-        GET_COLOR_MANAGEMENT,
-        GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
-        SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
+        GET_HDR_CAPABILITIES,       // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        GET_DISPLAY_COLOR_MODES,    // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        GET_ACTIVE_COLOR_MODE,      // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        SET_ACTIVE_COLOR_MODE,      // Deprecated. Autogenerated by .aidl now.
+        ENABLE_VSYNC_INJECTIONS,    // Deprecated. Autogenerated by .aidl now.
+        INJECT_VSYNC,               // Deprecated. Autogenerated by .aidl now.
+        GET_LAYER_DEBUG_INFO,       // Deprecated. Autogenerated by .aidl now.
+        GET_COMPOSITION_PREFERENCE, // Deprecated. Autogenerated by .aidl now.
+        GET_COLOR_MANAGEMENT,       // Deprecated. Autogenerated by .aidl now.
+        GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, // Deprecated. Autogenerated by .aidl now.
+        SET_DISPLAY_CONTENT_SAMPLING_ENABLED,      // Deprecated. Autogenerated by .aidl now.
         GET_DISPLAYED_CONTENT_SAMPLE,
-        GET_PROTECTED_CONTENT_SUPPORT,
-        IS_WIDE_COLOR_DISPLAY, // Deprecated. Autogenerated by .aidl now.
-        GET_DISPLAY_NATIVE_PRIMARIES,
-        GET_PHYSICAL_DISPLAY_IDS, // Deprecated. Autogenerated by .aidl now.
-        ADD_REGION_SAMPLING_LISTENER,
-        REMOVE_REGION_SAMPLING_LISTENER,
-        SET_DESIRED_DISPLAY_MODE_SPECS,
-        GET_DESIRED_DISPLAY_MODE_SPECS,
-        GET_DISPLAY_BRIGHTNESS_SUPPORT, // Deprecated. Autogenerated by .aidl now.
-        SET_DISPLAY_BRIGHTNESS,         // Deprecated. Autogenerated by .aidl now.
-        CAPTURE_DISPLAY_BY_ID,          // Deprecated. Autogenerated by .aidl now.
-        NOTIFY_POWER_BOOST,             // Deprecated. Autogenerated by .aidl now.
+        GET_PROTECTED_CONTENT_SUPPORT,   // Deprecated. Autogenerated by .aidl now.
+        IS_WIDE_COLOR_DISPLAY,           // Deprecated. Autogenerated by .aidl now.
+        GET_DISPLAY_NATIVE_PRIMARIES,    // Deprecated. Autogenerated by .aidl now.
+        GET_PHYSICAL_DISPLAY_IDS,        // Deprecated. Autogenerated by .aidl now.
+        ADD_REGION_SAMPLING_LISTENER,    // Deprecated. Autogenerated by .aidl now.
+        REMOVE_REGION_SAMPLING_LISTENER, // Deprecated. Autogenerated by .aidl now.
+        SET_DESIRED_DISPLAY_MODE_SPECS,  // Deprecated. Autogenerated by .aidl now.
+        GET_DESIRED_DISPLAY_MODE_SPECS,  // Deprecated. Autogenerated by .aidl now.
+        GET_DISPLAY_BRIGHTNESS_SUPPORT,  // Deprecated. Autogenerated by .aidl now.
+        SET_DISPLAY_BRIGHTNESS,          // Deprecated. Autogenerated by .aidl now.
+        CAPTURE_DISPLAY_BY_ID,           // Deprecated. Autogenerated by .aidl now.
+        NOTIFY_POWER_BOOST,              // Deprecated. Autogenerated by .aidl now.
         SET_GLOBAL_SHADOW_SETTINGS,
         GET_AUTO_LOW_LATENCY_MODE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
         SET_AUTO_LOW_LATENCY_MODE,         // Deprecated. Autogenerated by .aidl now.
         GET_GAME_CONTENT_TYPE_SUPPORT,     // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
         SET_GAME_CONTENT_TYPE,             // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
-        SET_FRAME_RATE,
+        SET_FRAME_RATE,                    // Deprecated. Autogenerated by .aidl now.
         // Deprecated. Use DisplayManager.setShouldAlwaysRespectAppRequestedMode(true);
         ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
-        SET_FRAME_TIMELINE_INFO,
-        ADD_TRANSACTION_TRACE_LISTENER,
+        SET_FRAME_TIMELINE_INFO,        // Deprecated. Autogenerated by .aidl now.
+        ADD_TRANSACTION_TRACE_LISTENER, // Deprecated. Autogenerated by .aidl now.
         GET_GPU_CONTEXT_PRIORITY,
         GET_MAX_ACQUIRED_BUFFER_COUNT,
-        GET_DYNAMIC_DISPLAY_INFO,
-        ADD_FPS_LISTENER,
-        REMOVE_FPS_LISTENER,
-        OVERRIDE_HDR_TYPES,
-        ADD_HDR_LAYER_INFO_LISTENER,    // Deprecated. Autogenerated by .aidl now.
-        REMOVE_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now.
-        ON_PULL_ATOM,
-        ADD_TUNNEL_MODE_ENABLED_LISTENER,
-        REMOVE_TUNNEL_MODE_ENABLED_LISTENER,
-        ADD_WINDOW_INFOS_LISTENER,
-        REMOVE_WINDOW_INFOS_LISTENER,
-        GET_PRIMARY_PHYSICAL_DISPLAY_ID, // Deprecated. Autogenerated by .aidl now.
+        GET_DYNAMIC_DISPLAY_INFO,            // Deprecated. Autogenerated by .aidl now.
+        ADD_FPS_LISTENER,                    // Deprecated. Autogenerated by .aidl now.
+        REMOVE_FPS_LISTENER,                 // Deprecated. Autogenerated by .aidl now.
+        OVERRIDE_HDR_TYPES,                  // Deprecated. Autogenerated by .aidl now.
+        ADD_HDR_LAYER_INFO_LISTENER,         // Deprecated. Autogenerated by .aidl now.
+        REMOVE_HDR_LAYER_INFO_LISTENER,      // Deprecated. Autogenerated by .aidl now.
+        ON_PULL_ATOM,                        // Deprecated. Autogenerated by .aidl now.
+        ADD_TUNNEL_MODE_ENABLED_LISTENER,    // Deprecated. Autogenerated by .aidl now.
+        REMOVE_TUNNEL_MODE_ENABLED_LISTENER, // Deprecated. Autogenerated by .aidl now.
+        ADD_WINDOW_INFOS_LISTENER,           // Deprecated. Autogenerated by .aidl now.
+        REMOVE_WINDOW_INFOS_LISTENER,        // Deprecated. Autogenerated by .aidl now.
+        GET_PRIMARY_PHYSICAL_DISPLAY_ID,     // Deprecated. Autogenerated by .aidl now.
         GET_DISPLAY_DECORATION_SUPPORT,
         GET_BOOT_DISPLAY_MODE_SUPPORT, // Deprecated. Autogenerated by .aidl now.
-        SET_BOOT_DISPLAY_MODE,
-        CLEAR_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now.
-        SET_OVERRIDE_FRAME_RATE,
+        SET_BOOT_DISPLAY_MODE,         // Deprecated. Autogenerated by .aidl now.
+        CLEAR_BOOT_DISPLAY_MODE,       // Deprecated. Autogenerated by .aidl now.
+        SET_OVERRIDE_FRAME_RATE,       // Deprecated. Autogenerated by .aidl now.
         // Always append new enum to the end.
     };
 
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
deleted file mode 100644
index 9e9e191..0000000
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ /dev/null
@@ -1,97 +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 <binder/IInterface.h>
-#include <binder/SafeInterface.h>
-#include <gui/LayerMetadata.h>
-#include <ui/PixelFormat.h>
-
-#include <unordered_map>
-
-namespace android {
-
-class FrameStats;
-class IGraphicBufferProducer;
-
-class ISurfaceComposerClient : public IInterface {
-public:
-    DECLARE_META_INTERFACE(SurfaceComposerClient)
-
-    // flags for createSurface()
-    enum { // (keep in sync with SurfaceControl.java)
-        eHidden = 0x00000004,
-        eDestroyBackbuffer = 0x00000020,
-        eSkipScreenshot = 0x00000040,
-        eSecure = 0x00000080,
-        eNonPremultiplied = 0x00000100,
-        eOpaque = 0x00000400,
-        eProtectedByApp = 0x00000800,
-        eProtectedByDRM = 0x00001000,
-        eCursorWindow = 0x00002000,
-        eNoColorFill = 0x00004000,
-
-        eFXSurfaceBufferQueue = 0x00000000,
-        eFXSurfaceEffect = 0x00020000,
-        eFXSurfaceBufferState = 0x00040000,
-        eFXSurfaceContainer = 0x00080000,
-        eFXSurfaceMask = 0x000F0000,
-    };
-
-    // TODO(b/172002646):  Clean up the Surface Creation Arguments
-    /*
-     * Requires ACCESS_SURFACE_FLINGER permission
-     */
-    virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
-                                   uint32_t flags, const sp<IBinder>& parent,
-                                   LayerMetadata metadata, sp<IBinder>* handle,
-                                   sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId,
-                                   uint32_t* outTransformHint) = 0;
-
-    /*
-     * Requires ACCESS_SURFACE_FLINGER permission
-     */
-    virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
-                                             PixelFormat format, uint32_t flags,
-                                             const sp<IGraphicBufferProducer>& parent,
-                                             LayerMetadata metadata, sp<IBinder>* handle,
-                                             sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId,
-                                             uint32_t* outTransformHint) = 0;
-
-    /*
-     * Requires ACCESS_SURFACE_FLINGER permission
-     */
-    virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const = 0;
-
-    /*
-     * Requires ACCESS_SURFACE_FLINGER permission
-     */
-    virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0;
-
-    virtual status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,
-                                   int32_t* outLayerId) = 0;
-};
-
-class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> {
-public:
-    BnSurfaceComposerClient()
-          : SafeBnInterface<ISurfaceComposerClient>("BnSurfaceComposerClient") {}
-
-    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
-};
-
-} // namespace android
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
index af834d7..dbb80e5 100644
--- a/libs/gui/include/gui/LayerDebugInfo.h
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -25,7 +25,7 @@
 #include <string>
 #include <math/vec4.h>
 
-namespace android {
+namespace android::gui {
 
 /* Class for transporting debug info from SurfaceFlinger to authorized
  * recipients.  The class is intended to be a data container. There are
@@ -52,7 +52,7 @@
     uint32_t mZ = 0 ;
     int32_t mWidth = -1;
     int32_t mHeight = -1;
-    Rect mCrop = Rect::INVALID_RECT;
+    android::Rect mCrop = android::Rect::INVALID_RECT;
     half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf);
     uint32_t mFlags = 0;
     PixelFormat mPixelFormat = PIXEL_FORMAT_NONE;
@@ -71,4 +71,4 @@
 
 std::string to_string(const LayerDebugInfo& info);
 
-} // namespace android
+} // namespace android::gui
diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h
index 27f4d37..5af5989 100644
--- a/libs/gui/include/gui/LayerMetadata.h
+++ b/libs/gui/include/gui/LayerMetadata.h
@@ -20,7 +20,7 @@
 
 #include <unordered_map>
 
-namespace android {
+namespace android::gui {
 
 enum {
     METADATA_OWNER_UID = 1,
@@ -69,4 +69,13 @@
     ftl_last = Battery
 };
 
-} // namespace android
+} // namespace android::gui
+
+using android::gui::METADATA_ACCESSIBILITY_ID;
+using android::gui::METADATA_DEQUEUE_TIME;
+using android::gui::METADATA_GAME_MODE;
+using android::gui::METADATA_MOUSE_CURSOR;
+using android::gui::METADATA_OWNER_PID;
+using android::gui::METADATA_OWNER_UID;
+using android::gui::METADATA_TASK_ID;
+using android::gui::METADATA_WINDOW_TYPE;
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 0a9b75a..f3701e8 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>
@@ -51,7 +52,9 @@
 namespace android {
 
 class Parcel;
-class ISurfaceComposerClient;
+
+using gui::ISurfaceComposerClient;
+using gui::LayerMetadata;
 
 struct client_cache_t {
     wp<IBinder> token = nullptr;
@@ -153,7 +156,7 @@
         eLayerStackChanged = 0x00000080,
         eDimmingEnabledChanged = 0x00000400,
         eShadowRadiusChanged = 0x00000800,
-        /* unused 0x00001000, */
+        eRenderBorderChanged = 0x00001000,
         eBufferCropChanged = 0x00002000,
         eRelativeLayerChanged = 0x00004000,
         eReparent = 0x00008000,
@@ -163,7 +166,7 @@
         eTransformToDisplayInverseChanged = 0x00080000,
         eCropChanged = 0x00100000,
         eBufferChanged = 0x00200000,
-        /* unused 0x00400000, */
+        eDefaultFrameRateCompatibilityChanged = 0x00400000,
         eDataspaceChanged = 0x00800000,
         eHdrMetadataChanged = 0x01000000,
         eSurfaceDamageRegionChanged = 0x02000000,
@@ -273,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
@@ -291,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;
 
@@ -352,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/Surface.h b/libs/gui/include/gui/Surface.h
index ab9ebaa..267c28f 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -17,8 +17,8 @@
 #ifndef ANDROID_GUI_SURFACE_H
 #define ANDROID_GUI_SURFACE_H
 
+#include <android/gui/FrameTimelineInfo.h>
 #include <gui/BufferQueueDefs.h>
-#include <gui/FrameTimelineInfo.h>
 #include <gui/HdrMetadata.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IProducerListener.h>
@@ -41,6 +41,8 @@
 
 class ISurfaceComposer;
 
+using gui::FrameTimelineInfo;
+
 /* This is the same as ProducerListener except that onBuffersDiscarded is
  * called with a vector of graphic buffers instead of buffer slots.
  */
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index efbdb36..24399ff 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -38,6 +38,9 @@
 #include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
 #include <ui/Rotation.h>
+#include <ui/StaticDisplayInfo.h>
+
+#include <android/gui/ISurfaceComposerClient.h>
 
 #include <gui/CpuConsumer.h>
 #include <gui/ISurfaceComposer.h>
@@ -52,14 +55,15 @@
 namespace android {
 
 class HdrCapabilities;
-class ISurfaceComposerClient;
 class IGraphicBufferProducer;
 class ITunnelModeEnabledListener;
 class Region;
 
 using gui::DisplayCaptureArgs;
 using gui::IRegionSamplingListener;
+using gui::ISurfaceComposerClient;
 using gui::LayerCaptureArgs;
+using gui::LayerMetadata;
 
 struct SurfaceControlStats {
     SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime,
@@ -215,7 +219,7 @@
     /**
      * Gets the context priority of surface flinger's render engine.
      */
-    static int getGPUContextPriority();
+    static int getGpuContextPriority();
 
     /**
      * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is
@@ -311,7 +315,7 @@
                                      uint32_t w,          // width in pixel
                                      uint32_t h,          // height in pixel
                                      PixelFormat format,  // pixel-format desired
-                                     uint32_t flags = 0,  // usage flags
+                                     int32_t flags = 0,   // usage flags
                                      const sp<IBinder>& parentHandle = nullptr, // parentHandle
                                      LayerMetadata metadata = LayerMetadata(),  // metadata
                                      uint32_t* outTransformHint = nullptr);
@@ -321,21 +325,11 @@
                                   uint32_t h,          // height in pixel
                                   PixelFormat format,  // pixel-format desired
                                   sp<SurfaceControl>* outSurface,
-                                  uint32_t flags = 0,                        // usage flags
+                                  int32_t flags = 0,                         // usage flags
                                   const sp<IBinder>& parentHandle = nullptr, // parentHandle
                                   LayerMetadata metadata = LayerMetadata(),  // metadata
                                   uint32_t* outTransformHint = nullptr);
 
-    //! Create a surface
-    sp<SurfaceControl> createWithSurfaceParent(const String8& name,       // name of the surface
-                                               uint32_t w,                // width in pixel
-                                               uint32_t h,                // height in pixel
-                                               PixelFormat format,        // pixel-format desired
-                                               uint32_t flags = 0,        // usage flags
-                                               Surface* parent = nullptr, // parent
-                                               LayerMetadata metadata = LayerMetadata(), // metadata
-                                               uint32_t* outTransformHint = nullptr);
-
     // Creates a mirrored hierarchy for the mirrorFromSurface. This returns a SurfaceControl
     // which is a parent of the root of the mirrored hierarchy.
     //
@@ -393,9 +387,27 @@
         std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls;
     };
 
+    // TODO(b/222421815) this class should be removed when
+    // SurfaceComposerClient::Transaction::syncInputWindows is removed and replaced with a method
+    // for adding callbacks to InputWindowCommands.
+    class Event {
+    private:
+        static constexpr std::chrono::seconds sTimeout{5};
+
+        bool mComplete = false;
+        std::condition_variable mConditionVariable;
+        std::mutex mMutex;
+
+    public:
+        void set();
+        bool wait();
+    };
+
     class Transaction : public Parcelable {
     private:
         void releaseBufferIfOverwriting(const layer_state_t& state);
+        static void mergeFrameTimelineInfo(FrameTimelineInfo& t, const FrameTimelineInfo& other);
+        static void clearFrameTimelineInfo(FrameTimelineInfo& t);
 
     protected:
         std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates;
@@ -440,6 +452,8 @@
         InputWindowCommands mInputWindowCommands;
         int mStatus = NO_ERROR;
 
+        std::shared_ptr<Event> mWindowInfosReportedEvent = nullptr;
+
         layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
         DisplayState& getDisplayState(const sp<IBinder>& token);
 
@@ -461,6 +475,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.
@@ -583,6 +601,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
@@ -629,6 +650,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);
 
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index b72cf83..e4a1350 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -24,11 +24,12 @@
 #include <utils/RefBase.h>
 #include <utils/threads.h>
 
+#include <android/gui/ISurfaceComposerClient.h>
+
 #include <ui/FrameStats.h>
 #include <ui/PixelFormat.h>
 #include <ui/Region.h>
 
-#include <gui/ISurfaceComposerClient.h>
 #include <math/vec3.h>
 
 namespace android {
@@ -93,8 +94,7 @@
     explicit SurfaceControl(const sp<SurfaceControl>& other);
 
     SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
-                   const sp<IGraphicBufferProducer>& gbp, int32_t layerId,
-                   uint32_t width = 0, uint32_t height = 0, PixelFormat format = 0,
+                   int32_t layerId, uint32_t width = 0, uint32_t height = 0, PixelFormat format = 0,
                    uint32_t transformHint = 0, uint32_t flags = 0);
 
     sp<SurfaceControl> getParentingLayer();
@@ -115,8 +115,7 @@
     status_t validate() const;
 
     sp<SurfaceComposerClient>   mClient;
-    sp<IBinder>                 mHandle;
-    sp<IGraphicBufferProducer>  mGraphicBufferProducer;
+    sp<IBinder> mHandle;
     mutable Mutex               mLock;
     mutable sp<Surface>         mSurfaceData;
     mutable sp<BLASTBufferQueue> mBbq;
diff --git a/libs/gui/include/gui/VsyncEventData.h b/libs/gui/include/gui/VsyncEventData.h
index 8e99539..dfdae21 100644
--- a/libs/gui/include/gui/VsyncEventData.h
+++ b/libs/gui/include/gui/VsyncEventData.h
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include <gui/FrameTimelineInfo.h>
+#include <android/gui/FrameTimelineInfo.h>
 
 #include <array>
 
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 169f7f0..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
     };
 
@@ -236,8 +238,6 @@
 
     void setInputConfig(ftl::Flags<InputConfig> config, bool value);
 
-    bool isClone = false;
-
     void addTouchableRegion(const Rect& region);
 
     bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h
index 3b4aed4..2754442 100644
--- a/libs/gui/include/gui/WindowInfosListenerReporter.h
+++ b/libs/gui/include/gui/WindowInfosListenerReporter.h
@@ -17,15 +17,14 @@
 #pragma once
 
 #include <android/gui/BnWindowInfosListener.h>
+#include <android/gui/ISurfaceComposer.h>
 #include <android/gui/IWindowInfosReportedListener.h>
 #include <binder/IBinder.h>
-#include <gui/ISurfaceComposer.h>
 #include <gui/SpHash.h>
 #include <gui/WindowInfosListener.h>
 #include <unordered_set>
 
 namespace android {
-class ISurfaceComposer;
 
 class WindowInfosListenerReporter : public gui::BnWindowInfosListener {
 public:
@@ -33,17 +32,17 @@
     binder::Status onWindowInfosChanged(const std::vector<gui::WindowInfo>&,
                                         const std::vector<gui::DisplayInfo>&,
                                         const sp<gui::IWindowInfosReportedListener>&) override;
-
     status_t addWindowInfosListener(
-            const sp<gui::WindowInfosListener>& windowInfosListener, const sp<ISurfaceComposer>&,
+            const sp<gui::WindowInfosListener>& windowInfosListener,
+            const sp<gui::ISurfaceComposer>&,
             std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo);
     status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener,
-                                       const sp<ISurfaceComposer>& surfaceComposer);
-    void reconnect(const sp<ISurfaceComposer>&);
+                                       const sp<gui::ISurfaceComposer>& surfaceComposer);
+    void reconnect(const sp<gui::ISurfaceComposer>&);
 
 private:
     std::mutex mListenersMutex;
-    std::unordered_set<sp<gui::WindowInfosListener>, SpHash<gui::WindowInfosListener>>
+    std::unordered_set<sp<gui::WindowInfosListener>, gui::SpHash<gui::WindowInfosListener>>
             mWindowInfosListeners GUARDED_BY(mListenersMutex);
 
     std::vector<gui::WindowInfo> mLastWindowInfos GUARDED_BY(mListenersMutex);
diff --git a/libs/gui/include/private/gui/ComposerServiceAIDL.h b/libs/gui/include/private/gui/ComposerServiceAIDL.h
index 9a96976..2963583 100644
--- a/libs/gui/include/private/gui/ComposerServiceAIDL.h
+++ b/libs/gui/include/private/gui/ComposerServiceAIDL.h
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 
 #include <android/gui/ISurfaceComposer.h>
+#include <ui/DisplayId.h>
 
 #include <utils/Singleton.h>
 #include <utils/StrongPointer.h>
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index e58543a..fc68ad2 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",
@@ -75,7 +74,6 @@
     name: "libgui_multilib_test",
     test_suites: ["device-tests"],
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -102,7 +100,6 @@
     name: "SurfaceParcelable_test",
     test_suites: ["device-tests"],
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
@@ -131,7 +128,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 cb7e94c..3e563b2 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -19,6 +19,7 @@
 #include <gui/BLASTBufferQueue.h>
 
 #include <android/hardware/graphics/common/1.2/types.h>
+#include <gui/AidlStatusUtil.h>
 #include <gui/BufferQueueCore.h>
 #include <gui/BufferQueueProducer.h>
 #include <gui/FrameTimestamps.h>
@@ -161,6 +162,10 @@
         ASSERT_EQ(numFramesSubmitted, mBlastBufferQueueAdapter->mSubmitted.size());
     }
 
+    void mergeWithNextTransaction(Transaction* merge, uint64_t frameNumber) {
+        mBlastBufferQueueAdapter->mergeWithNextTransaction(merge, frameNumber);
+    }
+
 private:
     sp<TestBLASTBufferQueue> mBlastBufferQueueAdapter;
 };
@@ -301,8 +306,9 @@
 
         const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
         binder::Status status = sf->captureDisplay(captureArgs, captureListener);
-        if (status.transactionError() != NO_ERROR) {
-            return status.transactionError();
+        status_t err = gui::aidl_utils::statusTFromBinderStatus(status);
+        if (err != NO_ERROR) {
+            return err;
         }
         captureResults = captureListener->waitForResults();
         return captureResults.result;
@@ -1111,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/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index c9106be..b18b544 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -19,14 +19,16 @@
 
 #include <android/gui/BnRegionSamplingListener.h>
 #include <binder/ProcessState.h>
+#include <gui/AidlStatusUtil.h>
 #include <gui/DisplayEventReceiver.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
-#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 #include <utils/Looper.h>
 
 using namespace std::chrono_literals;
+using android::gui::aidl_utils::statusTFromBinderStatus;
 
 namespace android::test {
 
@@ -242,24 +244,33 @@
 };
 
 TEST_F(RegionSamplingTest, invalidLayerHandle_doesNotCrash) {
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
     sp<Listener> listener = new Listener();
-    const Rect sampleArea{100, 100, 200, 200};
+    gui::ARect sampleArea;
+    sampleArea.left = 100;
+    sampleArea.top = 100;
+    sampleArea.right = 200;
+    sampleArea.bottom = 200;
     // Passing in composer service as the layer handle should not crash, we'll
     // treat it as a layer that no longer exists and silently allow sampling to
     // occur.
-    status_t status = composer->addRegionSamplingListener(sampleArea,
-                                                          IInterface::asBinder(composer), listener);
-    ASSERT_EQ(NO_ERROR, status);
+    binder::Status status =
+            composer->addRegionSamplingListener(sampleArea, IInterface::asBinder(composer),
+                                                listener);
+    ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status));
     composer->removeRegionSamplingListener(listener);
 }
 
 TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) {
     fill_render(rgba_green);
 
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
     sp<Listener> listener = new Listener();
-    const Rect sampleArea{100, 100, 200, 200};
+    gui::ARect sampleArea;
+    sampleArea.left = 100;
+    sampleArea.top = 100;
+    sampleArea.right = 200;
+    sampleArea.bottom = 200;
     composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
 
     EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
@@ -271,9 +282,13 @@
 TEST_F(RegionSamplingTest, DISABLED_CollectsChangingLuma) {
     fill_render(rgba_green);
 
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
     sp<Listener> listener = new Listener();
-    const Rect sampleArea{100, 100, 200, 200};
+    gui::ARect sampleArea;
+    sampleArea.left = 100;
+    sampleArea.top = 100;
+    sampleArea.right = 200;
+    sampleArea.bottom = 200;
     composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
 
     EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
@@ -291,13 +306,21 @@
 
 TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) {
     fill_render(rgba_green);
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
     sp<Listener> greenListener = new Listener();
-    const Rect greenSampleArea{100, 100, 200, 200};
+    gui::ARect greenSampleArea;
+    greenSampleArea.left = 100;
+    greenSampleArea.top = 100;
+    greenSampleArea.right = 200;
+    greenSampleArea.bottom = 200;
     composer->addRegionSamplingListener(greenSampleArea, mTopLayer->getHandle(), greenListener);
 
     sp<Listener> grayListener = new Listener();
-    const Rect graySampleArea{500, 100, 600, 200};
+    gui::ARect graySampleArea;
+    graySampleArea.left = 500;
+    graySampleArea.top = 100;
+    graySampleArea.right = 600;
+    graySampleArea.bottom = 200;
     composer->addRegionSamplingListener(graySampleArea, mTopLayer->getHandle(), grayListener);
 
     EXPECT_TRUE(grayListener->wait_event(300ms))
@@ -312,29 +335,49 @@
 }
 
 TEST_F(RegionSamplingTest, DISABLED_TestIfInvalidInputParameters) {
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
     sp<Listener> listener = new Listener();
-    const Rect sampleArea{100, 100, 200, 200};
+
+    gui::ARect invalidRect;
+    invalidRect.left = Rect::INVALID_RECT.left;
+    invalidRect.top = Rect::INVALID_RECT.top;
+    invalidRect.right = Rect::INVALID_RECT.right;
+    invalidRect.bottom = Rect::INVALID_RECT.bottom;
+
+    gui::ARect sampleArea;
+    sampleArea.left = 100;
+    sampleArea.top = 100;
+    sampleArea.right = 200;
+    sampleArea.bottom = 200;
     // Invalid input sampleArea
     EXPECT_EQ(BAD_VALUE,
-              composer->addRegionSamplingListener(Rect::INVALID_RECT, mTopLayer->getHandle(),
-                                                  listener));
+              statusTFromBinderStatus(composer->addRegionSamplingListener(invalidRect,
+                                                                          mTopLayer->getHandle(),
+                                                                          listener)));
     listener->reset();
     // Invalid input binder
-    EXPECT_EQ(NO_ERROR, composer->addRegionSamplingListener(sampleArea, NULL, listener));
+    EXPECT_EQ(NO_ERROR,
+              statusTFromBinderStatus(
+                      composer->addRegionSamplingListener(sampleArea, NULL, listener)));
     // Invalid input listener
     EXPECT_EQ(BAD_VALUE,
-              composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), NULL));
-    EXPECT_EQ(BAD_VALUE, composer->removeRegionSamplingListener(NULL));
+              statusTFromBinderStatus(composer->addRegionSamplingListener(sampleArea,
+                                                                          mTopLayer->getHandle(),
+                                                                          NULL)));
+    EXPECT_EQ(BAD_VALUE, statusTFromBinderStatus(composer->removeRegionSamplingListener(NULL)));
     // remove the listener
     composer->removeRegionSamplingListener(listener);
 }
 
 TEST_F(RegionSamplingTest, DISABLED_TestCallbackAfterRemoveListener) {
     fill_render(rgba_green);
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
     sp<Listener> listener = new Listener();
-    const Rect sampleArea{100, 100, 200, 200};
+    gui::ARect sampleArea;
+    sampleArea.left = 100;
+    sampleArea.top = 100;
+    sampleArea.right = 200;
+    sampleArea.bottom = 200;
     composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
     fill_render(rgba_green);
 
@@ -349,13 +392,18 @@
 }
 
 TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromMovingLayer) {
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
     sp<Listener> listener = new Listener();
     Rect sampleArea{100, 100, 200, 200};
+    gui::ARect sampleAreaA;
+    sampleAreaA.left = sampleArea.left;
+    sampleAreaA.top = sampleArea.top;
+    sampleAreaA.right = sampleArea.right;
+    sampleAreaA.bottom = sampleArea.bottom;
 
     // Test: listener in (100, 100). See layer before move, no layer after move.
     fill_render(rgba_blue);
-    composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+    composer->addRegionSamplingListener(sampleAreaA, mTopLayer->getHandle(), listener);
     EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
     EXPECT_NEAR(listener->luma(), luma_blue, error_margin);
     listener->reset();
@@ -367,7 +415,11 @@
     // Test: listener offset to (600, 600). No layer before move, see layer after move.
     fill_render(rgba_green);
     sampleArea.offsetTo(600, 600);
-    composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+    sampleAreaA.left = sampleArea.left;
+    sampleAreaA.top = sampleArea.top;
+    sampleAreaA.right = sampleArea.right;
+    sampleAreaA.bottom = sampleArea.bottom;
+    composer->addRegionSamplingListener(sampleAreaA, mTopLayer->getHandle(), listener);
     EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
     EXPECT_NEAR(listener->luma(), luma_gray, error_margin);
     listener->reset();
diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp
index a083a22..f98437b 100644
--- a/libs/gui/tests/SamplingDemo.cpp
+++ b/libs/gui/tests/SamplingDemo.cpp
@@ -26,7 +26,7 @@
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 #include <gui/SurfaceControl.h>
-#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 #include <utils/Trace.h>
 
 using namespace std::chrono_literals;
@@ -121,10 +121,22 @@
     const Rect backButtonArea{200, 1606, 248, 1654};
     sp<android::Button> backButton = new android::Button("BackButton", backButtonArea);
 
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
-    composer->addRegionSamplingListener(homeButtonArea, homeButton->getStopLayerHandle(),
+    gui::ARect homeButtonAreaA;
+    homeButtonAreaA.left = 490;
+    homeButtonAreaA.top = 1606;
+    homeButtonAreaA.right = 590;
+    homeButtonAreaA.bottom = 1654;
+
+    gui::ARect backButtonAreaA;
+    backButtonAreaA.left = 200;
+    backButtonAreaA.top = 1606;
+    backButtonAreaA.right = 248;
+    backButtonAreaA.bottom = 1654;
+
+    sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
+    composer->addRegionSamplingListener(homeButtonAreaA, homeButton->getStopLayerHandle(),
                                         homeButton);
-    composer->addRegionSamplingListener(backButtonArea, backButton->getStopLayerHandle(),
+    composer->addRegionSamplingListener(backButtonAreaA, backButton->getStopLayerHandle(),
                                         backButton);
 
     ProcessState::self()->startThreadPool();
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 065cd7a..7eff3b3 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -24,6 +24,7 @@
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <binder/ProcessState.h>
 #include <configstore/Utils.h>
+#include <gui/AidlStatusUtil.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/IProducerListener.h>
 #include <gui/ISurfaceComposer.h>
@@ -212,8 +213,9 @@
 
         const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
         binder::Status status = sf->captureDisplay(captureArgs, captureListener);
-        if (status.transactionError() != NO_ERROR) {
-            return status.transactionError();
+        status_t err = gui::aidl_utils::statusTFromBinderStatus(status);
+        if (err != NO_ERROR) {
+            return err;
         }
         captureResults = captureListener->waitForResults();
         return captureResults.result;
@@ -690,11 +692,6 @@
         mSupportsPresent = supportsPresent;
     }
 
-    sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
-    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*/,
@@ -708,179 +705,6 @@
         return NO_ERROR;
     }
 
-    void bootFinished() override {}
-    bool authenticateSurfaceTexture(
-            const sp<IGraphicBufferProducer>& /*surface*/) const override {
-        return false;
-    }
-
-    status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported)
-            const override {
-        *outSupported = {
-                FrameEvent::REQUESTED_PRESENT,
-                FrameEvent::ACQUIRE,
-                FrameEvent::LATCH,
-                FrameEvent::FIRST_REFRESH_START,
-                FrameEvent::LAST_REFRESH_START,
-                FrameEvent::GPU_COMPOSITION_DONE,
-                FrameEvent::DEQUEUE_READY,
-                FrameEvent::RELEASE
-        };
-        if (mSupportsPresent) {
-            outSupported->push_back(
-                        FrameEvent::DISPLAY_PRESENT);
-        }
-        return NO_ERROR;
-    }
-
-    status_t getStaticDisplayInfo(const sp<IBinder>& /*display*/, ui::StaticDisplayInfo*) override {
-        return NO_ERROR;
-    }
-    status_t getDynamicDisplayInfo(const sp<IBinder>& /*display*/,
-                                   ui::DynamicDisplayInfo*) override {
-        return NO_ERROR;
-    }
-    status_t getDisplayNativePrimaries(const sp<IBinder>& /*display*/,
-            ui::DisplayPrimaries& /*primaries*/) override {
-        return NO_ERROR;
-    }
-    status_t setActiveColorMode(const sp<IBinder>& /*display*/, ColorMode /*colorMode*/) override {
-        return NO_ERROR;
-    }
-    status_t setBootDisplayMode(const sp<IBinder>& /*display*/, ui::DisplayModeId /*id*/) override {
-        return NO_ERROR;
-    }
-
-    status_t clearAnimationFrameStats() override { return NO_ERROR; }
-    status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
-        return NO_ERROR;
-    }
-    status_t overrideHdrTypes(const sp<IBinder>& /*display*/,
-                              const std::vector<ui::Hdr>& /*hdrTypes*/) override {
-        return NO_ERROR;
-    }
-    status_t onPullAtom(const int32_t /*atomId*/, std::string* /*outData*/,
-                        bool* /*success*/) override {
-        return NO_ERROR;
-    }
-    status_t enableVSyncInjections(bool /*enable*/) override {
-        return NO_ERROR;
-    }
-    status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; }
-    status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) override {
-        return NO_ERROR;
-    }
-    status_t getCompositionPreference(
-            ui::Dataspace* /*outDefaultDataspace*/, ui::PixelFormat* /*outDefaultPixelFormat*/,
-            ui::Dataspace* /*outWideColorGamutDataspace*/,
-            ui::PixelFormat* /*outWideColorGamutPixelFormat*/) const override {
-        return NO_ERROR;
-    }
-    status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& /*display*/,
-                                                   ui::PixelFormat* /*outFormat*/,
-                                                   ui::Dataspace* /*outDataspace*/,
-                                                   uint8_t* /*outComponentMask*/) const override {
-        return NO_ERROR;
-    }
-    status_t setDisplayContentSamplingEnabled(const sp<IBinder>& /*display*/, bool /*enable*/,
-                                              uint8_t /*componentMask*/,
-                                              uint64_t /*maxFrames*/) override {
-        return NO_ERROR;
-    }
-    status_t getDisplayedContentSample(const sp<IBinder>& /*display*/, uint64_t /*maxFrames*/,
-                                       uint64_t /*timestamp*/,
-                                       DisplayedFrameStats* /*outStats*/) const override {
-        return NO_ERROR;
-    }
-
-    status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
-    status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
-
-    status_t addRegionSamplingListener(const Rect& /*samplingArea*/,
-                                       const sp<IBinder>& /*stopLayerHandle*/,
-                                       const sp<IRegionSamplingListener>& /*listener*/) override {
-        return NO_ERROR;
-    }
-    status_t removeRegionSamplingListener(
-            const sp<IRegionSamplingListener>& /*listener*/) override {
-        return NO_ERROR;
-    }
-    status_t addFpsListener(int32_t /*taskId*/, const sp<gui::IFpsListener>& /*listener*/) {
-        return NO_ERROR;
-    }
-    status_t removeFpsListener(const sp<gui::IFpsListener>& /*listener*/) { return NO_ERROR; }
-
-    status_t addTunnelModeEnabledListener(const sp<gui::ITunnelModeEnabledListener>& /*listener*/) {
-        return NO_ERROR;
-    }
-
-    status_t removeTunnelModeEnabledListener(
-            const sp<gui::ITunnelModeEnabledListener>& /*listener*/) {
-        return NO_ERROR;
-    }
-
-    status_t setDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/,
-                                        ui::DisplayModeId /*defaultMode*/,
-                                        bool /*allowGroupSwitching*/,
-                                        float /*primaryRefreshRateMin*/,
-                                        float /*primaryRefreshRateMax*/,
-                                        float /*appRequestRefreshRateMin*/,
-                                        float /*appRequestRefreshRateMax*/) {
-        return NO_ERROR;
-    }
-    status_t getDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/,
-                                        ui::DisplayModeId* /*outDefaultMode*/,
-                                        bool* /*outAllowGroupSwitching*/,
-                                        float* /*outPrimaryRefreshRateMin*/,
-                                        float* /*outPrimaryRefreshRateMax*/,
-                                        float* /*outAppRequestRefreshRateMin*/,
-                                        float* /*outAppRequestRefreshRateMax*/) override {
-        return NO_ERROR;
-    };
-
-    status_t setGlobalShadowSettings(const half4& /*ambientColor*/, const half4& /*spotColor*/,
-                                     float /*lightPosY*/, float /*lightPosZ*/,
-                                     float /*lightRadius*/) override {
-        return NO_ERROR;
-    }
-
-    status_t getDisplayDecorationSupport(
-            const sp<IBinder>& /*displayToken*/,
-            std::optional<DisplayDecorationSupport>* /*outSupport*/) const override {
-        return NO_ERROR;
-    }
-
-    status_t setFrameRate(const sp<IGraphicBufferProducer>& /*surface*/, float /*frameRate*/,
-                          int8_t /*compatibility*/, int8_t /*changeFrameRateStrategy*/) override {
-        return NO_ERROR;
-    }
-
-    status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& /*surface*/,
-                                  const FrameTimelineInfo& /*frameTimelineInfo*/) override {
-        return NO_ERROR;
-    }
-
-    status_t addTransactionTraceListener(
-            const sp<gui::ITransactionTraceListener>& /*listener*/) override {
-        return NO_ERROR;
-    }
-
-    int getGPUContextPriority() override { return 0; };
-
-    status_t getMaxAcquiredBufferCount(int* /*buffers*/) const override { return NO_ERROR; }
-
-    status_t addWindowInfosListener(
-            const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override {
-        return NO_ERROR;
-    }
-
-    status_t removeWindowInfosListener(
-            const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override {
-        return NO_ERROR;
-    }
-
-    status_t setOverrideFrameRate(uid_t /*uid*/, float /*frameRate*/) override { return NO_ERROR; }
-
 protected:
     IBinder* onAsBinder() override { return nullptr; }
 
@@ -894,6 +718,20 @@
 
     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();
+    }
+
     binder::Status createDisplay(const std::string& /*displayName*/, bool /*secure*/,
                                  sp<IBinder>* /*outDisplay*/) override {
         return binder::Status::ok();
@@ -920,6 +758,21 @@
         return binder::Status::ok();
     }
 
+    binder::Status getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) override {
+        *outSupported = {FrameEvent::REQUESTED_PRESENT,
+                         FrameEvent::ACQUIRE,
+                         FrameEvent::LATCH,
+                         FrameEvent::FIRST_REFRESH_START,
+                         FrameEvent::LAST_REFRESH_START,
+                         FrameEvent::GPU_COMPOSITION_DONE,
+                         FrameEvent::DEQUEUE_READY,
+                         FrameEvent::RELEASE};
+        if (mSupportsPresent) {
+            outSupported->push_back(FrameEvent::DISPLAY_PRESENT);
+        }
+        return binder::Status::ok();
+    }
+
     binder::Status getDisplayStats(const sp<IBinder>& /*display*/,
                                    gui::DisplayStatInfo* /*outStatInfo*/) override {
         return binder::Status::ok();
@@ -930,6 +783,30 @@
         return binder::Status::ok();
     }
 
+    binder::Status getStaticDisplayInfo(const sp<IBinder>& /*display*/,
+                                        gui::StaticDisplayInfo* /*outInfo*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getDynamicDisplayInfo(const sp<IBinder>& /*display*/,
+                                         gui::DynamicDisplayInfo* /*outInfo*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getDisplayNativePrimaries(const sp<IBinder>& /*display*/,
+                                             gui::DisplayPrimaries* /*outPrimaries*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status setActiveColorMode(const sp<IBinder>& /*display*/, int /*colorMode*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status setBootDisplayMode(const sp<IBinder>& /*display*/,
+                                      int /*displayModeId*/) override {
+        return binder::Status::ok();
+    }
+
     binder::Status clearBootDisplayMode(const sp<IBinder>& /*display*/) override {
         return binder::Status::ok();
     }
@@ -960,11 +837,107 @@
         return binder::Status::ok();
     }
 
+    binder::Status clearAnimationFrameStats() override { return binder::Status::ok(); }
+
+    binder::Status getAnimationFrameStats(gui::FrameStats* /*outStats*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status overrideHdrTypes(const sp<IBinder>& /*display*/,
+                                    const std::vector<int32_t>& /*hdrTypes*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status onPullAtom(int32_t /*atomId*/, gui::PullAtomData* /*outPullData*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status enableVSyncInjections(bool /*enable*/) override { return binder::Status::ok(); }
+
+    binder::Status injectVSync(int64_t /*when*/) override { return binder::Status::ok(); }
+
+    binder::Status getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* /*outLayers*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getColorManagement(bool* /*outGetColorManagement*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getCompositionPreference(gui::CompositionPreference* /*outPref*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getDisplayedContentSamplingAttributes(
+            const sp<IBinder>& /*display*/, gui::ContentSamplingAttributes* /*outAttrs*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status setDisplayContentSamplingEnabled(const sp<IBinder>& /*display*/, bool /*enable*/,
+                                                    int8_t /*componentMask*/,
+                                                    int64_t /*maxFrames*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getProtectedContentSupport(bool* /*outSupporte*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getDisplayedContentSample(const sp<IBinder>& /*display*/, int64_t /*maxFrames*/,
+                                             int64_t /*timestamp*/,
+                                             gui::DisplayedFrameStats* /*outStats*/) override {
+        return binder::Status::ok();
+    }
+
     binder::Status isWideColorDisplay(const sp<IBinder>& /*token*/,
                                       bool* /*outIsWideColorDisplay*/) override {
         return binder::Status::ok();
     }
 
+    binder::Status addRegionSamplingListener(
+            const gui::ARect& /*samplingArea*/, const sp<IBinder>& /*stopLayerHandle*/,
+            const sp<gui::IRegionSamplingListener>& /*listener*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status removeRegionSamplingListener(
+            const sp<gui::IRegionSamplingListener>& /*listener*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status addFpsListener(int32_t /*taskId*/,
+                                  const sp<gui::IFpsListener>& /*listener*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status removeFpsListener(const sp<gui::IFpsListener>& /*listener*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status addTunnelModeEnabledListener(
+            const sp<gui::ITunnelModeEnabledListener>& /*listener*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status removeTunnelModeEnabledListener(
+            const sp<gui::ITunnelModeEnabledListener>& /*listener*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status setDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/,
+                                              int32_t /*defaultMode*/, bool /*allowGroupSwitching*/,
+                                              float /*primaryRefreshRateMin*/,
+                                              float /*primaryRefreshRateMax*/,
+                                              float /*appRequestRefreshRateMin*/,
+                                              float /*appRequestRefreshRateMax*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/,
+                                              gui::DisplayModeSpecs* /*outSpecs*/) override {
+        return binder::Status::ok();
+    }
+
     binder::Status getDisplayBrightnessSupport(const sp<IBinder>& /*displayToken*/,
                                                bool* /*outSupport*/) override {
         return binder::Status::ok();
@@ -989,6 +962,45 @@
 
     binder::Status notifyPowerBoost(int /*boostId*/) override { return binder::Status::ok(); }
 
+    binder::Status setGlobalShadowSettings(const gui::Color& /*ambientColor*/,
+                                           const gui::Color& /*spotColor*/, float /*lightPosY*/,
+                                           float /*lightPosZ*/, float /*lightRadius*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getDisplayDecorationSupport(
+            const sp<IBinder>& /*displayToken*/,
+            std::optional<gui::DisplayDecorationSupport>* /*outSupport*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status setOverrideFrameRate(int32_t /*uid*/, float /*frameRate*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status addTransactionTraceListener(
+            const sp<gui::ITransactionTraceListener>& /*listener*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getGpuContextPriority(int32_t* /*outPriority*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getMaxAcquiredBufferCount(int32_t* /*buffers*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status addWindowInfosListener(
+            const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status removeWindowInfosListener(
+            const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) override {
+        return binder::Status::ok();
+    }
+
 protected:
     IBinder* onAsBinder() override { return nullptr; }
 
@@ -1034,10 +1046,10 @@
 
 class TestSurface : public Surface {
 public:
-    TestSurface(const sp<IGraphicBufferProducer>& bufferProducer,
-            FenceToFenceTimeMap* fenceMap)
-        : Surface(bufferProducer),
-          mFakeSurfaceComposer(new FakeSurfaceComposer) {
+    TestSurface(const sp<IGraphicBufferProducer>& bufferProducer, FenceToFenceTimeMap* fenceMap)
+          : Surface(bufferProducer),
+            mFakeSurfaceComposer(new FakeSurfaceComposer),
+            mFakeSurfaceComposerAIDL(new FakeSurfaceComposerAIDL) {
         mFakeFrameEventHistory = new FakeProducerFrameEventHistory(fenceMap);
         mFrameEventHistory.reset(mFakeFrameEventHistory);
     }
@@ -1048,6 +1060,10 @@
         return mFakeSurfaceComposer;
     }
 
+    sp<gui::ISurfaceComposer> composerServiceAIDL() const override {
+        return mFakeSurfaceComposerAIDL;
+    }
+
     nsecs_t now() const override {
         return mNow;
     }
@@ -1058,6 +1074,7 @@
 
 public:
     sp<FakeSurfaceComposer> mFakeSurfaceComposer;
+    sp<FakeSurfaceComposerAIDL> mFakeSurfaceComposerAIDL;
     nsecs_t mNow = 0;
 
     // mFrameEventHistory owns the instance of FakeProducerFrameEventHistory,
@@ -1424,6 +1441,7 @@
 TEST_F(GetFrameTimestampsTest, QueryPresentSupported) {
     bool displayPresentSupported = true;
     mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported);
+    mSurface->mFakeSurfaceComposerAIDL->setSupportsPresent(displayPresentSupported);
 
     // Verify supported bits are forwarded.
     int supportsPresent = -1;
@@ -1435,6 +1453,7 @@
 TEST_F(GetFrameTimestampsTest, QueryPresentNotSupported) {
     bool displayPresentSupported = false;
     mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported);
+    mSurface->mFakeSurfaceComposerAIDL->setSupportsPresent(displayPresentSupported);
 
     // Verify supported bits are forwarded.
     int supportsPresent = -1;
@@ -2012,6 +2031,7 @@
 TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) {
     enableFrameTimestamps();
     mSurface->mFakeSurfaceComposer->setSupportsPresent(false);
+    mSurface->mFakeSurfaceComposerAIDL->setSupportsPresent(false);
 
     // Dequeue and queue frame 1.
     const uint64_t fId1 = getNextFrameId();
diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index 99658cc..c51b244 100644
--- a/libs/gui/tests/WindowInfo_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -71,7 +71,6 @@
     i.applicationInfo.name = "ApplicationFooBar";
     i.applicationInfo.token = new BBinder();
     i.applicationInfo.dispatchingTimeoutMillis = 0x12345678ABCD;
-    i.isClone = true;
 
     Parcel p;
     i.writeToParcel(&p);
@@ -102,7 +101,6 @@
     ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop);
     ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle);
     ASSERT_EQ(i.applicationInfo, i2.applicationInfo);
-    ASSERT_EQ(i.isClone, i2.isClone);
 }
 
 TEST(InputApplicationInfo, Parcelling) {
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 5d7874a..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: [
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 13ca9ec..375b684 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -64,9 +64,10 @@
 }
 
 bool shouldDisregardTransformation(uint32_t source) {
-    // Do not apply any transformations to axes from joysticks or touchpads.
+    // Do not apply any transformations to axes from joysticks, touchpads, or relative mice.
     return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) ||
-            isFromSource(source, AINPUT_SOURCE_CLASS_POSITION);
+            isFromSource(source, AINPUT_SOURCE_CLASS_POSITION) ||
+            isFromSource(source, AINPUT_SOURCE_MOUSE_RELATIVE);
 }
 
 bool shouldDisregardOffset(uint32_t source) {
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/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..c3f5151 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() {
@@ -111,11 +118,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 +158,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) {
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/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/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/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 ed728dc..8d8a2bc 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -33,7 +33,7 @@
 
 cc_library_headers {
     name: "libnativedisplay_headers",
-    export_include_dirs: ["include",],
+    export_include_dirs: ["include"],
 }
 
 cc_library_shared {
@@ -43,8 +43,6 @@
         "include-private",
     ],
 
-    clang: true,
-
     cflags: [
         "-Wall",
         "-Werror",
@@ -55,6 +53,7 @@
     version_script: "libnativedisplay.map.txt",
 
     srcs: [
+        ":libgui_frame_event_aidl",
         "AChoreographer.cpp",
         "ADisplay.cpp",
         "surfacetexture/surface_texture.cpp",
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 4a1784e..f3009dd 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -357,12 +357,12 @@
         return INVALID_OPERATION;
     }
 
-    GraphicBuffer* gBuffer = new GraphicBuffer();
+    sp<GraphicBuffer> gBuffer(new GraphicBuffer());
     status_t err = gBuffer->unflatten(data, dataLen, fdData, fdCount);
     if (err != NO_ERROR) {
         return err;
     }
-    *outBuffer = AHardwareBuffer_from_GraphicBuffer(gBuffer);
+    *outBuffer = AHardwareBuffer_from_GraphicBuffer(gBuffer.get());
     // Ensure the buffer has a positive ref-count.
     AHardwareBuffer_acquire(*outBuffer);
 
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..f8c9e4a 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -21,6 +21,7 @@
     ANativeWindow_cancelBuffer; # llndk
     ANativeWindow_dequeueBuffer; # llndk
     ANativeWindow_getBuffersDataSpace; # introduced=28
+    ANativeWindow_getBuffersDefaultDataSpace; # introduced=34
     ANativeWindow_getFormat;
     ANativeWindow_getHeight;
     ANativeWindow_getLastDequeueDuration; # apex # introduced=30
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/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 59ef991..25fe9f2 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -22,6 +22,7 @@
 
 #include <math/mat4.h>
 #include <renderengine/PrintMatrix.h>
+#include <renderengine/BorderRenderInfo.h>
 #include <ui/GraphicTypes.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -79,6 +80,8 @@
     // 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) {
@@ -90,7 +93,8 @@
             lhs.deviceHandlesColorTransform == rhs.deviceHandlesColorTransform &&
             lhs.orientation == rhs.orientation &&
             lhs.targetLuminanceNits == rhs.targetLuminanceNits &&
-            lhs.dimmingStage == rhs.dimmingStage && lhs.renderIntent == rhs.renderIntent;
+            lhs.dimmingStage == rhs.dimmingStage && lhs.renderIntent == rhs.renderIntent &&
+            lhs.borderInfoList == rhs.borderInfoList;
 }
 
 static const char* orientation_to_string(uint32_t orientation) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 97271cb..5187d7b 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -24,16 +24,35 @@
 #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 <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 <android-base/stringprintf.h>
 #include <gl/GrGLInterface.h>
 #include <gui/TraceUtils.h>
@@ -52,8 +71,6 @@
 #include "../gl/GLExtensions.h"
 #include "Cache.h"
 #include "ColorSpaces.h"
-#include "SkBlendMode.h"
-#include "SkImageInfo.h"
 #include "filters/BlurFilter.h"
 #include "filters/GaussianBlurFilter.h"
 #include "filters/KawaseBlurFilter.h"
@@ -311,7 +328,7 @@
         mProtectedPlaceholderSurface(protectedPlaceholder),
         mDefaultPixelFormat(static_cast<PixelFormat>(args.pixelFormat)),
         mUseColorManagement(args.useColorManagement) {
-    sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
+    sk_sp<const GrGLInterface> glInterface = GrGLMakeNativeInterface();
     LOG_ALWAYS_FATAL_IF(!glInterface.get());
 
     GrContextOptions options;
@@ -762,15 +779,9 @@
         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");
+    ATRACE_NAME("SkiaGL::drawLayersInternal");
 
     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()});
@@ -1228,6 +1239,26 @@
             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();
     {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 5ef9944..a8bc4f7 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -41,6 +41,10 @@
 #include "filters/LinearEffect.h"
 #include "filters/StretchShaderFactory.h"
 
+class SkData;
+
+struct SkPoint3;
+
 namespace android {
 namespace renderengine {
 namespace skia {
diff --git a/libs/renderengine/skia/debug/SkiaCapture.cpp b/libs/renderengine/skia/debug/SkiaCapture.cpp
index 856fff4..b21b01c 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.cpp
+++ b/libs/renderengine/skia/debug/SkiaCapture.cpp
@@ -27,6 +27,9 @@
 #include <utils/Trace.h>
 
 #include "CommonPool.h"
+#include "SkCanvas.h"
+#include "SkRect.h"
+#include "SkTypeface.h"
 #include "src/utils/SkMultiPictureDocument.h"
 
 namespace android {
diff --git a/libs/renderengine/skia/debug/SkiaCapture.h b/libs/renderengine/skia/debug/SkiaCapture.h
index f194629..d65a579 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.h
+++ b/libs/renderengine/skia/debug/SkiaCapture.h
@@ -19,13 +19,15 @@
 #include <SkDocument.h>
 #include <SkNWayCanvas.h>
 #include <SkPictureRecorder.h>
+#include <SkRefCnt.h>
+#include <SkStream.h>
 #include <SkSurface.h>
+#include "tools/SkSharingProc.h"
 
 #include <chrono>
 #include <mutex>
 
 #include "CaptureTimer.h"
-#include "tools/SkSharingProc.h"
 
 namespace android {
 namespace renderengine {
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 63cc02b..2557ac9 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -17,7 +17,6 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #include "BlurFilter.h"
 #include <SkCanvas.h>
-#include <SkData.h>
 #include <SkPaint.h>
 #include <SkRRect.h>
 #include <SkRuntimeEffect.h>
diff --git a/libs/renderengine/skia/filters/GaussianBlurFilter.cpp b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp
index 55867a9..f3b6ab9 100644
--- a/libs/renderengine/skia/filters/GaussianBlurFilter.cpp
+++ b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp
@@ -18,7 +18,6 @@
 
 #include "GaussianBlurFilter.h"
 #include <SkCanvas.h>
-#include <SkData.h>
 #include <SkPaint.h>
 #include <SkRRect.h>
 #include <SkRuntimeEffect.h>
diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
index bfde06f..e370c39 100644
--- a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
+++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
@@ -18,7 +18,6 @@
 
 #include "KawaseBlurFilter.h"
 #include <SkCanvas.h>
-#include <SkData.h>
 #include <SkPaint.h>
 #include <SkRRect.h>
 #include <SkRuntimeEffect.h>
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 7c70a74..3340857 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -1606,6 +1606,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();
 
@@ -2411,6 +2441,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();
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/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/ui/Android.bp b/libs/ui/Android.bp
index d138495..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",
@@ -129,7 +127,6 @@
         "DebugUtils.cpp",
         "DeviceProductInfo.cpp",
         "DisplayIdentification.cpp",
-        "DisplayMode.cpp",
         "DynamicDisplayInfo.cpp",
         "Fence.cpp",
         "FenceTime.cpp",
@@ -141,11 +138,9 @@
         "GraphicBuffer.cpp",
         "GraphicBufferAllocator.cpp",
         "GraphicBufferMapper.cpp",
-        "HdrCapabilities.cpp",
         "PixelFormat.cpp",
         "PublicFormat.cpp",
         "StaticAsserts.cpp",
-        "StaticDisplayInfo.cpp",
     ],
 
     include_dirs: [
@@ -243,10 +238,6 @@
     ],
 
     afdo: true,
-
-    header_abi_checker: {
-        diff_flags: ["-allow-adding-removing-weak-symbols"],
-    },
 }
 
 cc_library_headers {
diff --git a/libs/ui/DeviceProductInfo.cpp b/libs/ui/DeviceProductInfo.cpp
index 04d9d3c..3306012 100644
--- a/libs/ui/DeviceProductInfo.cpp
+++ b/libs/ui/DeviceProductInfo.cpp
@@ -17,7 +17,6 @@
 #include <ui/DeviceProductInfo.h>
 
 #include <android-base/stringprintf.h>
-#include <ui/FlattenableHelpers.h>
 #include <utils/Log.h>
 
 #define RETURN_IF_ERROR(op) \
@@ -27,35 +26,6 @@
 
 using base::StringAppendF;
 
-size_t DeviceProductInfo::getFlattenedSize() const {
-    return FlattenableHelpers::getFlattenedSize(name) +
-            FlattenableHelpers::getFlattenedSize(manufacturerPnpId) +
-            FlattenableHelpers::getFlattenedSize(productId) +
-            FlattenableHelpers::getFlattenedSize(manufactureOrModelDate) +
-            FlattenableHelpers::getFlattenedSize(relativeAddress);
-}
-
-status_t DeviceProductInfo::flatten(void* buffer, size_t size) const {
-    if (size < getFlattenedSize()) {
-        return NO_MEMORY;
-    }
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, name));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, manufacturerPnpId));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, productId));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, manufactureOrModelDate));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, relativeAddress));
-    return OK;
-}
-
-status_t DeviceProductInfo::unflatten(void const* buffer, size_t size) {
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &name));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &manufacturerPnpId));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &productId));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &manufactureOrModelDate));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &relativeAddress));
-    return OK;
-}
-
 void DeviceProductInfo::dump(std::string& result) const {
     StringAppendF(&result, "{name=\"%s\", ", name.c_str());
     StringAppendF(&result, "manufacturerPnpId=%s, ", manufacturerPnpId.data());
diff --git a/libs/ui/DisplayMode.cpp b/libs/ui/DisplayMode.cpp
deleted file mode 100644
index cf05dbf..0000000
--- a/libs/ui/DisplayMode.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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 <ui/DisplayMode.h>
-
-#include <cstdint>
-
-#include <ui/FlattenableHelpers.h>
-
-#define RETURN_IF_ERROR(op) \
-    if (const status_t status = (op); status != OK) return status;
-
-namespace android::ui {
-
-size_t DisplayMode::getFlattenedSize() const {
-    return FlattenableHelpers::getFlattenedSize(id) +
-            FlattenableHelpers::getFlattenedSize(resolution) +
-            FlattenableHelpers::getFlattenedSize(xDpi) +
-            FlattenableHelpers::getFlattenedSize(yDpi) +
-            FlattenableHelpers::getFlattenedSize(refreshRate) +
-            FlattenableHelpers::getFlattenedSize(appVsyncOffset) +
-            FlattenableHelpers::getFlattenedSize(sfVsyncOffset) +
-            FlattenableHelpers::getFlattenedSize(presentationDeadline) +
-            FlattenableHelpers::getFlattenedSize(group);
-}
-
-status_t DisplayMode::flatten(void* buffer, size_t size) const {
-    if (size < getFlattenedSize()) {
-        return NO_MEMORY;
-    }
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, id));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, resolution));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, xDpi));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, yDpi));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, refreshRate));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, appVsyncOffset));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, sfVsyncOffset));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, presentationDeadline));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, group));
-    return OK;
-}
-
-status_t DisplayMode::unflatten(const void* buffer, size_t size) {
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &id));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &resolution));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &xDpi));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &yDpi));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &refreshRate));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &appVsyncOffset));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &sfVsyncOffset));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &presentationDeadline));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &group));
-    return OK;
-}
-
-} // namespace android::ui
diff --git a/libs/ui/DynamicDisplayInfo.cpp b/libs/ui/DynamicDisplayInfo.cpp
index 78ba996..f5feea9 100644
--- a/libs/ui/DynamicDisplayInfo.cpp
+++ b/libs/ui/DynamicDisplayInfo.cpp
@@ -18,11 +18,6 @@
 
 #include <cstdint>
 
-#include <ui/FlattenableHelpers.h>
-
-#define RETURN_IF_ERROR(op) \
-    if (const status_t status = (op); status != OK) return status;
-
 namespace android::ui {
 
 std::optional<ui::DisplayMode> DynamicDisplayInfo::getActiveDisplayMode() const {
@@ -34,42 +29,4 @@
     return {};
 }
 
-size_t DynamicDisplayInfo::getFlattenedSize() const {
-    return FlattenableHelpers::getFlattenedSize(supportedDisplayModes) +
-            FlattenableHelpers::getFlattenedSize(activeDisplayModeId) +
-            FlattenableHelpers::getFlattenedSize(supportedColorModes) +
-            FlattenableHelpers::getFlattenedSize(activeColorMode) +
-            FlattenableHelpers::getFlattenedSize(hdrCapabilities) +
-            FlattenableHelpers::getFlattenedSize(autoLowLatencyModeSupported) +
-            FlattenableHelpers::getFlattenedSize(gameContentTypeSupported) +
-            FlattenableHelpers::getFlattenedSize(preferredBootDisplayMode);
-}
-
-status_t DynamicDisplayInfo::flatten(void* buffer, size_t size) const {
-    if (size < getFlattenedSize()) {
-        return NO_MEMORY;
-    }
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedDisplayModes));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeDisplayModeId));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedColorModes));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeColorMode));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, hdrCapabilities));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, autoLowLatencyModeSupported));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, gameContentTypeSupported));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, preferredBootDisplayMode));
-    return OK;
-}
-
-status_t DynamicDisplayInfo::unflatten(const void* buffer, size_t size) {
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedDisplayModes));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeDisplayModeId));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedColorModes));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeColorMode));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &hdrCapabilities));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &autoLowLatencyModeSupported));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &gameContentTypeSupported));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &preferredBootDisplayMode));
-    return OK;
-}
-
 } // namespace android::ui
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
deleted file mode 100644
index aec2fac..0000000
--- a/libs/ui/HdrCapabilities.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <ui/HdrCapabilities.h>
-
-namespace android {
-
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wundefined-reinterpret-cast"
-#endif
-
-size_t HdrCapabilities::getFlattenedSize() const {
-    return  sizeof(mMaxLuminance) +
-            sizeof(mMaxAverageLuminance) +
-            sizeof(mMinLuminance) +
-            sizeof(int32_t) +
-            mSupportedHdrTypes.size() * sizeof(ui::Hdr);
-}
-
-status_t HdrCapabilities::flatten(void* buffer, size_t size) const {
-
-    if (size < getFlattenedSize()) {
-        return NO_MEMORY;
-    }
-
-    int32_t* const buf = static_cast<int32_t*>(buffer);
-    reinterpret_cast<float&>(buf[0]) = mMaxLuminance;
-    reinterpret_cast<float&>(buf[1]) = mMaxAverageLuminance;
-    reinterpret_cast<float&>(buf[2]) = mMinLuminance;
-    buf[3] = static_cast<int32_t>(mSupportedHdrTypes.size());
-    for (size_t i = 0, c = mSupportedHdrTypes.size(); i < c; ++i) {
-        buf[4 + i] = static_cast<int32_t>(mSupportedHdrTypes[i]);
-    }
-    return NO_ERROR;
-}
-
-status_t HdrCapabilities::unflatten(void const* buffer, size_t size) {
-
-    size_t minSize = sizeof(mMaxLuminance) +
-                     sizeof(mMaxAverageLuminance) +
-                     sizeof(mMinLuminance) +
-                     sizeof(int32_t);
-
-    if (size < minSize) {
-        return NO_MEMORY;
-    }
-
-    int32_t const * const buf = static_cast<int32_t const *>(buffer);
-    const size_t itemCount = size_t(buf[3]);
-
-    // check the buffer is large enough
-    if (size < minSize + itemCount * sizeof(int32_t)) {
-        return BAD_VALUE;
-    }
-
-    mMaxLuminance        = reinterpret_cast<float const&>(buf[0]);
-    mMaxAverageLuminance = reinterpret_cast<float const&>(buf[1]);
-    mMinLuminance        = reinterpret_cast<float const&>(buf[2]);
-    if (itemCount) {
-        mSupportedHdrTypes.resize(itemCount);
-        for (size_t i = 0; i < itemCount; ++i) {
-            mSupportedHdrTypes[i] = static_cast<ui::Hdr>(buf[4 + i]);
-        }
-    }
-    return NO_ERROR;
-}
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-
-} // namespace android
diff --git a/libs/ui/StaticDisplayInfo.cpp b/libs/ui/StaticDisplayInfo.cpp
deleted file mode 100644
index 03d15e4..0000000
--- a/libs/ui/StaticDisplayInfo.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <ui/StaticDisplayInfo.h>
-
-#include <cstdint>
-
-#include <ui/FlattenableHelpers.h>
-
-#define RETURN_IF_ERROR(op) \
-    if (const status_t status = (op); status != OK) return status;
-
-namespace android::ui {
-
-size_t StaticDisplayInfo::getFlattenedSize() const {
-    return FlattenableHelpers::getFlattenedSize(connectionType) +
-            FlattenableHelpers::getFlattenedSize(density) +
-            FlattenableHelpers::getFlattenedSize(secure) +
-            FlattenableHelpers::getFlattenedSize(deviceProductInfo) +
-            FlattenableHelpers::getFlattenedSize(installOrientation);
-}
-
-status_t StaticDisplayInfo::flatten(void* buffer, size_t size) const {
-    if (size < getFlattenedSize()) {
-        return NO_MEMORY;
-    }
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, connectionType));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, density));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, secure));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, deviceProductInfo));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, installOrientation));
-    return OK;
-}
-
-status_t StaticDisplayInfo::unflatten(void const* buffer, size_t size) {
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &connectionType));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &density));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &secure));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &deviceProductInfo));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &installOrientation));
-    return OK;
-}
-
-} // namespace android::ui
diff --git a/libs/ui/include/ui/DeviceProductInfo.h b/libs/ui/include/ui/DeviceProductInfo.h
index 807a5d9..879e46f 100644
--- a/libs/ui/include/ui/DeviceProductInfo.h
+++ b/libs/ui/include/ui/DeviceProductInfo.h
@@ -24,8 +24,6 @@
 #include <variant>
 #include <vector>
 
-#include <utils/Flattenable.h>
-
 namespace android {
 
 // NUL-terminated plug and play ID.
@@ -34,7 +32,7 @@
 // Product-specific information about the display or the directly connected device on the
 // display chain. For example, if the display is transitively connected, this field may contain
 // product information about the intermediate device.
-struct DeviceProductInfo : LightFlattenable<DeviceProductInfo> {
+struct DeviceProductInfo {
     struct ModelYear {
         uint32_t year;
     };
@@ -64,11 +62,6 @@
     // For example, for HDMI connected device this will be the physical address.
     std::vector<uint8_t> relativeAddress;
 
-    bool isFixedSize() const { return false; }
-    size_t getFlattenedSize() const;
-    status_t flatten(void* buffer, size_t size) const;
-    status_t unflatten(void const* buffer, size_t size);
-
     void dump(std::string& result) const;
 };
 
diff --git a/libs/ui/include/ui/DisplayMode.h b/libs/ui/include/ui/DisplayMode.h
index 56f68e7..a2791a6 100644
--- a/libs/ui/include/ui/DisplayMode.h
+++ b/libs/ui/include/ui/DisplayMode.h
@@ -29,7 +29,7 @@
 using DisplayModeId = int32_t;
 
 // Mode supported by physical display.
-struct DisplayMode : LightFlattenable<DisplayMode> {
+struct DisplayMode {
     DisplayModeId id;
     ui::Size resolution;
     float xDpi = 0;
@@ -40,11 +40,6 @@
     nsecs_t sfVsyncOffset = 0;
     nsecs_t presentationDeadline = 0;
     int32_t group = -1;
-
-    bool isFixedSize() const { return false; }
-    size_t getFlattenedSize() const;
-    status_t flatten(void* buffer, size_t size) const;
-    status_t unflatten(const void* buffer, size_t size);
 };
 
 } // namespace android::ui
diff --git a/libs/ui/include/ui/DynamicDisplayInfo.h b/libs/ui/include/ui/DynamicDisplayInfo.h
index ce75a65..8c9fe4c 100644
--- a/libs/ui/include/ui/DynamicDisplayInfo.h
+++ b/libs/ui/include/ui/DynamicDisplayInfo.h
@@ -24,12 +24,11 @@
 
 #include <ui/GraphicTypes.h>
 #include <ui/HdrCapabilities.h>
-#include <utils/Flattenable.h>
 
 namespace android::ui {
 
 // Information about a physical display which may change on hotplug reconnect.
-struct DynamicDisplayInfo : LightFlattenable<DynamicDisplayInfo> {
+struct DynamicDisplayInfo {
     std::vector<ui::DisplayMode> supportedDisplayModes;
 
     // This struct is going to be serialized over binder, so
@@ -53,11 +52,6 @@
     ui::DisplayModeId preferredBootDisplayMode;
 
     std::optional<ui::DisplayMode> getActiveDisplayMode() const;
-
-    bool isFixedSize() const { return false; }
-    size_t getFlattenedSize() const;
-    status_t flatten(void* buffer, size_t size) const;
-    status_t unflatten(const void* buffer, size_t size);
 };
 
 } // namespace android::ui
diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h
index 813adde..ae54223 100644
--- a/libs/ui/include/ui/HdrCapabilities.h
+++ b/libs/ui/include/ui/HdrCapabilities.h
@@ -22,12 +22,10 @@
 #include <vector>
 
 #include <ui/GraphicTypes.h>
-#include <utils/Flattenable.h>
 
 namespace android {
 
-class HdrCapabilities : public LightFlattenable<HdrCapabilities>
-{
+class HdrCapabilities {
 public:
     HdrCapabilities(const std::vector<ui::Hdr>& types,
             float maxLuminance, float maxAverageLuminance, float minLuminance)
@@ -49,12 +47,6 @@
     float getDesiredMaxAverageLuminance() const { return mMaxAverageLuminance; }
     float getDesiredMinLuminance() const { return mMinLuminance; }
 
-    // Flattenable protocol
-    bool isFixedSize() const { return false; }
-    size_t getFlattenedSize() const;
-    status_t flatten(void* buffer, size_t size) const;
-    status_t unflatten(void const* buffer, size_t size);
-
 private:
     std::vector<ui::Hdr> mSupportedHdrTypes;
     float mMaxLuminance;
diff --git a/libs/ui/include/ui/StaticDisplayInfo.h b/libs/ui/include/ui/StaticDisplayInfo.h
index cc7c869..566e417 100644
--- a/libs/ui/include/ui/StaticDisplayInfo.h
+++ b/libs/ui/include/ui/StaticDisplayInfo.h
@@ -20,24 +20,18 @@
 
 #include <ui/DeviceProductInfo.h>
 #include <ui/Rotation.h>
-#include <utils/Flattenable.h>
 
 namespace android::ui {
 
 enum class DisplayConnectionType { Internal, External };
 
 // Immutable information about physical display.
-struct StaticDisplayInfo : LightFlattenable<StaticDisplayInfo> {
+struct StaticDisplayInfo {
     DisplayConnectionType connectionType = DisplayConnectionType::Internal;
     float density = 0.f;
     bool secure = false;
     std::optional<DeviceProductInfo> deviceProductInfo;
     Rotation installOrientation = ROTATION_0;
-
-    bool isFixedSize() const { return false; }
-    size_t getFlattenedSize() const;
-    status_t flatten(void* buffer, size_t size) const;
-    status_t unflatten(void const* buffer, size_t size);
 };
 
 } // namespace android::ui
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/vr/libbroadcastring/Android.bp b/libs/vr/libbroadcastring/Android.bp
index fa449ae..e72ca74 100644
--- a/libs/vr/libbroadcastring/Android.bp
+++ b/libs/vr/libbroadcastring/Android.bp
@@ -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/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/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..36ae179 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());
     }
 
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/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 8ce2f35..21695c3 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -331,20 +331,9 @@
     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 "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";
@@ -365,6 +354,18 @@
     }
 }
 
+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::InputClassifier(InputListenerInterface& listener) : mQueuedListener(listener) {}
@@ -504,6 +505,7 @@
 
 void InputClassifier::monitor() {
     std::scoped_lock lock(mLock);
+    if (mMotionClassifier) mMotionClassifier->monitor();
 }
 
 InputClassifier::~InputClassifier() {
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index 56cf760..9b31a3c 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -78,9 +78,14 @@
     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;
 };
 
 /**
@@ -96,7 +101,7 @@
      */
     virtual void dump(std::string& dump) = 0;
 
-    /* Called by the heatbeat to ensures that the classifier has not deadlocked. */
+    /** Called by the heartbeat to ensure that the classifier has not deadlocked. */
     virtual void monitor() = 0;
 
     InputClassifierInterface() { }
@@ -155,13 +160,14 @@
     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.
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 b4b617e..f673a28 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -45,6 +45,101 @@
       ]
     },
     {
+      "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": [
+        {
+          "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": [
         {
diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp
index f57ff33..3ee60a9 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.cpp
+++ b/services/inputflinger/UnwantedInteractionBlocker.cpp
@@ -512,6 +512,15 @@
     return out;
 }
 
+class AndroidPalmRejectionModel : public ::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel {
+public:
+    AndroidPalmRejectionModel()
+          : ::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel(/*default version*/ "",
+                                                                     std::vector<float>()) {
+        config_.resample_touch = true;
+    }
+};
+
 PalmRejector::PalmRejector(const AndroidPalmFilterDeviceInfo& info,
                            std::unique_ptr<::ui::PalmDetectionFilter> filter)
       : mSharedPalmState(std::make_unique<::ui::SharedPalmDetectionFilterState>()),
@@ -523,8 +532,7 @@
         return;
     }
     std::unique_ptr<::ui::NeuralStylusPalmDetectionFilterModel> model =
-            std::make_unique<::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel>(
-                    std::vector<float>());
+            std::make_unique<AndroidPalmRejectionModel>();
     mPalmDetectionFilter =
             std::make_unique<::ui::NeuralStylusPalmDetectionFilter>(mDeviceInfo, std::move(model),
                                                                     mSharedPalmState.get());
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index a2e60c4..ec5841c 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -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;
     }
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/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp
index a02b3e8..4da846b 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;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 5e9427a..625c367 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -56,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;
@@ -1658,6 +1657,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);
@@ -1866,6 +1872,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) {
@@ -1955,7 +1972,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;
@@ -2152,23 +2169,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
@@ -2200,8 +2211,18 @@
                 pointerIds.markBit(pointerId);
             }
 
-            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. */
 
@@ -2278,7 +2299,8 @@
                 if (isSplit) {
                     pointerIds.markBit(entry.pointerProperties[0].id);
                 }
-                tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
+                tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds,
+                                                 entry.eventTime);
             }
         }
     }
@@ -2395,7 +2417,7 @@
                                                        InputTarget::
                                                                FLAG_WINDOW_IS_PARTIALLY_OBSCURED |
                                                        InputTarget::FLAG_DISPATCH_AS_IS,
-                                               BitSet32(0));
+                                               BitSet32(0), entry.eventTime);
                 }
             }
         }
@@ -2406,7 +2428,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
@@ -2591,6 +2614,7 @@
 
 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(),
@@ -2612,6 +2636,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;
@@ -2637,6 +2662,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;
         }
@@ -2921,8 +2948,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
             }
@@ -3678,15 +3709,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;
@@ -3734,11 +3763,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];
@@ -3806,6 +3835,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
@@ -3826,9 +3862,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;
@@ -5015,11 +5051,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) {
@@ -5070,12 +5101,13 @@
         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) {
@@ -5099,7 +5131,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) {
@@ -5249,10 +5281,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";
@@ -5578,7 +5612,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");
@@ -5593,16 +5630,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() ? "[" : ", ";
@@ -5614,8 +5655,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;
 }
 
@@ -5787,14 +5834,6 @@
     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));
-}
-
 void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
     if (connection == nullptr) {
         LOG_ALWAYS_FATAL("Caller must check for nullness");
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index ed89ed0..da4af48 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -121,7 +121,6 @@
     void setInputFilterEnabled(bool enabled) override;
     bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) 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;
@@ -256,6 +255,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()); }
@@ -344,7 +345,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,6 +550,7 @@
 
     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);
@@ -621,12 +622,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);
@@ -652,7 +655,6 @@
     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);
     void updateLastAnrStateLocked(const sp<android::gui::WindowInfoHandle>& window,
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index f46a8bc..047c628 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -286,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;
@@ -359,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.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..0962d0c 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -30,6 +30,10 @@
     sp<gui::WindowInfoHandle> windowHandle;
     int32_t targetFlags;
     BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set
+    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 67fed8b..84d9007 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>
@@ -142,13 +142,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 575b3d7..6ee05da 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;
 
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/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..fe4d443 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];
@@ -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,
@@ -1728,7 +1724,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;
         }
 
@@ -2418,53 +2417,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 9c5a129..79901f0 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -561,28 +561,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..b2d50fc 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -44,6 +44,8 @@
 #include "TouchVideoDevice.h"
 #include "VibrationElement.h"
 
+struct inotify_event;
+
 namespace android {
 
 /* Number of colors : {red, green, blue} */
@@ -311,7 +313,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 +490,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,7 +650,8 @@
     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);
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 a9a4c71..91dc619 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -76,7 +76,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);
@@ -131,12 +131,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;
@@ -144,7 +144,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;
@@ -157,12 +157,13 @@
         mHWheelScale = 1.0f;
     }
 
-    const bool configurePointerCapture = (!changes && config->pointerCaptureRequest.enable) ||
-            (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    const bool configurePointerCapture = mParameters.mode != Parameters::Mode::NAVIGATION &&
+            ((!changes && config->pointerCaptureRequest.enable) ||
+             (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE));
     if (configurePointerCapture) {
         if (config->pointerCaptureRequest.enable) {
-            if (mParameters.mode == Parameters::MODE_POINTER) {
-                mParameters.mode = Parameters::MODE_POINTER_RELATIVE;
+            if (mParameters.mode == Parameters::Mode::POINTER) {
+                mParameters.mode = Parameters::Mode::POINTER_RELATIVE;
                 mSource = AINPUT_SOURCE_MOUSE_RELATIVE;
                 // Keep PointerController around in order to preserve the pointer position.
                 mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
@@ -170,8 +171,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");
@@ -186,8 +187,8 @@
 
     if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED) ||
         configurePointerCapture) {
-        if (config->pointerCaptureRequest.enable) {
-            // Disable any acceleration or scaling when Pointer Capture is enabled.
+        if (mParameters.mode == Parameters::Mode::POINTER_RELATIVE) {
+            // Disable any acceleration or scaling for the pointer when Pointer Capture is enabled.
             mPointerVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
             mWheelXVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
             mWheelYVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
@@ -198,7 +199,8 @@
         }
     }
 
-    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);
@@ -207,8 +209,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) {
@@ -221,12 +224,12 @@
 }
 
 void CursorInputMapper::configureParameters() {
-    mParameters.mode = Parameters::MODE_POINTER;
+    mParameters.mode = Parameters::Mode::POINTER;
     String8 cursorModeString;
     if (getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.mode"),
                                                              cursorModeString)) {
         if (cursorModeString == "navigation") {
-            mParameters.mode = Parameters::MODE_NAVIGATION;
+            mParameters.mode = Parameters::Mode::NAVIGATION;
         } else if (cursorModeString != "pointer" && cursorModeString != "default") {
             ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string());
         }
@@ -237,7 +240,7 @@
                                                          mParameters.orientationAware);
 
     mParameters.hasAssociatedDisplay = false;
-    if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
+    if (mParameters.mode == Parameters::Mode::POINTER || mParameters.orientationAware) {
         mParameters.hasAssociatedDisplay = true;
     }
 }
@@ -246,21 +249,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));
 }
 
@@ -486,7 +475,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..8eb870f 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -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/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index 41a8426..8f5dc9b 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -31,23 +31,15 @@
 
 MultiTouchMotionAccumulator::MultiTouchMotionAccumulator()
       : mCurrentSlot(-1),
-        mSlots(nullptr),
-        mSlotCount(0),
         mUsingSlotsProtocol(false),
         mHaveStylus(false) {}
 
-MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() {
-    delete[] mSlots;
-}
-
 void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount,
                                             bool usingSlotsProtocol) {
-    mSlotCount = slotCount;
     mUsingSlotsProtocol = usingSlotsProtocol;
     mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE);
 
-    delete[] mSlots;
-    mSlots = new Slot[slotCount];
+    mSlots = std::vector<Slot>(slotCount);
 }
 
 void MultiTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) {
@@ -76,10 +68,8 @@
 }
 
 void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) {
-    if (mSlots) {
-        for (size_t i = 0; i < mSlotCount; i++) {
-            mSlots[i].clear();
-        }
+    for (Slot& slot : mSlots) {
+        slot.clear();
     }
     mCurrentSlot = initialSlot;
 }
@@ -96,68 +86,68 @@
             mCurrentSlot = 0;
         }
 
-        if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
+        if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) {
             if (DEBUG_POINTERS) {
                 if (newSlot) {
                     ALOGW("MultiTouch device emitted invalid slot index %d but it "
                           "should be between 0 and %zd; ignoring this slot.",
-                          mCurrentSlot, mSlotCount - 1);
+                          mCurrentSlot, mSlots.size() - 1);
                 }
             }
         } else {
-            Slot* slot = &mSlots[mCurrentSlot];
+            Slot& slot = mSlots[mCurrentSlot];
             // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of
             // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while
             // updating the slot.
             if (!mUsingSlotsProtocol) {
-                slot->mInUse = true;
+                slot.mInUse = true;
             }
 
             switch (rawEvent->code) {
                 case ABS_MT_POSITION_X:
-                    slot->mAbsMTPositionX = rawEvent->value;
-                    warnIfNotInUse(*rawEvent, *slot);
+                    slot.mAbsMTPositionX = rawEvent->value;
+                    warnIfNotInUse(*rawEvent, slot);
                     break;
                 case ABS_MT_POSITION_Y:
-                    slot->mAbsMTPositionY = rawEvent->value;
-                    warnIfNotInUse(*rawEvent, *slot);
+                    slot.mAbsMTPositionY = rawEvent->value;
+                    warnIfNotInUse(*rawEvent, slot);
                     break;
                 case ABS_MT_TOUCH_MAJOR:
-                    slot->mAbsMTTouchMajor = rawEvent->value;
+                    slot.mAbsMTTouchMajor = rawEvent->value;
                     break;
                 case ABS_MT_TOUCH_MINOR:
-                    slot->mAbsMTTouchMinor = rawEvent->value;
-                    slot->mHaveAbsMTTouchMinor = true;
+                    slot.mAbsMTTouchMinor = rawEvent->value;
+                    slot.mHaveAbsMTTouchMinor = true;
                     break;
                 case ABS_MT_WIDTH_MAJOR:
-                    slot->mAbsMTWidthMajor = rawEvent->value;
+                    slot.mAbsMTWidthMajor = rawEvent->value;
                     break;
                 case ABS_MT_WIDTH_MINOR:
-                    slot->mAbsMTWidthMinor = rawEvent->value;
-                    slot->mHaveAbsMTWidthMinor = true;
+                    slot.mAbsMTWidthMinor = rawEvent->value;
+                    slot.mHaveAbsMTWidthMinor = true;
                     break;
                 case ABS_MT_ORIENTATION:
-                    slot->mAbsMTOrientation = rawEvent->value;
+                    slot.mAbsMTOrientation = rawEvent->value;
                     break;
                 case ABS_MT_TRACKING_ID:
                     if (mUsingSlotsProtocol && rawEvent->value < 0) {
                         // The slot is no longer in use but it retains its previous contents,
                         // which may be reused for subsequent touches.
-                        slot->mInUse = false;
+                        slot.mInUse = false;
                     } else {
-                        slot->mInUse = true;
-                        slot->mAbsMTTrackingId = rawEvent->value;
+                        slot.mInUse = true;
+                        slot.mAbsMTTrackingId = rawEvent->value;
                     }
                     break;
                 case ABS_MT_PRESSURE:
-                    slot->mAbsMTPressure = rawEvent->value;
+                    slot.mAbsMTPressure = rawEvent->value;
                     break;
                 case ABS_MT_DISTANCE:
-                    slot->mAbsMTDistance = rawEvent->value;
+                    slot.mAbsMTDistance = rawEvent->value;
                     break;
                 case ABS_MT_TOOL_TYPE:
-                    slot->mAbsMTToolType = rawEvent->value;
-                    slot->mHaveAbsMTToolType = true;
+                    slot.mAbsMTToolType = rawEvent->value;
+                    slot.mHaveAbsMTToolType = true;
                     break;
             }
         }
@@ -186,28 +176,6 @@
 
 // --- MultiTouchMotionAccumulator::Slot ---
 
-MultiTouchMotionAccumulator::Slot::Slot() {
-    clear();
-}
-
-void MultiTouchMotionAccumulator::Slot::clear() {
-    mInUse = false;
-    mHaveAbsMTTouchMinor = false;
-    mHaveAbsMTWidthMinor = false;
-    mHaveAbsMTToolType = false;
-    mAbsMTPositionX = 0;
-    mAbsMTPositionY = 0;
-    mAbsMTTouchMajor = 0;
-    mAbsMTTouchMinor = 0;
-    mAbsMTWidthMajor = 0;
-    mAbsMTWidthMinor = 0;
-    mAbsMTOrientation = 0;
-    mAbsMTTrackingId = -1;
-    mAbsMTPressure = 0;
-    mAbsMTDistance = 0;
-    mAbsMTToolType = 0;
-}
-
 int32_t MultiTouchMotionAccumulator::Slot::getToolType() const {
     if (mHaveAbsMTToolType) {
         switch (mAbsMTToolType) {
@@ -264,14 +232,14 @@
     mHavePointerIds = true;
 
     for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
-        const MultiTouchMotionAccumulator::Slot* inSlot =
+        const MultiTouchMotionAccumulator::Slot& inSlot =
                 mMultiTouchMotionAccumulator.getSlot(inIndex);
-        if (!inSlot->isInUse()) {
+        if (!inSlot.isInUse()) {
             continue;
         }
 
-        if (inSlot->getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) {
-            std::optional<int32_t> id = getActiveBitId(*inSlot);
+        if (inSlot.getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) {
+            std::optional<int32_t> id = getActiveBitId(inSlot);
             if (id) {
                 outState->rawPointerData.canceledIdBits.markBit(id.value());
             }
@@ -292,19 +260,19 @@
         }
 
         RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];
-        outPointer.x = inSlot->getX();
-        outPointer.y = inSlot->getY();
-        outPointer.pressure = inSlot->getPressure();
-        outPointer.touchMajor = inSlot->getTouchMajor();
-        outPointer.touchMinor = inSlot->getTouchMinor();
-        outPointer.toolMajor = inSlot->getToolMajor();
-        outPointer.toolMinor = inSlot->getToolMinor();
-        outPointer.orientation = inSlot->getOrientation();
-        outPointer.distance = inSlot->getDistance();
+        outPointer.x = inSlot.getX();
+        outPointer.y = inSlot.getY();
+        outPointer.pressure = inSlot.getPressure();
+        outPointer.touchMajor = inSlot.getTouchMajor();
+        outPointer.touchMinor = inSlot.getTouchMinor();
+        outPointer.toolMajor = inSlot.getToolMajor();
+        outPointer.toolMinor = inSlot.getToolMinor();
+        outPointer.orientation = inSlot.getOrientation();
+        outPointer.distance = inSlot.getDistance();
         outPointer.tiltX = 0;
         outPointer.tiltY = 0;
 
-        outPointer.toolType = inSlot->getToolType();
+        outPointer.toolType = inSlot.getToolType();
         if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
             outPointer.toolType = mTouchButtonAccumulator.getToolType();
             if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
@@ -318,12 +286,12 @@
 
         bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE &&
                 (mTouchButtonAccumulator.isHovering() ||
-                 (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0));
+                 (mRawPointerAxes.pressure.valid && inSlot.getPressure() <= 0));
         outPointer.isHovering = isHovering;
 
         // Assign pointer id using tracking id if available.
         if (mHavePointerIds) {
-            int32_t trackingId = inSlot->getTrackingId();
+            int32_t trackingId = inSlot.getTrackingId();
             int32_t id = -1;
             if (trackingId >= 0) {
                 for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) {
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index b7c3457..fe8af5d 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -46,29 +46,27 @@
     private:
         friend class MultiTouchMotionAccumulator;
 
-        bool mInUse;
-        bool mHaveAbsMTTouchMinor;
-        bool mHaveAbsMTWidthMinor;
-        bool mHaveAbsMTToolType;
+        bool mInUse = false;
+        bool mHaveAbsMTTouchMinor = false;
+        bool mHaveAbsMTWidthMinor = false;
+        bool mHaveAbsMTToolType = false;
 
-        int32_t mAbsMTPositionX;
-        int32_t mAbsMTPositionY;
-        int32_t mAbsMTTouchMajor;
-        int32_t mAbsMTTouchMinor;
-        int32_t mAbsMTWidthMajor;
-        int32_t mAbsMTWidthMinor;
-        int32_t mAbsMTOrientation;
-        int32_t mAbsMTTrackingId;
-        int32_t mAbsMTPressure;
-        int32_t mAbsMTDistance;
-        int32_t mAbsMTToolType;
+        int32_t mAbsMTPositionX = 0;
+        int32_t mAbsMTPositionY = 0;
+        int32_t mAbsMTTouchMajor = 0;
+        int32_t mAbsMTTouchMinor = 0;
+        int32_t mAbsMTWidthMajor = 0;
+        int32_t mAbsMTWidthMinor = 0;
+        int32_t mAbsMTOrientation = 0;
+        int32_t mAbsMTTrackingId = -1;
+        int32_t mAbsMTPressure = 0;
+        int32_t mAbsMTDistance = 0;
+        int32_t mAbsMTToolType = 0;
 
-        Slot();
-        void clear();
+        void clear() { *this = Slot(); }
     };
 
     MultiTouchMotionAccumulator();
-    ~MultiTouchMotionAccumulator();
 
     void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol);
     void reset(InputDeviceContext& deviceContext);
@@ -76,13 +74,15 @@
     void finishSync();
     bool hasStylus() const;
 
-    inline size_t getSlotCount() const { return mSlotCount; }
-    inline const Slot* getSlot(size_t index) const { return &mSlots[index]; }
+    inline size_t getSlotCount() const { return mSlots.size(); }
+    inline const Slot& getSlot(size_t index) const {
+        LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index);
+        return mSlots[index];
+    }
 
 private:
     int32_t mCurrentSlot;
-    Slot* mSlots;
-    size_t mSlotCount;
+    std::vector<Slot> mSlots;
     bool mUsingSlotsProtocol;
     bool mHaveStylus;
 
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 637b1cb..f07a3e8 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -1053,6 +1053,10 @@
             mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
         }
     } else {
+        if (mPointerController != nullptr && mDeviceMode == DeviceMode::DIRECT &&
+            !mConfig.showTouches) {
+            mPointerController->clearSpots();
+        }
         mPointerController.reset();
     }
 
@@ -4021,10 +4025,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..714ad3f 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;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index df43071..70fd25c 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -58,6 +58,8 @@
         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);
 
@@ -412,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 {}
@@ -1942,6 +1943,77 @@
     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 =
+            new FakeWindowHandle(application, mDispatcher, "Window1", DISPLAY_ID);
+    window1->setTouchableRegion(Region{{0, 0, 100, 100}});
+    sp<FakeWindowHandle> window2 =
+            new FakeWindowHandle(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 =
@@ -5715,7 +5787,6 @@
     virtual void SetUp() override {
         InputDispatcherTest::SetUp();
         mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
-        mDispatcher->setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode::BLOCK);
         mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
     }
 
@@ -6096,6 +6167,7 @@
     sp<FakeWindowHandle> mWindow;
     sp<FakeWindowHandle> mSecondWindow;
     sp<FakeWindowHandle> mDragWindow;
+    sp<FakeWindowHandle> mSpyWindow;
 
     void SetUp() override {
         InputDispatcherTest::SetUp();
@@ -6106,8 +6178,13 @@
         mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
         mSecondWindow->setFrame(Rect(100, 0, 200, 100));
 
+        mSpyWindow = new FakeWindowHandle(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}}});
     }
 
     void injectDown() {
@@ -6118,6 +6195,8 @@
 
         // Window should receive motion event.
         mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+        // 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.
@@ -6130,8 +6209,9 @@
 
         // The drag window covers the entire display
         mDragWindow = new FakeWindowHandle(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
         bool transferred =
@@ -6209,6 +6289,30 @@
     mSecondWindow->assertNoEvents();
 }
 
+TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
+    performDrag();
+
+    // 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();
 
@@ -6862,123 +6966,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.
  */
@@ -7112,6 +7099,277 @@
     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() {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index a26a0bc..901b4de 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;
 };
@@ -887,13 +887,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;
@@ -1209,9 +1209,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;
@@ -1855,34 +1855,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]);
 }
 
@@ -2718,9 +2721,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.";
@@ -2795,16 +2798,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.";
@@ -3726,9 +3729,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]);
 }
@@ -4969,6 +4971,48 @@
     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>();
 
@@ -5363,9 +5407,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]);
 }
@@ -8578,7 +8622,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;
@@ -8605,6 +8650,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) {
diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
index 0062f42..7f14b94 100644
--- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
+++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
@@ -47,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;
@@ -630,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);
@@ -674,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/stats/Android.bp b/services/stats/Android.bp
index 7fea616..7d358e1 100644
--- a/services/stats/Android.bp
+++ b/services/stats/Android.bp
@@ -13,10 +13,13 @@
         "StatsAidl.cpp",
         "StatsHal.cpp",
     ],
-    cflags: ["-Wall", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     shared_libs: [
         "android.frameworks.stats@1.0",
-        "android.frameworks.stats-V1-ndk",
+        "android.frameworks.stats-V2-ndk",
         "libbinder_ndk",
         "libhidlbase",
         "liblog",
@@ -29,10 +32,12 @@
     ],
     export_shared_lib_headers: [
         "android.frameworks.stats@1.0",
-        "android.frameworks.stats-V1-ndk",
+        "android.frameworks.stats-V2-ndk",
     ],
     local_include_dirs: [
         "include/stats",
     ],
-    vintf_fragments: ["android.frameworks.stats@1.0-service.xml"]
+    vintf_fragments: [
+        "android.frameworks.stats-service.xml",
+    ],
 }
diff --git a/services/stats/StatsAidl.cpp b/services/stats/StatsAidl.cpp
index a3b68f1..8d6a9bd 100644
--- a/services/stats/StatsAidl.cpp
+++ b/services/stats/StatsAidl.cpp
@@ -62,6 +62,10 @@
                 AStatsEvent_writeString(event,
                     atomValue.get<VendorAtomValue::stringValue>().c_str());
                 break;
+            case VendorAtomValue::boolValue:
+                AStatsEvent_writeBool(event,
+                    atomValue.get<VendorAtomValue::boolValue>());
+                break;
         }
     }
     AStatsEvent_build(event);
diff --git a/services/stats/android.frameworks.stats@1.0-service.xml b/services/stats/android.frameworks.stats-service.xml
similarity index 93%
rename from services/stats/android.frameworks.stats@1.0-service.xml
rename to services/stats/android.frameworks.stats-service.xml
index c564b7b..7e2635e 100644
--- a/services/stats/android.frameworks.stats@1.0-service.xml
+++ b/services/stats/android.frameworks.stats-service.xml
@@ -11,7 +11,7 @@
 
     <hal format="aidl">
         <name>android.frameworks.stats</name>
-        <version>1</version>
+        <version>2</version>
         <fqname>IStats/default</fqname>
     </hal>
 </manifest>
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 000a2cb..20e86a0 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -143,7 +143,6 @@
         "BackgroundExecutor.cpp",
         "BufferLayer.cpp",
         "BufferLayerConsumer.cpp",
-        "BufferQueueLayer.cpp",
         "BufferStateLayer.cpp",
         "ClientCache.cpp",
         "Client.cpp",
@@ -280,7 +279,7 @@
         "liblog",
     ],
     static_libs: [
-        "SurfaceFlingerProperties",
+        "libSurfaceFlingerProperties",
     ],
     export_shared_lib_headers: [
         "android.hardware.graphics.common@1.2",
@@ -288,6 +287,6 @@
         "libui",
     ],
     export_static_lib_headers: [
-        "SurfaceFlingerProperties",
+        "libSurfaceFlingerProperties",
     ],
 }
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index d9c89cd..fb15f1d 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -738,10 +738,14 @@
 }
 
 void BufferLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) {
-    GLConsumer::computeTransformMatrix(outMatrix,
-                                       mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer()
-                                                           : nullptr,
-                                       mBufferInfo.mCrop, mBufferInfo.mTransform, filteringEnabled);
+    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 BufferLayer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 4c70eb5..3bb0fb3 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -20,7 +20,7 @@
 #include <cstdint>
 #include <list>
 
-#include <gui/ISurfaceComposerClient.h>
+#include <android/gui/ISurfaceComposerClient.h>
 #include <gui/LayerState.h>
 #include <renderengine/Image.h>
 #include <renderengine/Mesh.h>
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
deleted file mode 100644
index bee4de3..0000000
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ /dev/null
@@ -1,575 +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(ftl::SharedFuture<FenceResult> futureFenceResult) {
-    const sp<Fence> releaseFence = futureFenceResult.get().value_or(Fence::NO_FENCE);
-    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) {
-    if (!mConsumer->releasePendingBuffer()) {
-        return;
-    }
-}
-
-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() {
-    mPreviousFrameNumber = mCurrentFrameNumber;
-    mCurrentFrameNumber = mConsumer->getFrameNumber();
-    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 e1c80d5..0000000
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ /dev/null
@@ -1,154 +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(ftl::SharedFuture<FenceResult>) 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() 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 3875f15..d88d7c9 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -853,7 +853,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() {
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 6d7b732..b27055d 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -21,12 +21,16 @@
 
 #include <private/android_filesystem_config.h>
 
+#include <gui/AidlStatusUtil.h>
+
 #include "Client.h"
 #include "Layer.h"
 #include "SurfaceFlinger.h"
 
 namespace android {
 
+using gui::aidl_utils::binderStatusFromStatusT;
+
 // ---------------------------------------------------------------------------
 
 const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
@@ -72,52 +76,74 @@
     return lbc;
 }
 
-status_t Client::createSurface(const String8& name, uint32_t /* w */, uint32_t /* h */,
-                               PixelFormat /* format */, uint32_t flags,
-                               const sp<IBinder>& parentHandle, LayerMetadata metadata,
-                               sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* /* gbp */,
-                               int32_t* outLayerId, uint32_t* outTransformHint) {
+binder::Status Client::createSurface(const std::string& name, int32_t flags,
+                                     const sp<IBinder>& parent, const gui::LayerMetadata& metadata,
+                                     gui::CreateSurfaceResult* outResult) {
     // We rely on createLayer to check permissions.
-    LayerCreationArgs args(mFlinger.get(), this, name.c_str(), flags, std::move(metadata));
-    return mFlinger->createLayer(args, outHandle, parentHandle, outLayerId, nullptr,
-                                 outTransformHint);
+    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));
+    const status_t status =
+            mFlinger->createLayer(args, &handle, parent, &layerId, nullptr, &transformHint);
+    if (status == NO_ERROR) {
+        outResult->handle = handle;
+        outResult->layerId = layerId;
+        outResult->transformHint = static_cast<int32_t>(transformHint);
+    }
+    return binderStatusFromStatusT(status);
 }
 
-status_t Client::createWithSurfaceParent(const String8& /* name */, uint32_t /* w */,
-                                         uint32_t /* h */, PixelFormat /* format */,
-                                         uint32_t /* flags */,
-                                         const sp<IGraphicBufferProducer>& /* parent */,
-                                         LayerMetadata /* metadata */, sp<IBinder>* /* handle */,
-                                         sp<IGraphicBufferProducer>* /* gbp */,
-                                         int32_t* /* outLayerId */,
-                                         uint32_t* /* outTransformHint */) {
-    // This api does not make sense with blast since SF no longer tracks IGBP. This api should be
-    // removed.
-    return BAD_VALUE;
-}
-
-status_t Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,
-                               int32_t* outLayerId) {
-    LayerCreationArgs args(mFlinger.get(), this, "MirrorRoot", 0 /* flags */, LayerMetadata());
-    return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId);
-}
-
-status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
+binder::Status Client::clearLayerFrameStats(const sp<IBinder>& handle) {
+    status_t status;
     sp<Layer> layer = getLayerUser(handle);
     if (layer == nullptr) {
-        return NAME_NOT_FOUND;
+        status = NAME_NOT_FOUND;
+    } else {
+        layer->clearFrameStats();
+        status = NO_ERROR;
     }
-    layer->clearFrameStats();
-    return NO_ERROR;
+    return binderStatusFromStatusT(status);
 }
 
-status_t Client::getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const {
+binder::Status Client::getLayerFrameStats(const sp<IBinder>& handle, gui::FrameStats* outStats) {
+    status_t status;
     sp<Layer> layer = getLayerUser(handle);
     if (layer == nullptr) {
-        return NAME_NOT_FOUND;
+        status = NAME_NOT_FOUND;
+    } else {
+        FrameStats stats;
+        layer->getFrameStats(&stats);
+        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);
+        }
+        status = NO_ERROR;
     }
-    layer->getFrameStats(outStats);
-    return NO_ERROR;
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle,
+                                     gui::MirrorSurfaceResult* outResult) {
+    sp<IBinder> handle;
+    int32_t layerId;
+    LayerCreationArgs args(mFlinger.get(), this, "MirrorRoot", 0 /* flags */, gui::LayerMetadata());
+    status_t status = mFlinger->mirrorLayer(args, mirrorFromHandle, &handle, &layerId);
+    if (status == NO_ERROR) {
+        outResult->handle = handle;
+        outResult->layerId = layerId;
+    }
+    return binderStatusFromStatusT(status);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 15cd763..4720d5c 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -24,15 +24,14 @@
 #include <utils/KeyedVector.h>
 #include <utils/Mutex.h>
 
-#include <gui/ISurfaceComposerClient.h>
+#include <android/gui/BnSurfaceComposerClient.h>
 
 namespace android {
 
 class Layer;
 class SurfaceFlinger;
 
-class Client : public BnSurfaceComposerClient
-{
+class Client : public gui::BnSurfaceComposerClient {
 public:
     explicit Client(const sp<SurfaceFlinger>& flinger);
     ~Client() = default;
@@ -47,25 +46,18 @@
 
 private:
     // ISurfaceComposerClient interface
-    virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
-                                   uint32_t flags, const sp<IBinder>& parent,
-                                   LayerMetadata metadata, sp<IBinder>* handle,
-                                   sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId,
-                                   uint32_t* outTransformHint = nullptr);
 
-    virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
-                                             PixelFormat format, uint32_t flags,
-                                             const sp<IGraphicBufferProducer>& parent,
-                                             LayerMetadata metadata, sp<IBinder>* handle,
-                                             sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId,
-                                             uint32_t* outTransformHint = nullptr);
+    binder::Status createSurface(const std::string& name, int32_t flags, const sp<IBinder>& parent,
+                                 const gui::LayerMetadata& metadata,
+                                 gui::CreateSurfaceResult* outResult) override;
 
-    status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* handle,
-                           int32_t* outLayerId);
+    binder::Status clearLayerFrameStats(const sp<IBinder>& handle) override;
 
-    virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
+    binder::Status getLayerFrameStats(const sp<IBinder>& handle,
+                                      gui::FrameStats* outStats) override;
 
-    virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;
+    binder::Status mirrorSurface(const sp<IBinder>& mirrorFromHandle,
+                                 gui::MirrorSurfaceResult* outResult) override;
 
     // constant
     sp<SurfaceFlinger> mFlinger;
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/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index db2fd1b..2203639 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -27,6 +27,7 @@
 #include <compositionengine/LayerFE.h>
 #include <renderengine/LayerSettings.h>
 #include <ui/Fence.h>
+#include <ui/FenceTime.h>
 #include <ui/GraphicTypes.h>
 #include <ui/LayerStack.h>
 #include <ui/Region.h>
@@ -311,6 +312,8 @@
             const Region& flashRegion,
             std::vector<LayerFE::LayerSettings>& clientCompositionLayers) = 0;
     virtual void setExpensiveRenderingExpected(bool enabled) = 0;
+    virtual void setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) = 0;
+    virtual bool isPowerHintSessionEnabled() = 0;
     virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0;
     virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 61a0e6a..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 31c51e6..fc8dd8b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -140,6 +140,8 @@
           std::vector<LayerFE*> &outLayerFEs) override;
     void appendRegionFlashRequests(const Region&, std::vector<LayerFE::LayerSettings>&) override;
     void setExpensiveRenderingExpected(bool enabled) override;
+    void setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) override;
+    bool isPowerHintSessionEnabled() override;
     void dumpBase(std::string&) const;
 
     // Implemented by the final implementation for the final state it uses.
@@ -152,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 7709b96..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>
@@ -164,6 +165,8 @@
 
     bool treat170mAsSrgb = false;
 
+    std::vector<renderengine::BorderRenderInfo> borderInfoList;
+
     uint64_t lastOutputLayerHash = 0;
     uint64_t outputLayerHash = 0;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index cb9fbad..2a04949 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -133,6 +133,8 @@
     MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
     MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
     MOCK_METHOD1(setTreat170mAsSrgb, void(bool));
+    MOCK_METHOD(void, setHintSessionGpuFence, (std::unique_ptr<FenceTime> && gpuFence));
+    MOCK_METHOD(bool, isPowerHintSessionEnabled, ());
 };
 
 } // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index b79b46b..ea856e4 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -243,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);
@@ -257,6 +260,11 @@
         return false;
     }
 
+    if (isPowerHintSessionEnabled()) {
+        mPowerAdvisor->setHwcValidateTiming(mId, startTime, systemTime());
+        mPowerAdvisor->setRequiresClientComposition(mId, requiresClientComposition);
+    }
+
     return true;
 }
 
@@ -356,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
@@ -384,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:
@@ -396,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/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index c3385a8..509312f 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -733,6 +733,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() {
@@ -1099,6 +1137,10 @@
         return;
     }
 
+    if (isPowerHintSessionEnabled()) {
+        // get fence end time to know when gpu is complete in display
+        setHintSessionGpuFence(std::make_unique<FenceTime>(new Fence(dup(optReadyFence->get()))));
+    }
     // swap buffers (presentation)
     mRenderSurface->queueBuffer(std::move(*optReadyFence));
 }
@@ -1195,6 +1237,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();
 
@@ -1403,6 +1452,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__);
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 948c0c9..c512a1e 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -62,14 +62,18 @@
     dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits);
     dumpVal(out, "clientTargetBrightness", clientTargetBrightness);
     dumpVal(out, "displayBrightness", displayBrightness);
-
     out.append("\n   ");
     dumpVal(out, "compositionStrategyPredictionState", ftl::enum_string(strategyPrediction));
+    out.append("\n   ");
 
     out.append("\n   ");
     dumpVal(out, "treate170mAsSrgb", treat170mAsSrgb);
 
-    out += '\n';
+    out.append("\n");
+    for (const auto& borderRenderInfo : borderInfoList) {
+        dumpVal(out, "borderRegion", borderRenderInfo.combinedRegion);
+    }
+    out.append("\n");
 }
 
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 0e5a7b6..344fea3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -169,6 +169,7 @@
         EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
         EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
         EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
+        EXPECT_CALL(mPowerAdvisor, usePowerHintSession()).WillRepeatedly(Return(false));
     }
 
     DisplayCreationArgs getDisplayCreationArgsForPhysicalDisplay() {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 9b12b08..d7704a8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -137,6 +137,7 @@
     MOCK_METHOD(bool, hasDisplayIdleTimerCapability, (PhysicalDisplayId), (const, override));
     MOCK_METHOD(Hwc2::AidlTransform, getPhysicalDisplayOrientation, (PhysicalDisplayId),
                 (const, override));
+    MOCK_METHOD(bool, getValidateSkipped, (HalDisplayId), (const, override));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index 50adcfb..8c164ed 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -38,11 +38,32 @@
     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, setPresentFenceTime, (nsecs_t presentFenceTime), (override));
+    MOCK_METHOD(void, setHwcPresentDelayedTime,
+                (DisplayId displayId,
+                 std::chrono::steady_clock::time_point earliestFrameStartTime));
+    MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override));
+    MOCK_METHOD(void, setCommitStart, (nsecs_t commitStartTime), (override));
+    MOCK_METHOD(void, setCompositeEnd, (nsecs_t compositeEndtime), (override));
+    MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override));
+    MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (int64_t targetDuration), (override));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 063726b..505f94e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3319,6 +3319,9 @@
         MOCK_METHOD2(appendRegionFlashRequests,
                      void(const Region&, std::vector<LayerFE::LayerSettings>&));
         MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
+        MOCK_METHOD(void, setHintSessionGpuFence, (std::unique_ptr<FenceTime> && gpuFence),
+                    (override));
+        MOCK_METHOD(bool, isPowerHintSessionEnabled, (), (override));
     };
 
     OutputComposeSurfacesTest() {
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a915b61..8680900 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -211,6 +211,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(),
@@ -537,6 +538,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..2161436 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -249,6 +249,10 @@
     nsecs_t getVsyncPeriodFromHWC() const;
     nsecs_t getRefreshTimestamp() const;
 
+    status_t setRefreshRatePolicy(
+            const std::optional<scheduler::RefreshRateConfigs::Policy>& policy,
+            bool overridePolicy);
+
     // release HWC resources (if any) for removable displays
     void disconnect();
 
@@ -303,6 +307,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/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 24aef9b..486eaf8 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -88,7 +88,7 @@
 
     virtual hal::HWDisplayId getId() const = 0;
     virtual bool isConnected() const = 0;
-    virtual void setConnected(bool connected) = 0; // For use by Device only
+    virtual void setConnected(bool connected) = 0; // For use by HWComposer only
     virtual bool hasCapability(
             aidl::android::hardware::graphics::composer3::DisplayCapability) const = 0;
     virtual bool isVsyncPeriodSwitchSupported() const = 0;
@@ -253,7 +253,7 @@
     // Other Display methods
     hal::HWDisplayId getId() const override { return mId; }
     bool isConnected() const override { return mIsConnected; }
-    void setConnected(bool connected) override; // For use by Device only
+    void setConnected(bool connected) override;
     bool hasCapability(aidl::android::hardware::graphics::composer3::DisplayCapability)
             const override EXCLUDES(mDisplayCapabilitiesMutex);
     bool isVsyncPeriodSwitchSupported() const override;
@@ -271,7 +271,7 @@
 
     // Member variables
 
-    // These are references to data owned by HWC2::Device, which will outlive
+    // These are references to data owned by HWComposer, which will outlive
     // this HWC2::Display, so these references are guaranteed to be valid for
     // the lifetime of this object.
     android::Hwc2::Composer& mComposer;
@@ -383,7 +383,7 @@
     hal::Error setBlockingRegion(const android::Region& region) override;
 
 private:
-    // These are references to data owned by HWC2::Device, which will outlive
+    // These are references to data owned by HWComposer, which will outlive
     // this HWC2::Layer, so these references are guaranteed to be valid for
     // the lifetime of this object.
     android::Hwc2::Composer& mComposer;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 0da8ece..a6aee1f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -738,6 +738,13 @@
             });
 }
 
+bool HWComposer::getValidateSkipped(HalDisplayId displayId) const {
+    if (mDisplayData.count(displayId) == 0) {
+        return false;
+    }
+    return mDisplayData.at(displayId).validateWasSkipped;
+}
+
 status_t HWComposer::setBootDisplayMode(PhysicalDisplayId displayId,
                                         hal::HWConfigId displayModeId) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 4c0ecd8..92a8f30 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -199,6 +199,9 @@
             PhysicalDisplayId, float brightness, float brightnessNits,
             const Hwc2::Composer::DisplayBrightnessOptions&) = 0;
 
+    // Get whether the display skipped validation on the latest present
+    virtual bool getValidateSkipped(HalDisplayId displayId) const = 0;
+
     // Events handling ---------------------------------------------------------
 
     // Returns stable display ID (and display name on connection of new or previously disconnected
@@ -397,6 +400,8 @@
 
     status_t setActiveColorMode(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent) override;
 
+    bool getValidateSkipped(HalDisplayId displayId) const override;
+
     // Composer 2.4
     ui::DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override;
     bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const override;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index b5678b4..77dda6c 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -196,7 +196,7 @@
     return mPowerHintSessionRunning;
 }
 
-void PowerAdvisor::setTargetWorkDuration(int64_t targetDurationNanos) {
+void PowerAdvisor::setTargetWorkDuration(int64_t targetDuration) {
     if (!usePowerHintSession()) {
         ALOGV("Power hint session target duration cannot be set, skipping");
         return;
@@ -205,26 +205,45 @@
         std::lock_guard lock(mPowerHalMutex);
         HalWrapper* const halWrapper = getPowerHal();
         if (halWrapper != nullptr) {
-            halWrapper->setTargetWorkDuration(targetDurationNanos - kTargetSafetyMargin.count());
+            halWrapper->setTargetWorkDuration(targetDuration);
         }
     }
 }
 
-void PowerAdvisor::sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) {
+void PowerAdvisor::sendActualWorkDuration() {
     if (!mBootFinished || !usePowerHintSession()) {
         ALOGV("Actual work duration power hint cannot be sent, skipping");
         return;
     }
-    {
+    const std::optional<nsecs_t> actualDuration = estimateWorkDuration(false);
+    if (actualDuration.has_value()) {
         std::lock_guard lock(mPowerHalMutex);
         HalWrapper* const halWrapper = getPowerHal();
         if (halWrapper != nullptr) {
-            halWrapper->sendActualWorkDuration(actualDurationNanos, timeStampNanos);
+            halWrapper->sendActualWorkDuration(*actualDuration + kTargetSafetyMargin.count(),
+                                               systemTime());
         }
     }
 }
 
-// needs to be set after the flag is known but before PowerAdvisor enters onBootFinished
+void PowerAdvisor::sendPredictedWorkDuration() {
+    if (!mBootFinished || !usePowerHintSession()) {
+        ALOGV("Actual work duration power hint cannot be sent, skipping");
+        return;
+    }
+
+    const std::optional<nsecs_t> predictedDuration = estimateWorkDuration(true);
+
+    if (predictedDuration.has_value()) {
+        std::lock_guard lock(mPowerHalMutex);
+        HalWrapper* const halWrapper = getPowerHal();
+        if (halWrapper != nullptr) {
+            halWrapper->sendActualWorkDuration(*predictedDuration + kTargetSafetyMargin.count(),
+                                               systemTime());
+        }
+    }
+}
+
 void PowerAdvisor::enablePowerHint(bool enabled) {
     mPowerHintEnabled = enabled;
 }
@@ -244,6 +263,301 @@
     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::setPresentFenceTime(nsecs_t presentFenceTime) {
+    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) {
+    mLastCompositeEndTime = compositeEnd;
+    // calculate the postcomp time here as well
+    std::vector<DisplayId>&& displays = getOrderedDisplayIds(&DisplayTimingData::hwcPresentEndTime);
+    DisplayTimingData& timingData = mDisplayTimingData[displays.back()];
+    mLastPostcompDuration = compositeEnd -
+            (timingData.skippedValidate ? *timingData.hwcValidateEndTime
+                                        : *timingData.hwcPresentEndTime);
+}
+
+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 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);
+
+    // Don't count time spent idly waiting in the estimate as we could do more work in that time
+    estimatedEndTime -= 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 = estimatedEndTime + mLastPostcompDuration - mCommitStartTimes[0];
+    nsecs_t combinedDuration = combineTimingEstimates(totalDuration, flingerDuration);
+
+    return std::make_optional(combinedDuration);
+}
+
+nsecs_t PowerAdvisor::combineTimingEstimates(nsecs_t totalDuration, nsecs_t flingerDuration) {
+    nsecs_t targetDuration;
+    {
+        std::lock_guard lock(mPowerHalMutex);
+        targetDuration = *getPowerHal()->getTargetWorkDuration();
+    }
+    if (!mTotalFrameTargetDuration.has_value()) return flingerDuration;
+
+    // Normalize total to the flinger target (vsync period) since that's how often we actually send
+    // hints
+    nsecs_t normalizedTotalDuration = (targetDuration * totalDuration) / *mTotalFrameTargetDuration;
+    return std::max(flingerDuration, normalizedTotalDuration);
+}
+
+PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimeline::estimateTimelineFromReference(
+        nsecs_t fenceTime, nsecs_t displayStartTime) {
+    DisplayTimeline estimated;
+    estimated.hwcPresentStartTime = displayStartTime;
+
+    // We don't predict waiting for vsync alignment yet
+    estimated.hwcPresentDelayDuration = 0;
+
+    // How long we expect to run before we start waiting for the fence
+    // For now just re-use last frame's post-present duration and assume it will not change much
+    // Excludes time spent waiting for vsync since that's not going to be consistent
+    estimated.presentFenceWaitStartTime = estimated.hwcPresentStartTime +
+            (presentFenceWaitStartTime - (hwcPresentStartTime + hwcPresentDelayDuration));
+    estimated.probablyWaitsForPresentFence = fenceTime > estimated.presentFenceWaitStartTime;
+    estimated.hwcPresentEndTime = postPresentFenceHwcPresentDuration +
+            (estimated.probablyWaitsForPresentFence ? fenceTime
+                                                    : estimated.presentFenceWaitStartTime);
+    return estimated;
+}
+
+PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayTimeline(
+        nsecs_t fenceTime) {
+    DisplayTimeline timeline;
+    // How long between calling hwc present and trying to wait on the fence
+    const nsecs_t fenceWaitStartDelay =
+            (skippedValidate ? kFenceWaitStartDelaySkippedValidate : kFenceWaitStartDelayValidated)
+                    .count();
+
+    // Did our reference frame wait for an appropriate vsync before calling into hwc
+    const bool waitedOnHwcPresentTime = hwcPresentDelayedTime.has_value() &&
+            *hwcPresentDelayedTime > *hwcPresentStartTime &&
+            *hwcPresentDelayedTime < *hwcPresentEndTime;
+
+    // Use validate start here if we skipped it because we did validate + present together
+    timeline.hwcPresentStartTime = skippedValidate ? *hwcValidateStartTime : *hwcPresentStartTime;
+
+    // Use validate end here if we skipped it because we did validate + present together
+    timeline.hwcPresentEndTime = skippedValidate ? *hwcValidateEndTime : *hwcPresentEndTime;
+
+    // How long hwc present was delayed waiting for the next appropriate vsync
+    timeline.hwcPresentDelayDuration =
+            (waitedOnHwcPresentTime ? *hwcPresentDelayedTime - *hwcPresentStartTime : 0);
+    // When we started waiting for the present fence after calling into hwc present
+    timeline.presentFenceWaitStartTime =
+            timeline.hwcPresentStartTime + timeline.hwcPresentDelayDuration + fenceWaitStartDelay;
+    timeline.probablyWaitsForPresentFence = fenceTime > timeline.presentFenceWaitStartTime &&
+            fenceTime < timeline.hwcPresentEndTime;
+
+    // How long we ran after we finished waiting for the fence but before hwc present finished
+    timeline.postPresentFenceHwcPresentDuration = timeline.hwcPresentEndTime -
+            (timeline.probablyWaitsForPresentFence ? fenceTime
+                                                   : timeline.presentFenceWaitStartTime);
+    return timeline;
+}
+
+std::optional<PowerAdvisor::GpuTimeline> PowerAdvisor::DisplayTimingData::estimateGpuTiming(
+        std::optional<nsecs_t> previousEnd) {
+    if (!(usedClientComposition && lastValidGpuStartTime.has_value() && gpuEndFenceTime)) {
+        return std::nullopt;
+    }
+    const nsecs_t latestGpuStartTime = std::max(previousEnd.value_or(0), *gpuStartTime);
+    const nsecs_t latestGpuEndTime = gpuEndFenceTime->getSignalTime();
+    nsecs_t gpuDuration = 0;
+    if (latestGpuEndTime != Fence::SIGNAL_TIME_INVALID &&
+        latestGpuEndTime != Fence::SIGNAL_TIME_PENDING) {
+        // If we know how long the most recent gpu duration was, use that
+        gpuDuration = latestGpuEndTime - latestGpuStartTime;
+    } else if (lastValidGpuEndTime.has_value()) {
+        // If we don't have the fence data, use the most recent information we do have
+        gpuDuration = *lastValidGpuEndTime - *lastValidGpuStartTime;
+        if (latestGpuEndTime == Fence::SIGNAL_TIME_PENDING) {
+            // If pending but went over the previous duration, use current time as the end
+            gpuDuration = std::max(gpuDuration, systemTime() - latestGpuStartTime);
+        }
+    }
+    return GpuTimeline{.duration = gpuDuration, .startTime = latestGpuStartTime};
+}
+
 class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
 public:
     HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
@@ -325,6 +639,10 @@
     }
 
     mSupportsPowerHint = checkPowerHintSessionSupported();
+
+    mAllowedActualDeviation =
+            base::GetIntProperty<nsecs_t>("debug.sf.allowed_actual_deviation",
+                                          std::chrono::nanoseconds(250us).count());
 }
 
 AidlPowerHalWrapper::~AidlPowerHalWrapper() {
@@ -332,7 +650,7 @@
         mPowerHintSession->close();
         mPowerHintSession = nullptr;
     }
-};
+}
 
 std::unique_ptr<PowerAdvisor::HalWrapper> AidlPowerHalWrapper::connect() {
     // This only waits if the service is actually declared
@@ -370,7 +688,7 @@
     return ret.isOk();
 }
 
-// only version 2+ of the aidl supports power hint sessions, hidl has no support
+// Only version 2+ of the aidl supports power hint sessions, hidl has no support
 bool AidlPowerHalWrapper::supportsPowerHintSession() {
     return mSupportsPowerHint;
 }
@@ -424,30 +742,14 @@
     return isPowerHintSessionRunning();
 }
 
-bool AidlPowerHalWrapper::shouldSetTargetDuration(int64_t targetDurationNanos) {
-    if (targetDurationNanos <= 0) {
-        return false;
-    }
-    // report if the change in target from our last submission to now exceeds the threshold
-    return abs(1.0 -
-               static_cast<double>(mLastTargetDurationSent) /
-                       static_cast<double>(targetDurationNanos)) >= kAllowedTargetDeviationPercent;
-}
-
-void AidlPowerHalWrapper::setTargetWorkDuration(int64_t targetDurationNanos) {
+void AidlPowerHalWrapper::setTargetWorkDuration(int64_t targetDuration) {
     ATRACE_CALL();
-    mTargetDuration = targetDurationNanos;
-    if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos);
-    if (!sNormalizeTarget && isPowerHintSessionRunning() &&
-        shouldSetTargetDuration(targetDurationNanos)) {
-        if (mLastActualDurationSent.has_value()) {
-            // update the error term here since we are actually sending an update to powerhal
-            if (sTraceHintSessionData)
-                ATRACE_INT64("Target error term", targetDurationNanos - *mLastActualDurationSent);
-        }
-        ALOGV("Sending target time: %" PRId64 "ns", targetDurationNanos);
-        mLastTargetDurationSent = targetDurationNanos;
-        auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
+    mTargetDuration = targetDuration;
+    if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration);
+    if (isPowerHintSessionRunning() && (targetDuration != mLastTargetDurationSent)) {
+        ALOGV("Sending target time: %" PRId64 "ns", targetDuration);
+        mLastTargetDurationSent = targetDuration;
+        auto ret = mPowerHintSession->updateTargetWorkDuration(targetDuration);
         if (!ret.isOk()) {
             ALOGW("Failed to set power hint target work duration with error: %s",
                   ret.exceptionMessage().c_str());
@@ -456,8 +758,8 @@
     }
 }
 
-bool AidlPowerHalWrapper::shouldReportActualDurationsNow() {
-    // report if we have never reported before or are approaching a stale session
+bool AidlPowerHalWrapper::shouldReportActualDurations() {
+    // Report if we have never reported before or are approaching a stale session
     if (!mLastActualDurationSent.has_value() ||
         (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
         return true;
@@ -466,65 +768,42 @@
     if (!mActualDuration.has_value()) {
         return false;
     }
-
-    // duration of most recent timing
-    const double mostRecentActualDuration = static_cast<double>(*mActualDuration);
-    // duration of the last timing actually reported to the powerhal
-    const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent);
-
-    // report if the change in duration from then to now exceeds the threshold
-    return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
-            kAllowedActualDeviationPercent;
+    // Report if the change in actual duration exceeds the threshold
+    return abs(*mActualDuration - *mLastActualDurationSent) > mAllowedActualDeviation;
 }
 
-void AidlPowerHalWrapper::sendActualWorkDuration(int64_t actualDurationNanos,
-                                                 nsecs_t timeStampNanos) {
+void AidlPowerHalWrapper::sendActualWorkDuration(int64_t actualDuration, nsecs_t timestamp) {
     ATRACE_CALL();
 
-    if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
+    if (actualDuration < 0 || !isPowerHintSessionRunning()) {
         ALOGV("Failed to send actual work duration, skipping");
         return;
     }
-    nsecs_t reportedDuration = actualDurationNanos;
+    const nsecs_t reportedDuration = actualDuration;
 
-    // normalize the sent values to a pre-set target
-    if (sNormalizeTarget) {
-        reportedDuration += mLastTargetDurationSent - mTargetDuration;
-    } else {
-        // when target duration change is within deviation and not updated, adjust the actual
-        // duration proportionally based on the difference, e.g. if new target is 5ms longer than
-        // last reported but actual duration is the same as last target, we want to report a smaller
-        // actual work duration now to indicate that we are overshooting
-        if (mLastTargetDurationSent != kDefaultTarget.count() && mTargetDuration != 0) {
-            reportedDuration =
-                    static_cast<int64_t>(static_cast<long double>(mLastTargetDurationSent) /
-                                         mTargetDuration * actualDurationNanos);
-            mActualDuration = reportedDuration;
-        }
-    }
     mActualDuration = reportedDuration;
     WorkDuration duration;
     duration.durationNanos = reportedDuration;
-    duration.timeStampNanos = timeStampNanos;
+    duration.timeStampNanos = timestamp;
     mPowerHintQueue.push_back(duration);
 
     if (sTraceHintSessionData) {
-        ATRACE_INT64("Measured duration", actualDurationNanos);
-        ATRACE_INT64("Target error term", mTargetDuration - actualDurationNanos);
+        ATRACE_INT64("Measured duration", actualDuration);
+        ATRACE_INT64("Target error term", actualDuration - mTargetDuration);
 
         ATRACE_INT64("Reported duration", reportedDuration);
         ATRACE_INT64("Reported target", mLastTargetDurationSent);
-        ATRACE_INT64("Reported target error term", mLastTargetDurationSent - reportedDuration);
+        ATRACE_INT64("Reported target error term", reportedDuration - mLastTargetDurationSent);
     }
 
     ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64
           " with error: %" PRId64,
-          reportedDuration, mLastTargetDurationSent, mLastTargetDurationSent - reportedDuration);
+          reportedDuration, mLastTargetDurationSent, reportedDuration - mLastTargetDurationSent);
 
     // This rate limiter queues similar duration reports to the powerhal into
     // batches to avoid excessive binder calls. The criteria to send a given batch
     // are outlined in shouldReportActualDurationsNow()
-    if (shouldReportActualDurationsNow()) {
+    if (shouldReportActualDurations()) {
         ALOGV("Sending hint update batch");
         mLastActualReportTimestamp = systemTime();
         auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
@@ -534,8 +813,8 @@
             mShouldReconnectHal = true;
         }
         mPowerHintQueue.clear();
-        // we save the non-normalized value here to detect % changes
-        mLastActualDurationSent = reportedDuration;
+        // We save the actual duration here for rate limiting
+        mLastActualDurationSent = actualDuration;
     }
 }
 
@@ -551,12 +830,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;
@@ -565,7 +845,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;
 
@@ -582,7 +862,7 @@
 
     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;
         }
@@ -590,7 +870,7 @@
         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
@@ -601,13 +881,12 @@
         sHalWrapper = HidlPowerHalWrapper::connect();
     } else {
         ALOGD("Successfully connecting AIDL Power HAL");
-        // if AIDL, pass on any existing hint session values
-        // thread ids always safe to set
+        // 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 7c10e19..98921b0 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 once it's known at the end of the frame
+    virtual void setPresentFenceTime(nsecs_t presentFenceTime) = 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 setPresentFenceTime(nsecs_t presentFenceTime) 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,15 +159,6 @@
     std::mutex mPowerHalMutex;
 
     std::atomic_bool mBootFinished = false;
-    std::optional<bool> mPowerHintEnabled;
-    std::optional<bool> mSupportsPowerHint;
-    bool mPowerHintSessionRunning = false;
-
-    // An adjustable safety margin which moves the "target" earlier to allow flinger to
-    // go a bit over without dropping a frame, especially since we can't measure
-    // the exact time HWC finishes composition so "actual" durations are measured
-    // from the end of present() instead, which is a bit later.
-    static constexpr const std::chrono::nanoseconds kTargetSafetyMargin = 2ms;
 
     std::unordered_set<DisplayId> mExpensiveDisplays;
     bool mNotifiedExpensiveRendering = false;
@@ -117,6 +167,110 @@
     std::atomic_bool mSendUpdateImminent = true;
     std::atomic<nsecs_t> mLastScreenUpdatedTime = 0;
     std::optional<scheduler::OneShotTimer> mScreenUpdateTimer;
+
+    // Higher-level timing data used for estimation
+    struct DisplayTimeline {
+        // The start of hwc present, or the start of validate if it happened there instead
+        nsecs_t hwcPresentStartTime = -1;
+        // The end of hwc present or validate, whichever one actually presented
+        nsecs_t hwcPresentEndTime = -1;
+        // How long the actual hwc present was delayed after hwcPresentStartTime
+        nsecs_t hwcPresentDelayDuration = 0;
+        // When we think we started waiting for the present fence after calling into hwc present and
+        // after potentially waiting for the earliest present time
+        nsecs_t presentFenceWaitStartTime = -1;
+        // How long we ran after we finished waiting for the fence but before hwc present finished
+        nsecs_t postPresentFenceHwcPresentDuration = 0;
+        // Are we likely to have waited for the present fence during composition
+        bool probablyWaitsForPresentFence = false;
+        // Estimate one frame's timeline from that of a previous frame
+        DisplayTimeline estimateTimelineFromReference(nsecs_t fenceTime, nsecs_t displayStartTime);
+    };
+
+    struct GpuTimeline {
+        nsecs_t duration = 0;
+        nsecs_t startTime = -1;
+    };
+
+    // Power hint session data recorded from the pipeline
+    struct DisplayTimingData {
+        std::unique_ptr<FenceTime> gpuEndFenceTime;
+        std::optional<nsecs_t> gpuStartTime;
+        std::optional<nsecs_t> lastValidGpuEndTime;
+        std::optional<nsecs_t> lastValidGpuStartTime;
+        std::optional<nsecs_t> hwcPresentStartTime;
+        std::optional<nsecs_t> hwcPresentEndTime;
+        std::optional<nsecs_t> hwcValidateStartTime;
+        std::optional<nsecs_t> hwcValidateEndTime;
+        std::optional<nsecs_t> hwcPresentDelayedTime;
+        bool usedClientComposition = false;
+        bool skippedValidate = false;
+        // Calculate high-level timing milestones from more granular display timing data
+        DisplayTimeline calculateDisplayTimeline(nsecs_t fenceTime);
+        // Estimate the gpu duration for a given display from previous gpu timing data
+        std::optional<GpuTimeline> estimateGpuTiming(std::optional<nsecs_t> previousEnd);
+    };
+
+    template <class T, size_t N>
+    class RingBuffer {
+        std::array<T, N> elements = {};
+        size_t mIndex = 0;
+        size_t numElements = 0;
+
+    public:
+        void append(T item) {
+            mIndex = (mIndex + 1) % N;
+            numElements = std::min(N, numElements + 1);
+            elements[mIndex] = item;
+        }
+        bool isFull() const { return numElements == N; }
+        // Allows access like [0] == current, [-1] = previous, etc..
+        T& operator[](int offset) {
+            size_t positiveOffset =
+                    static_cast<size_t>((offset % static_cast<int>(N)) + static_cast<int>(N));
+            return elements[(mIndex + positiveOffset) % N];
+        }
+    };
+
+    // Filter and sort the display ids by a given property
+    std::vector<DisplayId> getOrderedDisplayIds(std::optional<nsecs_t> DisplayTimingData::*sortBy);
+    // Estimates a frame's total work duration including gpu time.
+    // Runs either at the beginning or end of a frame, using the most recent data available
+    std::optional<nsecs_t> estimateWorkDuration(bool earlyHint);
+    // There are two different targets and actual work durations we care about,
+    // this normalizes them together and takes the max of the two
+    nsecs_t combineTimingEstimates(nsecs_t totalDuration, nsecs_t flingerDuration);
+
+    std::unordered_map<DisplayId, DisplayTimingData> mDisplayTimingData;
+
+    // Current frame's delay
+    nsecs_t mFrameDelayDuration = 0;
+    // Last frame's composite end time
+    nsecs_t mLastCompositeEndTime = -1;
+    // 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;
+    // Target for the entire pipeline including gpu
+    std::optional<nsecs_t> mTotalFrameTargetDuration;
+    // Updated list of display IDs
+    std::vector<DisplayId> mDisplayIds;
+
+    std::optional<bool> mPowerHintEnabled;
+    std::optional<bool> mSupportsPowerHint;
+    bool mPowerHintSessionRunning = false;
+
+    // An adjustable safety margin which pads the "actual" value sent to PowerHAL,
+    // encouraging more aggressive boosting to give SurfaceFlinger a larger margin for error
+    static constexpr const std::chrono::nanoseconds kTargetSafetyMargin = 1ms;
+
+    // How long we expect hwc to run after the present call until it waits for the fence
+    static constexpr const std::chrono::nanoseconds kFenceWaitStartDelayValidated = 150us;
+    static constexpr const std::chrono::nanoseconds kFenceWaitStartDelaySkippedValidate = 250us;
 };
 
 class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
@@ -133,50 +287,50 @@
     void restartPowerHintSession() override;
     void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override;
     bool startPowerHintSession() override;
-    void setTargetWorkDuration(int64_t targetDurationNanos) override;
-    void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override;
+    void setTargetWorkDuration(nsecs_t targetDuration) override;
+    void sendActualWorkDuration(nsecs_t actualDuration, nsecs_t timestamp) override;
     bool shouldReconnectHAL() override;
     std::vector<int32_t> getPowerHintSessionThreadIds() override;
-    std::optional<int64_t> getTargetWorkDuration() override;
+    std::optional<nsecs_t> getTargetWorkDuration() override;
 
 private:
+    friend class AidlPowerHalWrapperTest;
+
     bool checkPowerHintSessionSupported();
     void closePowerHintSession();
-    bool shouldReportActualDurationsNow();
-    bool shouldSetTargetDuration(int64_t targetDurationNanos);
+    bool shouldReportActualDurations();
+
+    // Used for testing
+    void setAllowedActualDeviation(nsecs_t);
 
     const sp<hardware::power::IPower> mPowerHal = nullptr;
     bool mHasExpensiveRendering = false;
     bool mHasDisplayUpdateImminent = false;
     // Used to indicate an error state and need for reconstruction
     bool mShouldReconnectHal = false;
-    // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
+
+    // Power hint session data
+
+    // Concurrent access for this is protected by mPowerHalMutex
     sp<hardware::power::IPowerHintSession> mPowerHintSession = nullptr;
     // Queue of actual durations saved to report
     std::vector<hardware::power::WorkDuration> mPowerHintQueue;
-    // The latest un-normalized values we have received for target and actual
-    int64_t mTargetDuration = kDefaultTarget.count();
-    std::optional<int64_t> mActualDuration;
+    // The latest values we have received for target and actual
+    nsecs_t mTargetDuration = kDefaultTarget.count();
+    std::optional<nsecs_t> mActualDuration;
     // The list of thread ids, stored so we can restart the session from this class if needed
     std::vector<int32_t> mPowerHintThreadIds;
-    bool mSupportsPowerHint;
+    bool mSupportsPowerHint = false;
     // Keep track of the last messages sent for rate limiter change detection
-    std::optional<int64_t> mLastActualDurationSent;
-    // timestamp of the last report we sent, used to avoid stale sessions
-    int64_t mLastActualReportTimestamp = 0;
-    int64_t mLastTargetDurationSent = kDefaultTarget.count();
-    // Whether to normalize all the actual values as error terms relative to a constant target
-    // This saves a binder call by not setting the target, and should not affect the pid values
-    static const bool sNormalizeTarget;
+    std::optional<nsecs_t> mLastActualDurationSent;
+    // Timestamp of the last report we sent, used to avoid stale sessions
+    nsecs_t mLastActualReportTimestamp = 0;
+    nsecs_t mLastTargetDurationSent = kDefaultTarget.count();
+    // Max amount the error term can vary without causing an actual value report
+    nsecs_t mAllowedActualDeviation = -1;
     // Whether we should emit ATRACE_INT data for hint sessions
     static const bool sTraceHintSessionData;
-
-    // Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
-    static constexpr double kAllowedActualDeviationPercent = 0.1;
-    // Max percent the target duration can vary without causing a report (eg: 0.1 = 10%)
-    static constexpr double kAllowedTargetDeviationPercent = 0.1;
-    // Target used for init and normalization, the actual value does not really matter
-    static constexpr const std::chrono::nanoseconds kDefaultTarget = 50ms;
+    static constexpr const std::chrono::nanoseconds kDefaultTarget = 16ms;
     // Amount of time after the last message was sent before the session goes stale
     // actually 100ms but we use 80 here to ideally avoid going stale
     static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
diff --git a/services/surfaceflinger/FpsReporter.cpp b/services/surfaceflinger/FpsReporter.cpp
index e12835f..c89c9ff 100644
--- a/services/surfaceflinger/FpsReporter.cpp
+++ b/services/surfaceflinger/FpsReporter.cpp
@@ -56,8 +56,8 @@
 
     mFlinger.mCurrentState.traverse([&](Layer* layer) {
         auto& currentState = layer->getDrawingState();
-        if (currentState.metadata.has(METADATA_TASK_ID)) {
-            int32_t taskId = currentState.metadata.getInt32(METADATA_TASK_ID, 0);
+        if (currentState.metadata.has(gui::METADATA_TASK_ID)) {
+            int32_t taskId = currentState.metadata.getInt32(gui::METADATA_TASK_ID, 0);
             if (seenTasks.count(taskId) == 0) {
                 // localListeners is expected to be tiny
                 for (TrackedListener& listener : localListeners) {
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 66beff2..3e69b5c 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -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;
 }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index be16942..6e9dad1 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -86,6 +86,8 @@
 using namespace ftl::flag_operators;
 
 using base::StringAppendF;
+using gui::GameMode;
+using gui::LayerMetadata;
 using gui::WindowInfo;
 
 using PresentState = frametimeline::SurfaceFrame::PresentState;
@@ -97,8 +99,10 @@
         mFlinger(args.flinger),
         mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)),
         mClientRef(args.client),
-        mWindowType(static_cast<WindowInfo::Type>(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))),
-        mLayerCreationFlags(args.flags) {
+        mWindowType(static_cast<WindowInfo::Type>(
+                args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))),
+        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;
@@ -144,6 +148,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.
@@ -160,8 +165,8 @@
 
     if (mCallingUid == AID_GRAPHICS || mCallingUid == AID_SYSTEM) {
         // If the system didn't send an ownerUid, use the callingUid for the ownerUid.
-        mOwnerUid = args.metadata.getInt32(METADATA_OWNER_UID, mCallingUid);
-        mOwnerPid = args.metadata.getInt32(METADATA_OWNER_PID, mCallingPid);
+        mOwnerUid = args.metadata.getInt32(gui::METADATA_OWNER_UID, mCallingUid);
+        mOwnerPid = args.metadata.getInt32(gui::METADATA_OWNER_PID, mCallingPid);
     } else {
         // A create layer request from a non system request cannot specify the owner uid
         mOwnerUid = mCallingUid;
@@ -720,7 +725,7 @@
 
     if (s.sequence != mLastCommittedTxSequence) {
         // invalidate and recompute the visible regions if needed
-         mLastCommittedTxSequence = s.sequence;
+        mLastCommittedTxSequence = s.sequence;
         flags |= eVisibleRegion;
         this->contentDirty = true;
 
@@ -728,6 +733,10 @@
         mNeedsFiltering = getActiveTransform(s).needsBilinearFiltering();
     }
 
+    if (!mPotentialCursor && (flags & Layer::eVisibleRegion)) {
+        mFlinger->mUpdateInputInfo = true;
+    }
+
     commitTransaction(mDrawingState);
 
     return flags;
@@ -878,7 +887,7 @@
     if (mDrawingState.isTrustedOverlay == isTrustedOverlay) return false;
     mDrawingState.isTrustedOverlay = isTrustedOverlay;
     mDrawingState.modified = true;
-    mFlinger->mInputInfoChanged = true;
+    mFlinger->mUpdateInputInfo = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -975,6 +984,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);
 
@@ -1086,6 +1102,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;
 };
@@ -1150,6 +1179,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 = [&] {
@@ -1398,10 +1449,10 @@
 // ----------------------------------------------------------------------------
 
 // TODO(marissaw): add new layer state info to layer debugging
-LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const {
+gui::LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const {
     using namespace std::string_literals;
 
-    LayerDebugInfo info;
+    gui::LayerDebugInfo info;
     const State& ds = getDrawingState();
     info.mName = getName();
     sp<Layer> parent = mDrawingParent.promote();
@@ -1550,8 +1601,9 @@
 
 void Layer::setGameModeForTree(GameMode gameMode) {
     const auto& currentState = getDrawingState();
-    if (currentState.metadata.has(METADATA_GAME_MODE)) {
-        gameMode = static_cast<GameMode>(currentState.metadata.getInt32(METADATA_GAME_MODE, 0));
+    if (currentState.metadata.has(gui::METADATA_GAME_MODE)) {
+        gameMode =
+                static_cast<GameMode>(currentState.metadata.getInt32(gui::METADATA_GAME_MODE, 0));
     }
     setGameMode(gameMode);
     for (const sp<Layer>& child : mCurrentChildren) {
@@ -1586,8 +1638,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);
     }
 }
 
@@ -2024,7 +2078,7 @@
     mDrawingState.inputInfo = info;
     mDrawingState.touchableRegionCrop = fromHandle(info.touchableRegionCropHandle.promote());
     mDrawingState.modified = true;
-    mFlinger->mInputInfoChanged = true;
+    mFlinger->mUpdateInputInfo = true;
     setTransactionFlags(eTransactionNeeded);
 }
 
@@ -2423,7 +2477,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.isClone = true;
+        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);
@@ -2603,6 +2657,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:
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 24abad9..fb9b663 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -17,8 +17,8 @@
 #pragma once
 
 #include <android/gui/DropInputMode.h>
+#include <android/gui/ISurfaceComposerClient.h>
 #include <gui/BufferQueue.h>
-#include <gui/ISurfaceComposerClient.h>
 #include <gui/LayerState.h>
 #include <gui/WindowInfo.h>
 #include <layerproto/LayerProtoHeader.h>
@@ -69,13 +69,16 @@
 class DisplayDevice;
 class GraphicBuffer;
 class SurfaceFlinger;
-class LayerDebugInfo;
 
 namespace compositionengine {
 class OutputLayer;
 struct LayerFECompositionState;
 }
 
+namespace gui {
+class LayerDebugInfo;
+}
+
 namespace impl {
 class SurfaceInterceptor;
 }
@@ -232,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
@@ -435,6 +441,7 @@
     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 */) {}
@@ -443,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;
@@ -735,7 +745,7 @@
     inline const State& getDrawingState() const { return mDrawingState; }
     inline State& getDrawingState() { return mDrawingState; }
 
-    LayerDebugInfo getLayerDebugInfo(const DisplayDevice*) const;
+    gui::LayerDebugInfo getLayerDebugInfo(const DisplayDevice*) const;
 
     void miniDump(std::string& result, const DisplayDevice&) const;
     void dumpFrameStats(std::string& result) const;
@@ -885,6 +895,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; }
@@ -1126,7 +1140,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/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 639ba5a..d152ab2 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),
@@ -288,8 +288,7 @@
 }
 
 sp<EventThreadConnection> EventThread::createEventConnection(
-        ResyncCallback resyncCallback,
-        ISurfaceComposer::EventRegistrationFlags eventRegistration) const {
+        ResyncCallback resyncCallback, EventRegistrationFlags eventRegistration) const {
     return new EventThreadConnection(const_cast<EventThread*>(this),
                                      IPCThreadState::self()->getCallingUid(),
                                      std::move(resyncCallback), eventRegistration);
@@ -553,7 +552,7 @@
 
         case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: {
             return connection->mEventRegistration.test(
-                    ISurfaceComposer::EventRegistration::modeChanged);
+                    gui::ISurfaceComposer::EventRegistration::modeChanged);
         }
 
         case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
@@ -586,7 +585,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 adb96fd..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,7 +107,7 @@
 
     VSyncRequest vsyncRequest = VSyncRequest::None;
     const uid_t mOwnerUid;
-    const ISurfaceComposer::EventRegistrationFlags mEventRegistration;
+    const EventRegistrationFlags mEventRegistration;
 
 private:
     virtual void onFirstRef();
@@ -123,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;
@@ -171,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/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 37f0fec..3181a7f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -25,6 +25,7 @@
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
+#include <ftl/fake_guard.h>
 #include <gui/WindowInfo.h>
 #include <system/window.h>
 #include <ui/DisplayStatInfo.h>
@@ -94,9 +95,13 @@
 }
 
 void Scheduler::setRefreshRateConfigs(std::shared_ptr<RefreshRateConfigs> configs) {
+    // The current RefreshRateConfigs instance may outlive this call, so unbind its idle timer.
     {
-        // The current RefreshRateConfigs instance may outlive this call, so unbind its idle timer.
-        std::scoped_lock lock(mRefreshRateConfigsLock);
+        // mRefreshRateConfigsLock is not locked here to avoid the deadlock
+        // as the callback can attempt to acquire the lock before stopIdleTimer can finish
+        // the execution. It's safe to FakeGuard as main thread is the only thread that
+        // writes to the mRefreshRateConfigs.
+        ftl::FakeGuard guard(mRefreshRateConfigsLock);
         if (mRefreshRateConfigs) {
             mRefreshRateConfigs->stopIdleTimer();
             mRefreshRateConfigs->clearIdleTimerCallbacks();
@@ -209,12 +214,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);
@@ -492,24 +497,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) {
@@ -530,6 +521,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;
@@ -554,11 +550,12 @@
     }
 }
 
-void Scheduler::setDisplayPowerState(bool normal) {
+void Scheduler::setDisplayPowerMode(hal::PowerMode powerMode) {
     {
         std::lock_guard<std::mutex> lock(mPolicyLock);
-        mPolicy.isDisplayPowerStateNormal = normal;
+        mPolicy.displayPowerMode = powerMode;
     }
+    mVsyncSchedule->getController().setDisplayPowerMode(powerMode);
 
     if (mDisplayPowerTimer) {
         mDisplayPowerTimer->reset();
@@ -706,7 +703,8 @@
     // If Display Power is not in normal operation we want to be in performance mode. When coming
     // back to normal mode, a grace period is given with DisplayPowerTimer.
     if (mDisplayPowerTimer &&
-        (!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) {
+        (mPolicy.displayPowerMode != hal::PowerMode::ON ||
+         mPolicy.displayPowerTimer == TimerState::Reset)) {
         constexpr GlobalSignals kNoSignals;
         return {configs->getMaxRefreshRateByPolicy(), kNoSignals};
     }
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 0c72124..7f76d1e 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -32,6 +32,8 @@
 #include <ui/GraphicTypes.h>
 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
 
+#include <ui/DisplayStatInfo.h>
+
 #include <scheduler/Features.h>
 
 #include "EventThread.h"
@@ -131,7 +133,7 @@
                                       impl::EventThread::InterceptVSyncsCallback);
 
     sp<IDisplayEventConnection> createDisplayEventConnection(
-            ConnectionHandle, ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
+            ConnectionHandle, EventRegistrationFlags eventRegistration = {});
 
     sp<EventThreadConnection> getEventConnection(ConnectionHandle);
 
@@ -176,6 +178,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,7 +189,7 @@
     // Indicates that touch interaction is taking place.
     void onTouchHint();
 
-    void setDisplayPowerState(bool normal);
+    void setDisplayPowerMode(hal::PowerMode powerMode);
 
     VSyncDispatch& getVsyncDispatch() { return mVsyncSchedule->getDispatch(); }
 
@@ -248,7 +251,7 @@
     // 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 +328,7 @@
         TimerState idleTimer = TimerState::Reset;
         TouchState touch = TouchState::Inactive;
         TimerState displayPowerTimer = TimerState::Expired;
-        bool isDisplayPowerStateNormal = true;
+        hal::PowerMode displayPowerMode = hal::PowerMode::ON;
 
         // Chosen display mode.
         DisplayModePtr mode;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6a17cd8..ab5bb77 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -30,6 +30,7 @@
 #include <android-base/strings.h>
 #include <android/configuration.h>
 #include <android/gui/IDisplayEventConnection.h>
+#include <android/gui/StaticDisplayInfo.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
 #include <android/hardware/configstore/1.1/types.h>
@@ -55,6 +56,7 @@
 #include <ftl/fake_guard.h>
 #include <ftl/future.h>
 #include <ftl/small_map.h>
+#include <gui/AidlStatusUtil.h>
 #include <gui/BufferQueue.h>
 #include <gui/DebugEGLImageTracker.h>
 #include <gui/IProducerListener.h>
@@ -104,7 +106,6 @@
 #include <ui/DisplayIdentification.h>
 #include "BackgroundExecutor.h"
 #include "BufferLayer.h"
-#include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
 #include "Client.h"
 #include "Colorizer.h"
@@ -154,6 +155,10 @@
 #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::string_literals;
@@ -170,9 +175,12 @@
 
 using base::StringAppendF;
 using gui::DisplayInfo;
+using gui::GameMode;
 using gui::IDisplayEventConnection;
 using gui::IWindowInfosListener;
+using gui::LayerMetadata;
 using gui::WindowInfo;
+using gui::aidl_utils::binderStatusFromStatusT;
 using ui::ColorMode;
 using ui::Dataspace;
 using ui::DisplayPrimaries;
@@ -273,6 +281,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;
@@ -331,7 +341,7 @@
         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());
 }
 
@@ -402,7 +412,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 =
@@ -444,6 +454,11 @@
     }
 
     mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false);
+
+    // Power hint session mode, representing which hint(s) to send: early, late, or both)
+    mPowerHintSessionMode =
+            {.late = base::GetBoolProperty("debug.sf.send_late_power_session_hint"s, true),
+             .early = base::GetBoolProperty("debug.sf.send_early_power_session_hint"s, true)};
 }
 
 LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
@@ -478,11 +493,6 @@
     mScheduler->run();
 }
 
-sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
-    const sp<Client> client = new Client(this);
-    return client->initCheck() == NO_ERROR ? client : nullptr;
-}
-
 sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, bool secure) {
     // onTransact already checks for some permissions, but adding an additional check here.
     // This is to ensure that only system and graphics can request to create a secure
@@ -876,17 +886,6 @@
 
 // ----------------------------------------------------------------------------
 
-bool SurfaceFlinger::authenticateSurfaceTexture(
-        const sp<IGraphicBufferProducer>& bufferProducer) const {
-    Mutex::Autolock _l(mStateLock);
-    return authenticateSurfaceTextureLocked(bufferProducer);
-}
-
-bool SurfaceFlinger::authenticateSurfaceTextureLocked(
-        const sp<IGraphicBufferProducer>& /* bufferProducer */) const {
-    return false;
-}
-
 status_t SurfaceFlinger::getSupportedFrameTimestamps(
         std::vector<FrameEvent>* outSupported) const {
     *outSupported = {
@@ -1578,7 +1577,7 @@
             : BAD_VALUE;
 }
 
-status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) {
+status_t SurfaceFlinger::getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) {
     outLayers->clear();
     auto future = mScheduler->schedule([=] {
         const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
@@ -1810,10 +1809,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);
 }
@@ -1991,12 +1991,6 @@
 
 bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
         FTL_FAKE_GUARD(kMainThreadContext) {
-    // we set this once at the beginning of commit to ensure consistency throughout the whole frame
-    mPowerHintSessionData.sessionEnabled = mPowerAdvisor->usePowerHintSession();
-    if (mPowerHintSessionData.sessionEnabled) {
-        mPowerHintSessionData.commitStart = systemTime();
-    }
-
     // calculate the expected present time once and use the cached
     // value throughout this frame to make sure all layers are
     // seeing this same value.
@@ -2010,10 +2004,6 @@
     const nsecs_t lastScheduledPresentTime = mScheduledPresentTime;
     mScheduledPresentTime = expectedVsyncTime;
 
-    if (mPowerHintSessionData.sessionEnabled) {
-        mPowerAdvisor->setTargetWorkDuration(mExpectedPresentTime -
-                                             mPowerHintSessionData.commitStart);
-    }
     const auto vsyncIn = [&] {
         if (!ATRACE_ENABLED()) return 0.f;
         return (mExpectedPresentTime - systemTime()) / 1e6f;
@@ -2065,6 +2055,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) {
@@ -2089,9 +2084,28 @@
         }
     }
 
-    if (mTracingEnabledChanged) {
-        mLayerTracingEnabled = mLayerTracing.isEnabled();
-        mTracingEnabledChanged = false;
+    // Save this once per commit + composite to ensure consistency
+    mPowerHintSessionEnabled = mPowerAdvisor->usePowerHintSession();
+    if (mPowerHintSessionEnabled) {
+        nsecs_t vsyncPeriod;
+        {
+            Mutex::Autolock lock(mStateLock);
+            vsyncPeriod = getVsyncPeriodFromHWC();
+        }
+        mPowerAdvisor->setCommitStart(frameTime);
+        mPowerAdvisor->setExpectedPresentTime(mExpectedPresentTime);
+        const nsecs_t idealSfWorkDuration =
+                mVsyncModulator->getVsyncConfig().sfWorkDuration.count();
+        // Frame delay is how long we should have minus how long we actually have
+        mPowerAdvisor->setFrameDelay(idealSfWorkDuration - (mExpectedPresentTime - frameTime));
+        mPowerAdvisor->setTotalFrameTargetWorkDuration(idealSfWorkDuration);
+        mPowerAdvisor->setTargetWorkDuration(vsyncPeriod);
+
+        // Send early hint here to make sure there's not another frame pending
+        if (mPowerHintSessionMode.early) {
+            // Send a rough prediction for this frame based on last frame's timing info
+            mPowerAdvisor->sendPredictedWorkDuration();
+        }
     }
 
     if (mRefreshRateOverlaySpinner) {
@@ -2108,7 +2122,7 @@
 
         bool needsTraversal = false;
         if (clearTransactionFlags(eTransactionFlushNeeded)) {
-            needsTraversal |= commitCreatedLayers();
+            needsTraversal |= commitCreatedLayers(vsyncId);
             needsTraversal |= flushTransactionQueues(vsyncId);
         }
 
@@ -2153,8 +2167,9 @@
 
     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, vsyncId);
     }
+    mLastCommittedVsyncId = vsyncId;
 
     persistDisplayBrightness(mustComposite);
 
@@ -2165,20 +2180,35 @@
         FTL_FAKE_GUARD(kMainThreadContext) {
     ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId);
 
-    if (mPowerHintSessionData.sessionEnabled) {
-        mPowerHintSessionData.compositeStart = systemTime();
-    }
-
     compositionengine::CompositionRefreshArgs refreshArgs;
     const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays);
     refreshArgs.outputs.reserve(displays.size());
+    std::vector<DisplayId> displayIds;
     for (const auto& [_, display] : displays) {
         refreshArgs.outputs.push_back(display->getCompositionDisplay());
+        displayIds.push_back(display->getId());
     }
+    mPowerAdvisor->setDisplays(displayIds);
     mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
         if (auto layerFE = layer->getCompositionEngineLayerFE())
             refreshArgs.layers.push_back(layerFE);
     });
+
+    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())
@@ -2222,12 +2252,16 @@
 
     mCompositionEngine->present(refreshArgs);
 
-    if (mPowerHintSessionData.sessionEnabled) {
-        mPowerHintSessionData.presentEnd = systemTime();
-    }
-
     mTimeStats->recordFrameDuration(frameTime, systemTime());
 
+    // Send a power hint hint after presentation is finished
+    if (mPowerHintSessionEnabled) {
+        mPowerAdvisor->setPresentFenceTime(mPreviousPresentFences[0].fenceTime->getSignalTime());
+        if (mPowerHintSessionMode.late) {
+            mPowerAdvisor->sendActualWorkDuration();
+        }
+    }
+
     if (mScheduler->onPostComposition(presentTime)) {
         scheduleComposite(FrameHint::kNone);
     }
@@ -2262,7 +2296,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, vsyncId);
     }
 
     mVisibleRegionsWereDirtyThisFrame = mVisibleRegionsDirty; // Cache value for use in post-comp
@@ -2272,11 +2306,8 @@
         scheduleCommit(FrameHint::kNone);
     }
 
-    // calculate total render time for performance hinting if adpf cpu hint is enabled,
-    if (mPowerHintSessionData.sessionEnabled) {
-        const nsecs_t flingerDuration =
-                (mPowerHintSessionData.presentEnd - mPowerHintSessionData.commitStart);
-        mPowerAdvisor->sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd);
+    if (mPowerHintSessionEnabled) {
+        mPowerAdvisor->setCompositeEnd(systemTime());
     }
 }
 
@@ -3084,6 +3115,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)
@@ -3128,6 +3160,7 @@
     if (mSomeChildrenChanged) {
         mVisibleRegionsDirty = true;
         mSomeChildrenChanged = false;
+        mUpdateInputInfo = true;
     }
 
     // Update transform hint.
@@ -3169,7 +3202,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.
 
@@ -3179,7 +3212,11 @@
                 hintDisplay = getDefaultDisplayDeviceLocked();
             }
 
-            layer->updateTransformHint(hintDisplay->getTransformHint());
+            if (hintDisplay) {
+                layer->updateTransformHint(hintDisplay->getTransformHint());
+            } else {
+                ALOGW("Ignoring transform hint update for %s", layer->getDebugName());
+            }
         });
     }
 
@@ -3187,6 +3224,7 @@
         mLayersAdded = false;
         // Layers have been added.
         mVisibleRegionsDirty = true;
+        mUpdateInputInfo = true;
     }
 
     // some layers might have been removed, so
@@ -3194,6 +3232,7 @@
     if (mLayersRemoved) {
         mLayersRemoved = false;
         mVisibleRegionsDirty = true;
+        mUpdateInputInfo = true;
         mDrawingState.traverseInZOrder([&](Layer* layer) {
             if (mLayersPendingRemoval.indexOf(layer) >= 0) {
                 // this layer is not visible anymore
@@ -3218,14 +3257,14 @@
     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().sendCallbacks({[updateWindowInfo,
                                                       windowInfos = std::move(windowInfos),
                                                       displayInfos = std::move(displayInfos),
@@ -3234,12 +3273,17 @@
                                                       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);
@@ -3619,9 +3663,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) {
@@ -4062,11 +4106,9 @@
     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);
@@ -4448,6 +4490,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,
@@ -4499,9 +4546,10 @@
     }
     std::optional<nsecs_t> dequeueBufferTimestamp;
     if (what & layer_state_t::eMetadataChanged) {
-        dequeueBufferTimestamp = s.metadata.getInt64(METADATA_DEQUEUE_TIME);
+        dequeueBufferTimestamp = s.metadata.getInt64(gui::METADATA_DEQUEUE_TIME);
 
-        if (const int32_t gameMode = s.metadata.getInt32(METADATA_GAME_MODE, -1); gameMode != -1) {
+        if (const int32_t gameMode = s.metadata.getInt32(gui::METADATA_GAME_MODE, -1);
+            gameMode != -1) {
             // The transaction will be received on the Task layer and needs to be applied to all
             // child layers. Child layers that are added at a later point will obtain the game mode
             // info through addChild().
@@ -4518,6 +4566,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;
@@ -4568,7 +4624,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
@@ -4717,42 +4773,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();
@@ -4911,6 +4931,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);
         }
@@ -4929,7 +4952,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());
@@ -5506,29 +5529,11 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic error "-Wswitch-enum"
     switch (static_cast<ISurfaceComposerTag>(code)) {
-        case ENABLE_VSYNC_INJECTIONS:
-        case INJECT_VSYNC:
-            if (!hasMockHwc()) return PERMISSION_DENIED;
-            [[fallthrough]];
         // These methods should at minimum make sure that the client requested
         // access to SF.
-        case BOOT_FINISHED:
-        case CLEAR_ANIMATION_FRAME_STATS:
-        case GET_ANIMATION_FRAME_STATS:
-        case OVERRIDE_HDR_TYPES:
         case GET_HDR_CAPABILITIES:
-        case SET_DESIRED_DISPLAY_MODE_SPECS:
-        case GET_DESIRED_DISPLAY_MODE_SPECS:
-        case SET_ACTIVE_COLOR_MODE:
-        case SET_BOOT_DISPLAY_MODE:
         case GET_AUTO_LOW_LATENCY_MODE_SUPPORT:
         case GET_GAME_CONTENT_TYPE_SUPPORT:
-        case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
-        case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
-        case GET_DISPLAYED_CONTENT_SAMPLE:
-        case ADD_TUNNEL_MODE_ENABLED_LISTENER:
-        case REMOVE_TUNNEL_MODE_ENABLED_LISTENER:
-        case SET_GLOBAL_SHADOW_SETTINGS:
         case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
             // OVERRIDE_HDR_TYPES is used by CTS tests, which acquire the necessary
             // permission dynamically. Don't use the permission cache for this check.
@@ -5541,100 +5546,38 @@
             }
             return OK;
         }
-        case GET_LAYER_DEBUG_INFO: {
-            IPCThreadState* ipc = IPCThreadState::self();
-            const int pid = ipc->getCallingPid();
-            const int uid = ipc->getCallingUid();
-            if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) {
-                ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
-                return PERMISSION_DENIED;
-            }
-            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.
-        case AUTHENTICATE_SURFACE:
         case GET_ACTIVE_COLOR_MODE:
         case GET_ACTIVE_DISPLAY_MODE:
         case GET_DISPLAY_COLOR_MODES:
-        case GET_DISPLAY_NATIVE_PRIMARIES:
-        case GET_STATIC_DISPLAY_INFO:
-        case GET_DYNAMIC_DISPLAY_INFO:
         case GET_DISPLAY_MODES:
-        case GET_SUPPORTED_FRAME_TIMESTAMPS:
         // Calling setTransactionState is safe, because you need to have been
         // granted a reference to Client* and Handle* to do anything with it.
-        case SET_TRANSACTION_STATE:
-        case CREATE_CONNECTION:
-        case GET_COLOR_MANAGEMENT:
-        case GET_COMPOSITION_PREFERENCE:
-        case GET_PROTECTED_CONTENT_SUPPORT:
-        // setFrameRate() is deliberately available for apps to call without any
-        // special permissions.
-        case SET_FRAME_RATE:
-        case GET_DISPLAY_DECORATION_SUPPORT:
-        case SET_FRAME_TIMELINE_INFO:
-        case GET_GPU_CONTEXT_PRIORITY:
-        case GET_MAX_ACQUIRED_BUFFER_COUNT: {
+        case SET_TRANSACTION_STATE: {
             // This is not sensitive information, so should not require permission control.
             return OK;
         }
-        case ADD_FPS_LISTENER:
-        case REMOVE_FPS_LISTENER:
-        case ADD_REGION_SAMPLING_LISTENER:
-        case REMOVE_REGION_SAMPLING_LISTENER: {
-            // codes that require permission check
-            IPCThreadState* ipc = IPCThreadState::self();
-            const int pid = ipc->getCallingPid();
-            const int uid = ipc->getCallingUid();
-            if ((uid != AID_GRAPHICS) &&
-                !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
-                ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid);
-                return PERMISSION_DENIED;
-            }
-            return OK;
-        }
-        case ADD_TRANSACTION_TRACE_LISTENER: {
-            IPCThreadState* ipc = IPCThreadState::self();
-            const int uid = ipc->getCallingUid();
-            if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) {
-                return OK;
-            }
-            return PERMISSION_DENIED;
-        }
-        case SET_OVERRIDE_FRAME_RATE: {
-            const int uid = IPCThreadState::self()->getCallingUid();
-            if (uid == AID_ROOT || uid == AID_SYSTEM) {
-                return OK;
-            }
-            return PERMISSION_DENIED;
-        }
-        case ON_PULL_ATOM: {
-            const int uid = IPCThreadState::self()->getCallingUid();
-            if (uid == AID_SYSTEM) {
-                return OK;
-            }
-            return PERMISSION_DENIED;
-        }
-        case ADD_WINDOW_INFOS_LISTENER:
-        case REMOVE_WINDOW_INFOS_LISTENER: {
-            const int uid = IPCThreadState::self()->getCallingUid();
-            if (uid == AID_SYSTEM || uid == AID_GRAPHICS) {
-                return OK;
-            }
-            return PERMISSION_DENIED;
-        }
+        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:
         case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
         case GET_PHYSICAL_DISPLAY_IDS:
         case GET_PHYSICAL_DISPLAY_TOKEN:
+        case AUTHENTICATE_SURFACE:
         case SET_POWER_MODE:
+        case GET_SUPPORTED_FRAME_TIMESTAMPS:
         case GET_DISPLAY_STATE:
         case GET_DISPLAY_STATS:
+        case GET_STATIC_DISPLAY_INFO:
+        case GET_DYNAMIC_DISPLAY_INFO:
+        case GET_DISPLAY_NATIVE_PRIMARIES:
+        case SET_ACTIVE_COLOR_MODE:
+        case SET_BOOT_DISPLAY_MODE:
         case CLEAR_BOOT_DISPLAY_MODE:
         case GET_BOOT_DISPLAY_MODE_SUPPORT:
         case SET_AUTO_LOW_LATENCY_MODE:
@@ -5642,12 +5585,43 @@
         case CAPTURE_LAYERS:
         case CAPTURE_DISPLAY:
         case CAPTURE_DISPLAY_BY_ID:
+        case CLEAR_ANIMATION_FRAME_STATS:
+        case GET_ANIMATION_FRAME_STATS:
+        case OVERRIDE_HDR_TYPES:
+        case ON_PULL_ATOM:
+        case ENABLE_VSYNC_INJECTIONS:
+        case INJECT_VSYNC:
+        case GET_LAYER_DEBUG_INFO:
+        case GET_COLOR_MANAGEMENT:
+        case GET_COMPOSITION_PREFERENCE:
+        case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
+        case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
+        case GET_DISPLAYED_CONTENT_SAMPLE:
+        case GET_PROTECTED_CONTENT_SUPPORT:
         case IS_WIDE_COLOR_DISPLAY:
+        case ADD_REGION_SAMPLING_LISTENER:
+        case REMOVE_REGION_SAMPLING_LISTENER:
+        case ADD_FPS_LISTENER:
+        case REMOVE_FPS_LISTENER:
+        case ADD_TUNNEL_MODE_ENABLED_LISTENER:
+        case REMOVE_TUNNEL_MODE_ENABLED_LISTENER:
+        case ADD_WINDOW_INFOS_LISTENER:
+        case REMOVE_WINDOW_INFOS_LISTENER:
+        case SET_DESIRED_DISPLAY_MODE_SPECS:
+        case GET_DESIRED_DISPLAY_MODE_SPECS:
         case GET_DISPLAY_BRIGHTNESS_SUPPORT:
         case SET_DISPLAY_BRIGHTNESS:
         case ADD_HDR_LAYER_INFO_LISTENER:
         case REMOVE_HDR_LAYER_INFO_LISTENER:
         case NOTIFY_POWER_BOOST:
+        case SET_GLOBAL_SHADOW_SETTINGS:
+        case GET_DISPLAY_DECORATION_SUPPORT:
+        case SET_FRAME_RATE:
+        case SET_OVERRIDE_FRAME_RATE:
+        case SET_FRAME_TIMELINE_INFO:
+        case ADD_TRANSACTION_TRACE_LISTENER:
+        case GET_GPU_CONTEXT_PRIORITY:
+        case GET_MAX_ACQUIRED_BUFFER_COUNT:
             LOG_FATAL("Deprecated opcode: %d, migrated to AIDL", code);
             return PERMISSION_DENIED;
     }
@@ -5859,7 +5833,8 @@
                                 (fixedStartingTime) ? fixedStartingTime : systemTime();
                         mScheduler
                                 ->schedule([&]() FTL_FAKE_GUARD(mStateLock) {
-                                    mLayerTracing.notify("start", startingTime);
+                                    mLayerTracing.notify(true /* visibleRegionDirty */,
+                                                         startingTime, mLastCommittedVsyncId);
                                 })
                                 .wait();
                     }
@@ -6842,11 +6817,6 @@
     return future;
 }
 
-void SurfaceFlinger::windowInfosReported() {
-    Mutex::Autolock _l(mStateLock);
-    signalSynchronousTransactions(CountDownLatch::eSyncInputWindows);
-}
-
 // ---------------------------------------------------------------------------
 
 void SurfaceFlinger::State::traverse(const LayerVector::Visitor& visitor) const {
@@ -6895,9 +6865,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;
     }
@@ -7081,45 +7049,12 @@
     // on the work to remove the table in that bug rather than adding more to
     // it.
     static const std::unordered_map<std::string, uint32_t> genericLayerMetadataKeyMap{
-            {"org.chromium.arc.V1_0.TaskId", METADATA_TASK_ID},
-            {"org.chromium.arc.V1_0.CursorInfo", METADATA_MOUSE_CURSOR},
+            {"org.chromium.arc.V1_0.TaskId", gui::METADATA_TASK_ID},
+            {"org.chromium.arc.V1_0.CursorInfo", gui::METADATA_MOUSE_CURSOR},
     };
     return genericLayerMetadataKeyMap;
 }
 
-status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
-                                      int8_t compatibility, int8_t changeFrameRateStrategy) {
-    if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy,
-                           "SurfaceFlinger::setFrameRate")) {
-        return BAD_VALUE;
-    }
-
-    static_cast<void>(mScheduler->schedule([=] {
-        Mutex::Autolock lock(mStateLock);
-        if (authenticateSurfaceTextureLocked(surface)) {
-            sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
-            if (layer == nullptr) {
-                ALOGE("Attempt to set frame rate on a layer that no longer exists");
-                return BAD_VALUE;
-            }
-            const auto strategy =
-                    Layer::FrameRate::convertChangeFrameRateStrategy(changeFrameRateStrategy);
-            if (layer->setFrameRate(
-                        Layer::FrameRate(Fps::fromValue(frameRate),
-                                         Layer::FrameRate::convertCompatibility(compatibility),
-                                         strategy))) {
-                setTransactionFlags(eTraversalNeeded);
-            }
-        } else {
-            ALOGE("Attempt to set frame rate on an unrecognized IGraphicBufferProducer");
-            return BAD_VALUE;
-        }
-        return NO_ERROR;
-    }));
-
-    return NO_ERROR;
-}
-
 status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) {
     PhysicalDisplayId displayId = [&]() {
         Mutex::Autolock lock(mStateLock);
@@ -7131,24 +7066,6 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface,
-                                              const FrameTimelineInfo& frameTimelineInfo) {
-    Mutex::Autolock lock(mStateLock);
-    if (!authenticateSurfaceTextureLocked(surface)) {
-        ALOGE("Attempt to set frame timeline info on an unrecognized IGraphicBufferProducer");
-        return BAD_VALUE;
-    }
-
-    sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
-    if (layer == nullptr) {
-        ALOGE("Attempt to set frame timeline info on a layer that no longer exists");
-        return BAD_VALUE;
-    }
-
-    layer->setFrameTimelineInfoForBuffer(frameTimelineInfo);
-    return NO_ERROR;
-}
-
 void SurfaceFlinger::enableRefreshRateOverlay(bool enable) {
     for (const auto& [ignored, display] : mDisplays) {
         if (display->isInternal()) {
@@ -7168,7 +7085,7 @@
     return NO_ERROR;
 }
 
-int SurfaceFlinger::getGPUContextPriority() {
+int SurfaceFlinger::getGpuContextPriority() {
     return getRenderEngine().getContextPriority();
 }
 
@@ -7214,7 +7131,7 @@
     return calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
 }
 
-void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state) {
+void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state, int64_t vsyncId) {
     sp<Layer> layer = state.layer.promote();
     if (!layer) {
         ALOGD("Layer was destroyed soon after creation %p", state.layer.unsafe_get());
@@ -7244,7 +7161,9 @@
     }
 
     layer->updateTransformHint(mActiveDisplayTransformHint);
-
+    if (mTransactionTracing) {
+        mTransactionTracing->onLayerAddedToDrawingState(layer->getSequence(), vsyncId);
+    }
     mInterceptor->saveSurfaceCreation(layer);
 }
 
@@ -7328,7 +7247,7 @@
     return buffer;
 }
 
-bool SurfaceFlinger::commitCreatedLayers() {
+bool SurfaceFlinger::commitCreatedLayers(int64_t vsyncId) {
     std::vector<LayerCreatedState> createdLayers;
     {
         std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
@@ -7341,7 +7260,7 @@
 
     Mutex::Autolock _l(mStateLock);
     for (const auto& createdLayer : createdLayers) {
-        handleLayerCreatedLocked(createdLayer);
+        handleLayerCreatedLocked(createdLayer, vsyncId);
     }
     createdLayers.clear();
     mLayersAdded = true;
@@ -7350,24 +7269,58 @@
 
 // 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);
+    if (client->initCheck() == NO_ERROR) {
+        *outClient = client;
+        return binder::Status::ok();
+    } else {
+        *outClient = nullptr;
+        return binderStatusFromStatusT(BAD_VALUE);
+    }
+}
+
 binder::Status SurfaceComposerAIDL::createDisplay(const std::string& displayName, bool secure,
                                                   sp<IBinder>* outDisplay) {
     status_t status = checkAccessPermission();
-    if (status == OK) {
-        String8 displayName8 = String8::format("%s", displayName.c_str());
-        *outDisplay = mFlinger->createDisplay(displayName8, secure);
-        return binder::Status::ok();
+    if (status != OK) {
+        return binderStatusFromStatusT(status);
     }
-    return binder::Status::fromStatusT(status);
+    String8 displayName8 = String8::format("%s", displayName.c_str());
+    *outDisplay = mFlinger->createDisplay(displayName8, secure);
+    return binder::Status::ok();
 }
 
 binder::Status SurfaceComposerAIDL::destroyDisplay(const sp<IBinder>& display) {
     status_t status = checkAccessPermission();
-    if (status == OK) {
-        mFlinger->destroyDisplay(display);
-        return binder::Status::ok();
+    if (status != OK) {
+        return binderStatusFromStatusT(status);
     }
-    return binder::Status::fromStatusT(status);
+    mFlinger->destroyDisplay(display);
+    return binder::Status::ok();
 }
 
 binder::Status SurfaceComposerAIDL::getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) {
@@ -7384,7 +7337,7 @@
 binder::Status SurfaceComposerAIDL::getPrimaryPhysicalDisplayId(int64_t* outDisplayId) {
     status_t status = checkAccessPermission();
     if (status != OK) {
-        return binder::Status::fromStatusT(status);
+        return binderStatusFromStatusT(status);
     }
 
     PhysicalDisplayId id;
@@ -7392,7 +7345,7 @@
     if (status == NO_ERROR) {
         *outDisplayId = id.value;
     }
-    return binder::Status::fromStatusT(status);
+    return binderStatusFromStatusT(status);
 }
 
 binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId,
@@ -7404,12 +7357,25 @@
 
 binder::Status SurfaceComposerAIDL::setPowerMode(const sp<IBinder>& display, int mode) {
     status_t status = checkAccessPermission();
-    if (status != OK) return binder::Status::fromStatusT(status);
-
+    if (status != OK) {
+        return binderStatusFromStatusT(status);
+    }
     mFlinger->setPowerMode(display, mode);
     return binder::Status::ok();
 }
 
+binder::Status SurfaceComposerAIDL::getSupportedFrameTimestamps(
+        std::vector<FrameEvent>* outSupported) {
+    status_t status;
+    if (!outSupported) {
+        status = UNEXPECTED_NULL;
+    } else {
+        outSupported->clear();
+        status = mFlinger->getSupportedFrameTimestamps(outSupported);
+    }
+    return binderStatusFromStatusT(status);
+}
+
 binder::Status SurfaceComposerAIDL::getDisplayStats(const sp<IBinder>& display,
                                                     gui::DisplayStatInfo* outStatInfo) {
     DisplayStatInfo statInfo;
@@ -7418,7 +7384,7 @@
         outStatInfo->vsyncTime = static_cast<long>(statInfo.vsyncTime);
         outStatInfo->vsyncPeriod = static_cast<long>(statInfo.vsyncPeriod);
     }
-    return binder::Status::fromStatusT(status);
+    return binderStatusFromStatusT(status);
 }
 
 binder::Status SurfaceComposerAIDL::getDisplayState(const sp<IBinder>& display,
@@ -7431,37 +7397,175 @@
         outState->layerStackSpaceRect.width = state.layerStackSpaceRect.width;
         outState->layerStackSpaceRect.height = state.layerStackSpaceRect.height;
     }
-    return binder::Status::fromStatusT(status);
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getStaticDisplayInfo(const sp<IBinder>& display,
+                                                         gui::StaticDisplayInfo* outInfo) {
+    using Tag = gui::DeviceProductInfo::ManufactureOrModelDate::Tag;
+    ui::StaticDisplayInfo info;
+    status_t status = mFlinger->getStaticDisplayInfo(display, &info);
+    if (status == NO_ERROR) {
+        // convert ui::StaticDisplayInfo to gui::StaticDisplayInfo
+        outInfo->connectionType = static_cast<gui::DisplayConnectionType>(info.connectionType);
+        outInfo->density = info.density;
+        outInfo->secure = info.secure;
+        outInfo->installOrientation = static_cast<gui::Rotation>(info.installOrientation);
+
+        gui::DeviceProductInfo dinfo;
+        std::optional<DeviceProductInfo> dpi = info.deviceProductInfo;
+        dinfo.name = std::move(dpi->name);
+        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;
+            modelYear.year = model->year;
+            dinfo.manufactureOrModelDate.set<Tag::modelYear>(modelYear);
+        } else if (const auto* manufacture = std::get_if<DeviceProductInfo::ManufactureYear>(
+                           &dpi->manufactureOrModelDate)) {
+            gui::DeviceProductInfo::ManufactureYear date;
+            date.modelYear.year = manufacture->year;
+            dinfo.manufactureOrModelDate.set<Tag::manufactureYear>(date);
+        } else if (const auto* manufacture = std::get_if<DeviceProductInfo::ManufactureWeekAndYear>(
+                           &dpi->manufactureOrModelDate)) {
+            gui::DeviceProductInfo::ManufactureWeekAndYear date;
+            date.manufactureYear.modelYear.year = manufacture->year;
+            date.week = manufacture->week;
+            dinfo.manufactureOrModelDate.set<Tag::manufactureWeekAndYear>(date);
+        }
+
+        outInfo->deviceProductInfo = dinfo;
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDynamicDisplayInfo(const sp<IBinder>& display,
+                                                          gui::DynamicDisplayInfo* outInfo) {
+    ui::DynamicDisplayInfo info;
+    status_t status = mFlinger->getDynamicDisplayInfo(display, &info);
+    if (status == NO_ERROR) {
+        // convert ui::DynamicDisplayInfo to gui::DynamicDisplayInfo
+        outInfo->supportedDisplayModes.clear();
+        outInfo->supportedDisplayModes.reserve(info.supportedDisplayModes.size());
+        for (const auto& mode : info.supportedDisplayModes) {
+            gui::DisplayMode outMode;
+            outMode.id = mode.id;
+            outMode.resolution.width = mode.resolution.width;
+            outMode.resolution.height = mode.resolution.height;
+            outMode.xDpi = mode.xDpi;
+            outMode.yDpi = mode.yDpi;
+            outMode.refreshRate = mode.refreshRate;
+            outMode.appVsyncOffset = mode.appVsyncOffset;
+            outMode.sfVsyncOffset = mode.sfVsyncOffset;
+            outMode.presentationDeadline = mode.presentationDeadline;
+            outMode.group = mode.group;
+            outInfo->supportedDisplayModes.push_back(outMode);
+        }
+
+        outInfo->activeDisplayModeId = info.activeDisplayModeId;
+
+        outInfo->supportedColorModes.clear();
+        outInfo->supportedColorModes.reserve(info.supportedColorModes.size());
+        for (const auto& cmode : info.supportedColorModes) {
+            outInfo->supportedColorModes.push_back(static_cast<int32_t>(cmode));
+        }
+
+        outInfo->activeColorMode = static_cast<int32_t>(info.activeColorMode);
+
+        gui::HdrCapabilities& hdrCapabilities = outInfo->hdrCapabilities;
+        hdrCapabilities.supportedHdrTypes.clear();
+        hdrCapabilities.supportedHdrTypes.reserve(
+                info.hdrCapabilities.getSupportedHdrTypes().size());
+        for (const auto& hdr : info.hdrCapabilities.getSupportedHdrTypes()) {
+            hdrCapabilities.supportedHdrTypes.push_back(static_cast<int32_t>(hdr));
+        }
+        hdrCapabilities.maxLuminance = info.hdrCapabilities.getDesiredMaxLuminance();
+        hdrCapabilities.maxAverageLuminance = info.hdrCapabilities.getDesiredMaxAverageLuminance();
+        hdrCapabilities.minLuminance = info.hdrCapabilities.getDesiredMinLuminance();
+
+        outInfo->autoLowLatencyModeSupported = info.autoLowLatencyModeSupported;
+        outInfo->gameContentTypeSupported = info.gameContentTypeSupported;
+        outInfo->preferredBootDisplayMode = info.preferredBootDisplayMode;
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayNativePrimaries(const sp<IBinder>& display,
+                                                              gui::DisplayPrimaries* outPrimaries) {
+    ui::DisplayPrimaries primaries;
+    status_t status = mFlinger->getDisplayNativePrimaries(display, primaries);
+    if (status == NO_ERROR) {
+        outPrimaries->red.X = primaries.red.X;
+        outPrimaries->red.Y = primaries.red.Y;
+        outPrimaries->red.Z = primaries.red.Z;
+
+        outPrimaries->green.X = primaries.green.X;
+        outPrimaries->green.Y = primaries.green.Y;
+        outPrimaries->green.Z = primaries.green.Z;
+
+        outPrimaries->blue.X = primaries.blue.X;
+        outPrimaries->blue.Y = primaries.blue.Y;
+        outPrimaries->blue.Z = primaries.blue.Z;
+
+        outPrimaries->white.X = primaries.white.X;
+        outPrimaries->white.Y = primaries.white.Y;
+        outPrimaries->white.Z = primaries.white.Z;
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setActiveColorMode(const sp<IBinder>& display, int colorMode) {
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->setActiveColorMode(display, static_cast<ui::ColorMode>(colorMode));
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setBootDisplayMode(const sp<IBinder>& display,
+                                                       int displayModeId) {
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->setBootDisplayMode(display,
+                                              static_cast<ui::DisplayModeId>(displayModeId));
+    }
+    return binderStatusFromStatusT(status);
 }
 
 binder::Status SurfaceComposerAIDL::clearBootDisplayMode(const sp<IBinder>& display) {
     status_t status = checkAccessPermission();
-    if (status != OK) return binder::Status::fromStatusT(status);
-
-    status = mFlinger->clearBootDisplayMode(display);
-    return binder::Status::fromStatusT(status);
+    if (status == OK) {
+        status = mFlinger->clearBootDisplayMode(display);
+    }
+    return binderStatusFromStatusT(status);
 }
 
 binder::Status SurfaceComposerAIDL::getBootDisplayModeSupport(bool* outMode) {
     status_t status = checkAccessPermission();
-    if (status != OK) return binder::Status::fromStatusT(status);
-
-    status = mFlinger->getBootDisplayModeSupport(outMode);
-    return binder::Status::fromStatusT(status);
+    if (status == OK) {
+        status = mFlinger->getBootDisplayModeSupport(outMode);
+    }
+    return binderStatusFromStatusT(status);
 }
 
 binder::Status SurfaceComposerAIDL::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
     status_t status = checkAccessPermission();
-    if (status != OK) return binder::Status::fromStatusT(status);
-
+    if (status != OK) {
+        return binderStatusFromStatusT(status);
+    }
     mFlinger->setAutoLowLatencyMode(display, on);
     return binder::Status::ok();
 }
 
 binder::Status SurfaceComposerAIDL::setGameContentType(const sp<IBinder>& display, bool on) {
     status_t status = checkAccessPermission();
-    if (status != OK) return binder::Status::fromStatusT(status);
-
+    if (status != OK) {
+        return binderStatusFromStatusT(status);
+    }
     mFlinger->setGameContentType(display, on);
     return binder::Status::ok();
 }
@@ -7469,7 +7573,7 @@
 binder::Status SurfaceComposerAIDL::captureDisplay(
         const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
     status_t status = mFlinger->captureDisplay(args, captureListener);
-    return binder::Status::fromStatusT(status);
+    return binderStatusFromStatusT(status);
 }
 
 binder::Status SurfaceComposerAIDL::captureDisplayById(
@@ -7483,60 +7587,465 @@
     } else {
         status = PERMISSION_DENIED;
     }
-    return binder::Status::fromStatusT(status);
+    return binderStatusFromStatusT(status);
 }
 
 binder::Status SurfaceComposerAIDL::captureLayers(
         const LayerCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
     status_t status = mFlinger->captureLayers(args, captureListener);
-    return binder::Status::fromStatusT(status);
+    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
+    // permission dynamically. Don't use the permission cache for this check.
+    status_t status = checkAccessPermission(false);
+    if (status != OK) {
+        return binderStatusFromStatusT(status);
+    }
+
+    std::vector<ui::Hdr> hdrTypesVector;
+    for (int32_t i : hdrTypes) {
+        hdrTypesVector.push_back(static_cast<ui::Hdr>(i));
+    }
+    status = mFlinger->overrideHdrTypes(display, hdrTypesVector);
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::onPullAtom(int32_t atomId, gui::PullAtomData* outPullData) {
+    status_t status;
+    const int uid = IPCThreadState::self()->getCallingUid();
+    if (uid != AID_SYSTEM) {
+        status = PERMISSION_DENIED;
+    } else {
+        status = mFlinger->onPullAtom(atomId, &outPullData->data, &outPullData->success);
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::enableVSyncInjections(bool enable) {
+    if (!mFlinger->hasMockHwc()) {
+        return binderStatusFromStatusT(PERMISSION_DENIED);
+    }
+
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->enableVSyncInjections(enable);
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::injectVSync(int64_t when) {
+    if (!mFlinger->hasMockHwc()) {
+        return binderStatusFromStatusT(PERMISSION_DENIED);
+    }
+
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->injectVSync(when);
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) {
+    if (!outLayers) {
+        return binderStatusFromStatusT(UNEXPECTED_NULL);
+    }
+
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+    if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) {
+        ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
+        return binderStatusFromStatusT(PERMISSION_DENIED);
+    }
+    status_t status = mFlinger->getLayerDebugInfo(outLayers);
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getColorManagement(bool* outGetColorManagement) {
+    status_t status = mFlinger->getColorManagement(outGetColorManagement);
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getCompositionPreference(gui::CompositionPreference* outPref) {
+    ui::Dataspace dataspace;
+    ui::PixelFormat pixelFormat;
+    ui::Dataspace wideColorGamutDataspace;
+    ui::PixelFormat wideColorGamutPixelFormat;
+    status_t status =
+            mFlinger->getCompositionPreference(&dataspace, &pixelFormat, &wideColorGamutDataspace,
+                                               &wideColorGamutPixelFormat);
+    if (status == NO_ERROR) {
+        outPref->defaultDataspace = static_cast<int32_t>(dataspace);
+        outPref->defaultPixelFormat = static_cast<int32_t>(pixelFormat);
+        outPref->wideColorGamutDataspace = static_cast<int32_t>(wideColorGamutDataspace);
+        outPref->wideColorGamutPixelFormat = static_cast<int32_t>(wideColorGamutPixelFormat);
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayedContentSamplingAttributes(
+        const sp<IBinder>& display, gui::ContentSamplingAttributes* outAttrs) {
+    status_t status = checkAccessPermission();
+    if (status != OK) {
+        return binderStatusFromStatusT(status);
+    }
+
+    ui::PixelFormat format;
+    ui::Dataspace dataspace;
+    uint8_t componentMask;
+    status = mFlinger->getDisplayedContentSamplingAttributes(display, &format, &dataspace,
+                                                             &componentMask);
+    if (status == NO_ERROR) {
+        outAttrs->format = static_cast<int32_t>(format);
+        outAttrs->dataspace = static_cast<int32_t>(dataspace);
+        outAttrs->componentMask = static_cast<int8_t>(componentMask);
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setDisplayContentSamplingEnabled(const sp<IBinder>& display,
+                                                                     bool enable,
+                                                                     int8_t componentMask,
+                                                                     int64_t maxFrames) {
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->setDisplayContentSamplingEnabled(display, enable,
+                                                            static_cast<uint8_t>(componentMask),
+                                                            static_cast<uint64_t>(maxFrames));
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayedContentSample(const sp<IBinder>& display,
+                                                              int64_t maxFrames, int64_t timestamp,
+                                                              gui::DisplayedFrameStats* outStats) {
+    if (!outStats) {
+        return binderStatusFromStatusT(BAD_VALUE);
+    }
+
+    status_t status = checkAccessPermission();
+    if (status != OK) {
+        return binderStatusFromStatusT(status);
+    }
+
+    DisplayedFrameStats stats;
+    status = mFlinger->getDisplayedContentSample(display, static_cast<uint64_t>(maxFrames),
+                                                 static_cast<uint64_t>(timestamp), &stats);
+    if (status == NO_ERROR) {
+        // convert from ui::DisplayedFrameStats to gui::DisplayedFrameStats
+        outStats->numFrames = static_cast<int64_t>(stats.numFrames);
+        outStats->component_0_sample.reserve(stats.component_0_sample.size());
+        for (const auto& s : stats.component_0_sample) {
+            outStats->component_0_sample.push_back(static_cast<int64_t>(s));
+        }
+        outStats->component_1_sample.reserve(stats.component_1_sample.size());
+        for (const auto& s : stats.component_1_sample) {
+            outStats->component_1_sample.push_back(static_cast<int64_t>(s));
+        }
+        outStats->component_2_sample.reserve(stats.component_2_sample.size());
+        for (const auto& s : stats.component_2_sample) {
+            outStats->component_2_sample.push_back(static_cast<int64_t>(s));
+        }
+        outStats->component_3_sample.reserve(stats.component_3_sample.size());
+        for (const auto& s : stats.component_3_sample) {
+            outStats->component_3_sample.push_back(static_cast<int64_t>(s));
+        }
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getProtectedContentSupport(bool* outSupported) {
+    status_t status = mFlinger->getProtectedContentSupport(outSupported);
+    return binderStatusFromStatusT(status);
 }
 
 binder::Status SurfaceComposerAIDL::isWideColorDisplay(const sp<IBinder>& token,
                                                        bool* outIsWideColorDisplay) {
     status_t status = mFlinger->isWideColorDisplay(token, outIsWideColorDisplay);
-    return binder::Status::fromStatusT(status);
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::addRegionSamplingListener(
+        const gui::ARect& samplingArea, const sp<IBinder>& stopLayerHandle,
+        const sp<gui::IRegionSamplingListener>& listener) {
+    status_t status = checkReadFrameBufferPermission();
+    if (status != OK) {
+        return binderStatusFromStatusT(status);
+    }
+    android::Rect rect;
+    rect.left = samplingArea.left;
+    rect.top = samplingArea.top;
+    rect.right = samplingArea.right;
+    rect.bottom = samplingArea.bottom;
+    status = mFlinger->addRegionSamplingListener(rect, stopLayerHandle, listener);
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::removeRegionSamplingListener(
+        const sp<gui::IRegionSamplingListener>& listener) {
+    status_t status = checkReadFrameBufferPermission();
+    if (status == OK) {
+        status = mFlinger->removeRegionSamplingListener(listener);
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::addFpsListener(int32_t taskId,
+                                                   const sp<gui::IFpsListener>& listener) {
+    status_t status = checkReadFrameBufferPermission();
+    if (status == OK) {
+        status = mFlinger->addFpsListener(taskId, listener);
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::removeFpsListener(const sp<gui::IFpsListener>& listener) {
+    status_t status = checkReadFrameBufferPermission();
+    if (status == OK) {
+        status = mFlinger->removeFpsListener(listener);
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::addTunnelModeEnabledListener(
+        const sp<gui::ITunnelModeEnabledListener>& listener) {
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->addTunnelModeEnabledListener(listener);
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::removeTunnelModeEnabledListener(
+        const sp<gui::ITunnelModeEnabledListener>& listener) {
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->removeTunnelModeEnabledListener(listener);
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setDesiredDisplayModeSpecs(
+        const sp<IBinder>& displayToken, int32_t defaultMode, bool allowGroupSwitching,
+        float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin,
+        float appRequestRefreshRateMax) {
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->setDesiredDisplayModeSpecs(displayToken,
+                                                      static_cast<ui::DisplayModeId>(defaultMode),
+                                                      allowGroupSwitching, primaryRefreshRateMin,
+                                                      primaryRefreshRateMax,
+                                                      appRequestRefreshRateMin,
+                                                      appRequestRefreshRateMax);
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+                                                               gui::DisplayModeSpecs* outSpecs) {
+    if (!outSpecs) {
+        return binderStatusFromStatusT(BAD_VALUE);
+    }
+
+    status_t status = checkAccessPermission();
+    if (status != OK) {
+        return binderStatusFromStatusT(status);
+    }
+
+    ui::DisplayModeId displayModeId;
+    bool allowGroupSwitching;
+    float primaryRefreshRateMin;
+    float primaryRefreshRateMax;
+    float appRequestRefreshRateMin;
+    float appRequestRefreshRateMax;
+    status = mFlinger->getDesiredDisplayModeSpecs(displayToken, &displayModeId,
+                                                  &allowGroupSwitching, &primaryRefreshRateMin,
+                                                  &primaryRefreshRateMax, &appRequestRefreshRateMin,
+                                                  &appRequestRefreshRateMax);
+    if (status == NO_ERROR) {
+        outSpecs->defaultMode = displayModeId;
+        outSpecs->allowGroupSwitching = allowGroupSwitching;
+        outSpecs->primaryRefreshRateMin = primaryRefreshRateMin;
+        outSpecs->primaryRefreshRateMax = primaryRefreshRateMax;
+        outSpecs->appRequestRefreshRateMin = appRequestRefreshRateMin;
+        outSpecs->appRequestRefreshRateMax = appRequestRefreshRateMax;
+    }
+
+    return binderStatusFromStatusT(status);
 }
 
 binder::Status SurfaceComposerAIDL::getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
                                                                 bool* outSupport) {
     status_t status = mFlinger->getDisplayBrightnessSupport(displayToken, outSupport);
-    return binder::Status::fromStatusT(status);
+    return binderStatusFromStatusT(status);
 }
 
 binder::Status SurfaceComposerAIDL::setDisplayBrightness(const sp<IBinder>& displayToken,
                                                          const gui::DisplayBrightness& brightness) {
     status_t status = checkControlDisplayBrightnessPermission();
-    if (status != OK) return binder::Status::fromStatusT(status);
-
-    status = mFlinger->setDisplayBrightness(displayToken, brightness);
-    return binder::Status::fromStatusT(status);
+    if (status == OK) {
+        status = mFlinger->setDisplayBrightness(displayToken, brightness);
+    }
+    return binderStatusFromStatusT(status);
 }
 
 binder::Status SurfaceComposerAIDL::addHdrLayerInfoListener(
         const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
     status_t status = checkControlDisplayBrightnessPermission();
-    if (status != OK) return binder::Status::fromStatusT(status);
-
-    status = mFlinger->addHdrLayerInfoListener(displayToken, listener);
-    return binder::Status::fromStatusT(status);
+    if (status == OK) {
+        status = mFlinger->addHdrLayerInfoListener(displayToken, listener);
+    }
+    return binderStatusFromStatusT(status);
 }
 
 binder::Status SurfaceComposerAIDL::removeHdrLayerInfoListener(
         const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
     status_t status = checkControlDisplayBrightnessPermission();
-    if (status != OK) return binder::Status::fromStatusT(status);
-
-    status = mFlinger->removeHdrLayerInfoListener(displayToken, listener);
-    return binder::Status::fromStatusT(status);
+    if (status == OK) {
+        status = mFlinger->removeHdrLayerInfoListener(displayToken, listener);
+    }
+    return binderStatusFromStatusT(status);
 }
 
 binder::Status SurfaceComposerAIDL::notifyPowerBoost(int boostId) {
     status_t status = checkAccessPermission();
-    if (status != OK) return binder::Status::fromStatusT(status);
+    if (status == OK) {
+        status = mFlinger->notifyPowerBoost(boostId);
+    }
+    return binderStatusFromStatusT(status);
+}
 
-    status = mFlinger->notifyPowerBoost(boostId);
-    return binder::Status::fromStatusT(status);
+binder::Status SurfaceComposerAIDL::setGlobalShadowSettings(const gui::Color& ambientColor,
+                                                            const gui::Color& spotColor,
+                                                            float lightPosY, float lightPosZ,
+                                                            float lightRadius) {
+    status_t status = checkAccessPermission();
+    if (status != OK) {
+        return binderStatusFromStatusT(status);
+    }
+
+    half4 ambientColorHalf = {ambientColor.r, ambientColor.g, ambientColor.b, ambientColor.a};
+    half4 spotColorHalf = {spotColor.r, spotColor.g, spotColor.b, spotColor.a};
+    status = mFlinger->setGlobalShadowSettings(ambientColorHalf, spotColorHalf, lightPosY,
+                                               lightPosZ, lightRadius);
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayDecorationSupport(
+        const sp<IBinder>& displayToken, std::optional<gui::DisplayDecorationSupport>* outSupport) {
+    std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport> support;
+    status_t status = mFlinger->getDisplayDecorationSupport(displayToken, &support);
+    if (status != NO_ERROR) {
+        ALOGE("getDisplayDecorationSupport failed with error %d", status);
+        return binderStatusFromStatusT(status);
+    }
+
+    if (!support || !support.has_value()) {
+        outSupport->reset();
+    } else {
+        outSupport->emplace();
+        outSupport->value().format = static_cast<int32_t>(support->format);
+        outSupport->value().alphaInterpretation =
+                static_cast<int32_t>(support->alphaInterpretation);
+    }
+
+    return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::setOverrideFrameRate(int32_t uid, float frameRate) {
+    status_t status;
+    const int c_uid = IPCThreadState::self()->getCallingUid();
+    if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) {
+        status = mFlinger->setOverrideFrameRate(uid, frameRate);
+    } else {
+        ALOGE("setOverrideFrameRate() permission denied for uid: %d", c_uid);
+        status = PERMISSION_DENIED;
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::addTransactionTraceListener(
+        const sp<gui::ITransactionTraceListener>& listener) {
+    status_t status;
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int uid = ipc->getCallingUid();
+    if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) {
+        status = mFlinger->addTransactionTraceListener(listener);
+    } else {
+        status = PERMISSION_DENIED;
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getGpuContextPriority(int32_t* outPriority) {
+    *outPriority = mFlinger->getGpuContextPriority();
+    return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::getMaxAcquiredBufferCount(int32_t* buffers) {
+    status_t status = mFlinger->getMaxAcquiredBufferCount(buffers);
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::addWindowInfosListener(
+        const sp<gui::IWindowInfosListener>& windowInfosListener) {
+    status_t status;
+    const int uid = IPCThreadState::self()->getCallingUid();
+    if (uid == AID_SYSTEM || uid == AID_GRAPHICS) {
+        status = mFlinger->addWindowInfosListener(windowInfosListener);
+    } else {
+        status = PERMISSION_DENIED;
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::removeWindowInfosListener(
+        const sp<gui::IWindowInfosListener>& windowInfosListener) {
+    status_t status;
+    const int uid = IPCThreadState::self()->getCallingUid();
+    if (uid == AID_SYSTEM || uid == AID_GRAPHICS) {
+        status = mFlinger->removeWindowInfosListener(windowInfosListener);
+    } else {
+        status = PERMISSION_DENIED;
+    }
+    return binderStatusFromStatusT(status);
 }
 
 status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) {
@@ -7561,6 +8070,17 @@
     return OK;
 }
 
+status_t SurfaceComposerAIDL::checkReadFrameBufferPermission() {
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+    if ((uid != AID_GRAPHICS) && !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
+        ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid);
+        return PERMISSION_DENIED;
+    }
+    return OK;
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f14c755..ed6c8ce 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -25,6 +25,7 @@
 #include <android/gui/BnSurfaceComposer.h>
 #include <android/gui/DisplayStatInfo.h>
 #include <android/gui/DisplayState.h>
+#include <android/gui/ISurfaceComposerClient.h>
 #include <cutils/atomic.h>
 #include <cutils/compiler.h>
 #include <ftl/future.h>
@@ -32,8 +33,8 @@
 #include <gui/BufferQueue.h>
 #include <gui/FrameTimestamps.h>
 #include <gui/ISurfaceComposer.h>
-#include <gui/ISurfaceComposerClient.h>
 #include <gui/ITransactionCompletedListener.h>
+#include <gui/LayerDebugInfo.h>
 #include <gui/LayerState.h>
 #include <layerproto/LayerProtoHeader.h>
 #include <math/mat4.h>
@@ -309,9 +310,6 @@
 
     renderengine::RenderEngine& getRenderEngine() const;
 
-    bool authenticateSurfaceTextureLocked(
-        const sp<IGraphicBufferProducer>& bufferProducer) const;
-
     void onLayerFirstRef(Layer*);
     void onLayerDestroyed(Layer*);
     void onLayerUpdate();
@@ -335,7 +333,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
@@ -375,7 +372,6 @@
 
 private:
     friend class BufferLayer;
-    friend class BufferQueueLayer;
     friend class BufferStateLayer;
     friend class Client;
     friend class FpsReporter;
@@ -519,10 +515,11 @@
         }
     }
 
-    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); }
@@ -530,7 +527,6 @@
             EXCLUDES(mStateLock);
 
     // Implements ISurfaceComposer
-    sp<ISurfaceComposerClient> createConnection() override;
     sp<IBinder> createDisplay(const String8& displayName, bool secure);
     void destroyDisplay(const sp<IBinder>& displayToken);
     std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const EXCLUDES(mStateLock) {
@@ -549,13 +545,12 @@
                                  const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
                                  const std::vector<ListenerCallbacks>& listenerCallbacks,
                                  uint64_t transactionId) override;
-    void bootFinished() override;
-    bool authenticateSurfaceTexture(
-            const sp<IGraphicBufferProducer>& bufferProducer) const override;
-    status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const 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>&);
@@ -565,62 +560,58 @@
     status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*)
             EXCLUDES(mStateLock);
     status_t getStaticDisplayInfo(const sp<IBinder>& displayToken, ui::StaticDisplayInfo*)
-            EXCLUDES(mStateLock) override;
+            EXCLUDES(mStateLock);
     status_t getDynamicDisplayInfo(const sp<IBinder>& displayToken, ui::DynamicDisplayInfo*)
-            EXCLUDES(mStateLock) override;
-    status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
-                                       ui::DisplayPrimaries&) override;
-    status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
+            EXCLUDES(mStateLock);
+    status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken, ui::DisplayPrimaries&);
+    status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode);
     status_t getBootDisplayModeSupport(bool* outSupport) const;
-    status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id) override;
+    status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id);
     status_t clearBootDisplayMode(const sp<IBinder>& displayToken);
     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() override;
-    status_t getAnimationFrameStats(FrameStats* outStats) const override;
+    status_t clearAnimationFrameStats();
+    status_t getAnimationFrameStats(FrameStats* outStats) const;
     status_t overrideHdrTypes(const sp<IBinder>& displayToken,
-                              const std::vector<ui::Hdr>& hdrTypes) override;
-    status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) override;
-    status_t enableVSyncInjections(bool enable) override;
-    status_t injectVSync(nsecs_t when) override;
-    status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override;
-    status_t getColorManagement(bool* outGetColorManagement) const override;
+                              const std::vector<ui::Hdr>& hdrTypes);
+    status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success);
+    status_t enableVSyncInjections(bool enable);
+    status_t injectVSync(nsecs_t when);
+    status_t getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers);
+    status_t getColorManagement(bool* outGetColorManagement) const;
     status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
                                       ui::Dataspace* outWideColorGamutDataspace,
-                                      ui::PixelFormat* outWideColorGamutPixelFormat) const override;
+                                      ui::PixelFormat* outWideColorGamutPixelFormat) const;
     status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken,
                                                    ui::PixelFormat* outFormat,
                                                    ui::Dataspace* outDataspace,
-                                                   uint8_t* outComponentMask) const override;
+                                                   uint8_t* outComponentMask) const;
     status_t setDisplayContentSamplingEnabled(const sp<IBinder>& displayToken, bool enable,
-                                              uint8_t componentMask, uint64_t maxFrames) override;
+                                              uint8_t componentMask, uint64_t maxFrames);
     status_t getDisplayedContentSample(const sp<IBinder>& displayToken, uint64_t maxFrames,
-                                       uint64_t timestamp,
-                                       DisplayedFrameStats* outStats) const override;
-    status_t getProtectedContentSupport(bool* outSupported) const override;
+                                       uint64_t timestamp, DisplayedFrameStats* outStats) const;
+    status_t getProtectedContentSupport(bool* outSupported) const;
     status_t isWideColorDisplay(const sp<IBinder>& displayToken, bool* outIsWideColorDisplay) const;
     status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
-                                       const sp<IRegionSamplingListener>& listener) override;
-    status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
-    status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) override;
-    status_t removeFpsListener(const sp<gui::IFpsListener>& listener) override;
-    status_t addTunnelModeEnabledListener(
-            const sp<gui::ITunnelModeEnabledListener>& listener) override;
-    status_t removeTunnelModeEnabledListener(
-            const sp<gui::ITunnelModeEnabledListener>& listener) override;
+                                       const sp<IRegionSamplingListener>& listener);
+    status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener);
+    status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener);
+    status_t removeFpsListener(const sp<gui::IFpsListener>& listener);
+    status_t addTunnelModeEnabledListener(const sp<gui::ITunnelModeEnabledListener>& listener);
+    status_t removeTunnelModeEnabledListener(const sp<gui::ITunnelModeEnabledListener>& listener);
     status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
                                         ui::DisplayModeId displayModeId, bool allowGroupSwitching,
                                         float primaryRefreshRateMin, float primaryRefreshRateMax,
                                         float appRequestRefreshRateMin,
-                                        float appRequestRefreshRateMax) override;
+                                        float appRequestRefreshRateMax);
     status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
                                         ui::DisplayModeId* outDefaultMode,
                                         bool* outAllowGroupSwitching,
                                         float* outPrimaryRefreshRateMin,
                                         float* outPrimaryRefreshRateMax,
                                         float* outAppRequestRefreshRateMin,
-                                        float* outAppRequestRefreshRateMax) override;
+                                        float* outAppRequestRefreshRateMax);
     status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) const;
     status_t setDisplayBrightness(const sp<IBinder>& displayToken,
                                   const gui::DisplayBrightness& brightness);
@@ -630,30 +621,28 @@
                                         const sp<gui::IHdrLayerInfoListener>& listener);
     status_t notifyPowerBoost(int32_t boostId);
     status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
-                                     float lightPosY, float lightPosZ, float lightRadius) override;
+                                     float lightPosY, float lightPosZ, float lightRadius);
     status_t getDisplayDecorationSupport(
             const sp<IBinder>& displayToken,
             std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
-                    outSupport) const override;
+                    outSupport) const;
     status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
-                          int8_t compatibility, int8_t changeFrameRateStrategy) override;
+                          int8_t compatibility, int8_t changeFrameRateStrategy);
 
     status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface,
-                                  const FrameTimelineInfo& frameTimelineInfo) override;
+                                  const gui::FrameTimelineInfo& frameTimelineInfo);
 
-    status_t setOverrideFrameRate(uid_t uid, float frameRate) override;
+    status_t setOverrideFrameRate(uid_t uid, float frameRate);
 
-    status_t addTransactionTraceListener(
-            const sp<gui::ITransactionTraceListener>& listener) override;
+    status_t addTransactionTraceListener(const sp<gui::ITransactionTraceListener>& listener);
 
-    int getGPUContextPriority() override;
+    int getGpuContextPriority();
 
-    status_t getMaxAcquiredBufferCount(int* buffers) const override;
+    status_t getMaxAcquiredBufferCount(int* buffers) const;
 
-    status_t addWindowInfosListener(
-            const sp<gui::IWindowInfosListener>& windowInfosListener) const override;
+    status_t addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener) const;
     status_t removeWindowInfosListener(
-            const sp<gui::IWindowInfosListener>& windowInfosListener) const override;
+            const sp<gui::IWindowInfosListener>& windowInfosListener) const;
 
     // Implements IBinder::DeathRecipient.
     void binderDied(const wp<IBinder>& who) override;
@@ -832,10 +821,6 @@
                          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);
 
@@ -1178,7 +1163,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 =
@@ -1212,7 +1197,7 @@
     // 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;
@@ -1275,6 +1260,8 @@
     const std::unique_ptr<FrameTracer> mFrameTracer;
     const std::unique_ptr<frametimeline::FrameTimeline> mFrameTimeline;
 
+    int64_t mLastCommittedVsyncId = -1;
+
     // If blurs should be enabled on this device.
     bool mSupportsBlur = false;
     // If blurs are considered expensive and should require high GPU frequency.
@@ -1414,8 +1401,9 @@
     // 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(int64_t vsyncId);
+    void handleLayerCreatedLocked(const LayerCreatedState& state, int64_t vsyncId)
+            REQUIRES(mStateLock);
 
     std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint;
 
@@ -1435,12 +1423,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);
 
@@ -1449,8 +1437,13 @@
 
 class SurfaceComposerAIDL : public gui::BnSurfaceComposer {
 public:
-    SurfaceComposerAIDL(sp<SurfaceFlinger> sf) { mFlinger = sf; }
+    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;
@@ -1458,10 +1451,19 @@
     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;
     binder::Status getDisplayStats(const sp<IBinder>& display,
                                    gui::DisplayStatInfo* outStatInfo) override;
     binder::Status getDisplayState(const sp<IBinder>& display,
                                    gui::DisplayState* outState) override;
+    binder::Status getStaticDisplayInfo(const sp<IBinder>& display,
+                                        gui::StaticDisplayInfo* outInfo) override;
+    binder::Status getDynamicDisplayInfo(const sp<IBinder>& display,
+                                         gui::DynamicDisplayInfo* outInfo) override;
+    binder::Status getDisplayNativePrimaries(const sp<IBinder>& display,
+                                             gui::DisplayPrimaries* outPrimaries) override;
+    binder::Status setActiveColorMode(const sp<IBinder>& display, int colorMode) override;
+    binder::Status setBootDisplayMode(const sp<IBinder>& display, int displayModeId) override;
     binder::Status clearBootDisplayMode(const sp<IBinder>& display) override;
     binder::Status getBootDisplayModeSupport(bool* outMode) override;
     binder::Status setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override;
@@ -1471,8 +1473,45 @@
     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;
+    binder::Status overrideHdrTypes(const sp<IBinder>& display,
+                                    const std::vector<int32_t>& hdrTypes) override;
+    binder::Status onPullAtom(int32_t atomId, gui::PullAtomData* outPullData) override;
+    binder::Status enableVSyncInjections(bool enable) override;
+    binder::Status injectVSync(int64_t when) override;
+    binder::Status getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) override;
+    binder::Status getColorManagement(bool* outGetColorManagement) override;
+    binder::Status getCompositionPreference(gui::CompositionPreference* outPref) override;
+    binder::Status getDisplayedContentSamplingAttributes(
+            const sp<IBinder>& display, gui::ContentSamplingAttributes* outAttrs) override;
+    binder::Status setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
+                                                    int8_t componentMask,
+                                                    int64_t maxFrames) override;
+    binder::Status getDisplayedContentSample(const sp<IBinder>& display, int64_t maxFrames,
+                                             int64_t timestamp,
+                                             gui::DisplayedFrameStats* outStats) override;
+    binder::Status getProtectedContentSupport(bool* outSupporte) override;
     binder::Status isWideColorDisplay(const sp<IBinder>& token,
                                       bool* outIsWideColorDisplay) override;
+    binder::Status addRegionSamplingListener(
+            const gui::ARect& samplingArea, const sp<IBinder>& stopLayerHandle,
+            const sp<gui::IRegionSamplingListener>& listener) override;
+    binder::Status removeRegionSamplingListener(
+            const sp<gui::IRegionSamplingListener>& listener) override;
+    binder::Status addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) override;
+    binder::Status removeFpsListener(const sp<gui::IFpsListener>& listener) override;
+    binder::Status addTunnelModeEnabledListener(
+            const sp<gui::ITunnelModeEnabledListener>& listener) override;
+    binder::Status removeTunnelModeEnabledListener(
+            const sp<gui::ITunnelModeEnabledListener>& listener) override;
+    binder::Status setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, int32_t defaultMode,
+                                              bool allowGroupSwitching, float primaryRefreshRateMin,
+                                              float primaryRefreshRateMax,
+                                              float appRequestRefreshRateMin,
+                                              float appRequestRefreshRateMax) override;
+    binder::Status getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+                                              gui::DisplayModeSpecs* outSpecs) override;
     binder::Status getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
                                                bool* outSupport) override;
     binder::Status setDisplayBrightness(const sp<IBinder>& displayToken,
@@ -1483,11 +1522,27 @@
             const sp<IBinder>& displayToken,
             const sp<gui::IHdrLayerInfoListener>& listener) override;
     binder::Status notifyPowerBoost(int boostId) override;
+    binder::Status setGlobalShadowSettings(const gui::Color& ambientColor,
+                                           const gui::Color& spotColor, float lightPosY,
+                                           float lightPosZ, float lightRadius) override;
+    binder::Status getDisplayDecorationSupport(
+            const sp<IBinder>& displayToken,
+            std::optional<gui::DisplayDecorationSupport>* outSupport) override;
+    binder::Status setOverrideFrameRate(int32_t uid, float frameRate) override;
+    binder::Status addTransactionTraceListener(
+            const sp<gui::ITransactionTraceListener>& listener) override;
+    binder::Status getGpuContextPriority(int32_t* outPriority) override;
+    binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override;
+    binder::Status addWindowInfosListener(
+            const sp<gui::IWindowInfosListener>& windowInfosListener) override;
+    binder::Status removeWindowInfosListener(
+            const sp<gui::IWindowInfosListener>& windowInfosListener) override;
 
 private:
     static const constexpr bool kUsePermissionCache = true;
     status_t checkAccessPermission(bool usePermissionCache = kUsePermissionCache);
     status_t checkControlDisplayBrightnessPermission();
+    status_t checkReadFrameBufferPermission();
 
 private:
     sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index b81b445..39a5d0f 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -23,7 +23,6 @@
 #include <ui/GraphicBuffer.h>
 
 #include "BufferLayerConsumer.h"
-#include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
 #include "ContainerLayer.h"
 #include "DisplayDevice.h"
@@ -109,10 +108,6 @@
     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);
 }
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 501629d..173ca81 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -47,7 +47,6 @@
     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;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 6153e8e..e117e96 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -30,7 +30,6 @@
 
 typedef int32_t PixelFormat;
 
-class BufferQueueLayer;
 class BufferLayerConsumer;
 class BufferStateLayer;
 class ContainerLayer;
@@ -98,7 +97,6 @@
 
     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;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 7a159b8..61d7c22 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -34,6 +34,8 @@
 
 #include <scheduler/Fps.h>
 
+using android::gui::GameMode;
+using android::gui::LayerMetadata;
 using namespace android::surfaceflinger;
 
 namespace android {
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 237ae8d..60aa810 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -24,6 +24,9 @@
 #include <unordered_map>
 #include <vector>
 
+using android::gui::GameMode;
+using android::gui::LayerMetadata;
+
 namespace android {
 namespace surfaceflinger {
 
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index 49554c7..afa3e50 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -98,7 +98,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 +129,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 a73eccf..65918f6 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <gui/SurfaceComposerClient.h>
+#include <ui/Fence.h>
 #include <ui/Rect.h>
 
 #include "LayerProtoHelper.h"
@@ -458,7 +459,7 @@
             layer.parentSurfaceControlForChild =
                     new SurfaceControl(SurfaceComposerClient::getDefault(),
                                        mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
-                                       nullptr, static_cast<int32_t>(layerId));
+                                       static_cast<int32_t>(layerId));
         }
     }
     if (proto.what() & layer_state_t::eRelativeLayerChanged) {
@@ -469,7 +470,7 @@
             layer.relativeLayerSurfaceControl =
                     new SurfaceControl(SurfaceComposerClient::getDefault(),
                                        mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
-                                       nullptr, static_cast<int32_t>(layerId));
+                                       static_cast<int32_t>(layerId));
         }
         layer.z = proto.z();
     }
@@ -497,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 = nullptr;
+        }
+
         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..af0594e 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -152,17 +152,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 +251,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 +281,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 +296,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 +330,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 +341,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 +356,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 +400,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 +430,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 cf44eff..5e20b74 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>
@@ -104,10 +105,6 @@
         return new EffectLayer(args);
     }
 
-    sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
-        return nullptr;
-    }
-
     std::unique_ptr<FrameTracer> createFrameTracer() override {
         return std::make_unique<testing::NiceMock<mock::FrameTracer>>();
     }
@@ -142,6 +139,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;
@@ -181,6 +186,7 @@
 bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile,
                                    const char* outputLayersTracePath) {
     if (traceFile.entry_size() == 0) {
+        ALOGD("Trace file is empty");
         return false;
     }
 
@@ -205,6 +211,7 @@
     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>();
@@ -217,9 +224,10 @@
     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
@@ -238,7 +246,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,
@@ -265,13 +273,13 @@
                                          transaction.listenerCallbacks, transaction.id);
         }
 
-        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);
+
+        for (int j = 0; j < entry.removed_layer_handles_size(); j++) {
+            dataMapper->mLayerHandles.erase(entry.removed_layer_handles(j));
+        }
     }
 
     flinger->stopLayerTracing(outputLayersTracePath);
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index 900d566..bbfeac1 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -106,7 +106,6 @@
 public:
     enum {
         eSyncTransaction = 1 << 0,
-        eSyncInputWindows = 1 << 1,
     };
     explicit CountDownLatch(uint32_t flags) : mFlags(flags) {}
 
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index 30b9d8f..cc33001 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -26,21 +26,39 @@
 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);
@@ -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 (!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/Android.bp b/services/surfaceflinger/fuzzer/Android.bp
index b0b6bf1..7350e09 100644
--- a/services/surfaceflinger/fuzzer/Android.bp
+++ b/services/surfaceflinger/fuzzer/Android.bp
@@ -127,3 +127,13 @@
         "surfaceflinger_layer_fuzzer.cpp",
     ],
 }
+
+cc_fuzz {
+    name: "surfaceflinger_frametracer_fuzzer",
+    defaults: [
+        "surfaceflinger_fuzz_defaults",
+    ],
+    srcs: [
+        "surfaceflinger_frametracer_fuzzer.cpp",
+    ],
+}
diff --git a/services/surfaceflinger/fuzzer/README.md b/services/surfaceflinger/fuzzer/README.md
index 78a7596..7a5f229 100644
--- a/services/surfaceflinger/fuzzer/README.md
+++ b/services/surfaceflinger/fuzzer/README.md
@@ -4,6 +4,7 @@
 + [DisplayHardware](#DisplayHardware)
 + [Scheduler](#Scheduler)
 + [Layer](#Layer)
++ [FrameTracer](#FrameTracer)
 
 # <a name="SurfaceFlinger"></a> Fuzzer for SurfaceFlinger
 
@@ -93,3 +94,16 @@
   $ adb sync data
   $ adb shell /data/fuzz/arm64/surfaceflinger_layer_fuzzer/surfaceflinger_layer_fuzzer
 ```
+
+# <a name="FrameTracer"></a> Fuzzer for FrameTracer
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) surfaceflinger_frametracer_fuzzer
+```
+2. To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/surfaceflinger_frametracer_fuzzer/surfaceflinger_frametracer_fuzzer
+```
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp
new file mode 100644
index 0000000..a22a778
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp
@@ -0,0 +1,132 @@
+/*
+ * 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 <FrameTracer/FrameTracer.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <perfetto/trace/trace.pb.h>
+
+namespace android::fuzz {
+
+using namespace google::protobuf;
+
+constexpr size_t kMaxStringSize = 100;
+constexpr size_t kMinLayerIds = 1;
+constexpr size_t kMaxLayerIds = 10;
+constexpr int32_t kConfigDuration = 500;
+constexpr int32_t kBufferSize = 1024;
+constexpr int32_t kTimeOffset = 100000;
+
+class FrameTracerFuzzer {
+public:
+    FrameTracerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) {
+        // Fuzzer is single-threaded, so no need to be thread-safe.
+        static bool wasInitialized = false;
+        if (!wasInitialized) {
+            perfetto::TracingInitArgs args;
+            args.backends = perfetto::kInProcessBackend;
+            perfetto::Tracing::Initialize(args);
+            wasInitialized = true;
+        }
+        mFrameTracer = std::make_unique<android::FrameTracer>();
+    }
+    ~FrameTracerFuzzer() { mFrameTracer.reset(); }
+    void process();
+
+private:
+    std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest();
+    void traceTimestamp();
+    std::vector<int32_t> generateLayerIds(size_t numLayerIds);
+    void traceTimestamp(std::vector<int32_t> layerIds, size_t numLayerIds);
+    void traceFence(std::vector<int32_t> layerIds, size_t numLayerIds);
+    std::unique_ptr<android::FrameTracer> mFrameTracer = nullptr;
+    FuzzedDataProvider mFdp;
+    android::FenceToFenceTimeMap mFenceFactory;
+};
+
+std::unique_ptr<perfetto::TracingSession> FrameTracerFuzzer::getTracingSessionForTest() {
+    perfetto::TraceConfig cfg;
+    cfg.set_duration_ms(kConfigDuration);
+    cfg.add_buffers()->set_size_kb(kBufferSize);
+    auto* dsCfg = cfg.add_data_sources()->mutable_config();
+    dsCfg->set_name(android::FrameTracer::kFrameTracerDataSource);
+
+    auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
+    tracingSession->Setup(cfg);
+    return tracingSession;
+}
+
+std::vector<int32_t> FrameTracerFuzzer::generateLayerIds(size_t numLayerIds) {
+    std::vector<int32_t> layerIds;
+    for (size_t i = 0; i < numLayerIds; ++i) {
+        layerIds.push_back(mFdp.ConsumeIntegral<int32_t>());
+    }
+    return layerIds;
+}
+
+void FrameTracerFuzzer::traceTimestamp(std::vector<int32_t> layerIds, size_t numLayerIds) {
+    int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange<size_t>(0, numLayerIds - 1));
+    mFrameTracer->traceTimestamp(layerId, mFdp.ConsumeIntegral<uint64_t>() /*bufferID*/,
+                                 mFdp.ConsumeIntegral<uint64_t>() /*frameNumber*/,
+                                 mFdp.ConsumeIntegral<nsecs_t>() /*timestamp*/,
+                                 android::FrameTracer::FrameEvent::UNSPECIFIED,
+                                 mFdp.ConsumeIntegral<nsecs_t>() /*duration*/);
+}
+
+void FrameTracerFuzzer::traceFence(std::vector<int32_t> layerIds, size_t numLayerIds) {
+    const nsecs_t signalTime = systemTime();
+    const nsecs_t startTime = signalTime + kTimeOffset;
+    auto fence = mFenceFactory.createFenceTimeForTest(android::Fence::NO_FENCE);
+    mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, signalTime);
+    int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange<size_t>(0, numLayerIds - 1));
+    mFrameTracer->traceFence(layerId, mFdp.ConsumeIntegral<uint64_t>() /*bufferID*/,
+                             mFdp.ConsumeIntegral<uint64_t>() /*frameNumber*/, fence,
+                             android::FrameTracer::FrameEvent::ACQUIRE_FENCE, startTime);
+}
+
+void FrameTracerFuzzer::process() {
+    mFrameTracer->registerDataSource();
+
+    auto tracingSession = getTracingSessionForTest();
+    tracingSession->StartBlocking();
+
+    size_t numLayerIds = mFdp.ConsumeIntegralInRange<size_t>(kMinLayerIds, kMaxLayerIds);
+    std::vector<int32_t> layerIds = generateLayerIds(numLayerIds);
+
+    for (auto it = layerIds.begin(); it != layerIds.end(); ++it) {
+        mFrameTracer->traceNewLayer(*it /*layerId*/,
+                                    mFdp.ConsumeRandomLengthString(kMaxStringSize) /*layerName*/);
+    }
+
+    traceTimestamp(layerIds, numLayerIds);
+    traceFence(layerIds, numLayerIds);
+
+    mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, systemTime());
+
+    tracingSession->StopBlocking();
+
+    for (auto it = layerIds.begin(); it != layerIds.end(); ++it) {
+        mFrameTracer->onDestroy(*it);
+    }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FrameTracerFuzzer frameTracerFuzzer(data, size);
+    frameTracerFuzzer.process();
+    return 0;
+}
+
+} // namespace android::fuzz
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index f25043c..8e60247 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -151,7 +151,6 @@
     sp<IBinder> handle = defaultServiceManager()->checkService(
             String16(mFdp.ConsumeRandomLengthString().c_str()));
     mFlinger->fromHandle(handle);
-    mFlinger->windowInfosReported();
     mFlinger->disableExpensiveRendering();
 }
 
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 867a198..456a498 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -30,7 +30,6 @@
 #include <ui/DisplayStatInfo.h>
 #include <ui/DynamicDisplayInfo.h>
 
-#include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
 #include "ContainerLayer.h"
 #include "DisplayDevice.h"
@@ -356,10 +355,6 @@
         return compositionengine::impl::createCompositionEngine();
     }
 
-    sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs &) override {
-        return nullptr;
-    }
-
     sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs &) override {
         return nullptr;
     }
@@ -552,7 +547,7 @@
 
     sp<IBinder> fuzzBoot(FuzzedDataProvider *fdp) {
         mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(fdp->ConsumeBool());
-        mFlinger->createConnection();
+        const sp<Client> client = new Client(mFlinger);
 
         DisplayIdGenerator<HalVirtualDisplayId> kGenerator;
         HalVirtualDisplayId halVirtualDisplayId = kGenerator.generateId().value();
@@ -585,7 +580,6 @@
         sp<IBinder> display = fuzzBoot(&mFdp);
 
         sp<IGraphicBufferProducer> bufferProducer = sp<mock::GraphicBufferProducer>::make();
-        mFlinger->authenticateSurfaceTexture(bufferProducer.get());
 
         mFlinger->createDisplayEventConnection();
 
@@ -779,7 +773,7 @@
         return mFlinger->onTransact(code, data, reply, flags);
     }
 
-    auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); }
+    auto getGpuContextPriority() { return mFlinger->getGpuContextPriority(); }
 
     auto calculateMaxAcquiredBufferCount(Fps refreshRate,
                                          std::chrono::nanoseconds presentLatency) const {
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index 34cf906..4aef017 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -59,8 +59,10 @@
 }
 
 FrameTimelineInfo LayerFuzzer::getFuzzedFrameTimelineInfo() {
-    return FrameTimelineInfo{.vsyncId = mFdp.ConsumeIntegral<int64_t>(),
-                             .inputEventId = mFdp.ConsumeIntegral<int32_t>()};
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = mFdp.ConsumeIntegral<int64_t>();
+    ftInfo.inputEventId = mFdp.ConsumeIntegral<int32_t>();
+    return ftInfo;
 }
 
 LayerCreationArgs LayerFuzzer::createLayerCreationArgs(TestableSurfaceFlinger* flinger,
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index da60a69..1a91a69 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -319,7 +319,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 = new BufferStateLayer(args);
 
     layer->setFrameRateSelectionPriority(mFdp.ConsumeIntegral<int16_t>());
 }
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 52503ba..cdc2706 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -24,6 +24,8 @@
 #include <unordered_map>
 #include <vector>
 
+using android::gui::LayerMetadata;
+
 namespace android {
 namespace surfaceflinger {
 
diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto
index 13647b6..7def024 100644
--- a/services/surfaceflinger/layerproto/layerstrace.proto
+++ b/services/surfaceflinger/layerproto/layerstrace.proto
@@ -40,7 +40,7 @@
     repeated LayersTraceProto entry = 2;
 }
 
-/* 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 +60,6 @@
     optional uint32 missed_entries = 6;
 
     repeated DisplayProto displays = 7;
+
+    optional int64 vsync_id = 8;
 }
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/BootDisplayMode_test.cpp b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
index d70908e..432e227 100644
--- a/services/surfaceflinger/tests/BootDisplayMode_test.cpp
+++ b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
@@ -18,6 +18,7 @@
 
 #include <gtest/gtest.h>
 
+#include <gui/AidlStatusUtil.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
 #include <private/gui/ComposerServiceAIDL.h>
@@ -25,15 +26,17 @@
 
 namespace android {
 
+using gui::aidl_utils::statusTFromBinderStatus;
+
 TEST(BootDisplayModeTest, setBootDisplayMode) {
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    sp<gui::ISurfaceComposer> sf_aidl(ComposerServiceAIDL::getComposerService());
+    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
     auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
     bool bootModeSupport = false;
-    binder::Status status = sf_aidl->getBootDisplayModeSupport(&bootModeSupport);
-    ASSERT_NO_FATAL_FAILURE(status.transactionError());
+    binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport);
+    ASSERT_NO_FATAL_FAILURE(statusTFromBinderStatus(status));
     if (bootModeSupport) {
-        ASSERT_EQ(NO_ERROR, sf->setBootDisplayMode(displayToken, 0));
+        status = sf->setBootDisplayMode(displayToken, 0);
+        ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status));
     }
 }
 
@@ -42,10 +45,10 @@
     auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
     bool bootModeSupport = false;
     binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport);
-    ASSERT_NO_FATAL_FAILURE(status.transactionError());
+    ASSERT_NO_FATAL_FAILURE(statusTFromBinderStatus(status));
     if (bootModeSupport) {
         status = sf->clearBootDisplayMode(displayToken);
-        ASSERT_EQ(NO_ERROR, status.transactionError());
+        ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status));
     }
 }
 
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index d33bc10..8a443b8 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -18,13 +18,14 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wconversion"
 
+#include <android/gui/ISurfaceComposer.h>
 #include <gtest/gtest.h>
-#include <gui/ISurfaceComposer.h>
+#include <gui/AidlStatusUtil.h>
 #include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/android_filesystem_config.h>
-#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 #include <ui/DisplayMode.h>
 #include <ui/DynamicDisplayInfo.h>
 #include <utils/String8.h>
@@ -34,6 +35,8 @@
 namespace android {
 
 using Transaction = SurfaceComposerClient::Transaction;
+using gui::LayerDebugInfo;
+using gui::aidl_utils::statusTFromBinderStatus;
 using ui::ColorMode;
 
 namespace {
@@ -307,23 +310,26 @@
  */
 TEST_F(CredentialsTest, GetLayerDebugInfo) {
     setupBackgroundSurface();
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
 
     // Historically, only root and shell can access the getLayerDebugInfo which
     // is called when we call dumpsys. I don't see a reason why we should change this.
     std::vector<LayerDebugInfo> outLayers;
     // Check with root.
     seteuid(AID_ROOT);
-    ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers));
+    binder::Status status = sf->getLayerDebugInfo(&outLayers);
+    ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status));
 
     // Check as a shell.
     seteuid(AID_SHELL);
-    ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers));
+    status = sf->getLayerDebugInfo(&outLayers);
+    ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status));
 
     // Check as anyone else.
     seteuid(AID_ROOT);
     seteuid(AID_BIN);
-    ASSERT_EQ(PERMISSION_DENIED, sf->getLayerDebugInfo(&outLayers));
+    status = sf->getLayerDebugInfo(&outLayers);
+    ASSERT_EQ(PERMISSION_DENIED, statusTFromBinderStatus(status));
 }
 
 TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) {
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/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index d192a2d..023133f 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -48,7 +48,7 @@
     }
 
     sp<SurfaceControl> makeNotSurfaceControl() {
-        return new SurfaceControl(mScc, new NotALayer(), nullptr, true);
+        return new SurfaceControl(mScc, new NotALayer(), 1);
     }
 };
 
@@ -64,4 +64,4 @@
 } // namespace android
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerBorder_test.cpp b/services/surfaceflinger/tests/LayerBorder_test.cpp
new file mode 100644
index 0000000..f80c705
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerBorder_test.cpp
@@ -0,0 +1,284 @@
+/*
+ * 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 =
+                new GraphicBuffer(400, 400, PIXEL_FORMAT_RGBA_8888, 1,
+                                  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 219db8c..c8df0a0 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -1050,7 +1050,10 @@
     }
 
     const Vsync vsync = waitForNextVsync();
-    transaction.setFrameTimelineInfo({vsync.vsyncId, 0});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = vsync.vsyncId;
+    ftInfo.inputEventId = 0;
+    transaction.setFrameTimelineInfo(ftInfo);
     transaction.apply();
 
     ExpectedResult expected;
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index 6bd7920..b46db65 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -23,9 +23,11 @@
 
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
+#include <gui/AidlStatusUtil.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 #include <ui/DisplayMode.h>
 
 #include "BufferGenerator.h"
@@ -44,8 +46,9 @@
 
         ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
 
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
+        sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
+        binder::Status status = sf->getColorManagement(&mColorManagementUsed);
+        ASSERT_NO_FATAL_FAILURE(gui::aidl_utils::statusTFromBinderStatus(status));
 
         mCaptureArgs.displayToken = mDisplay;
     }
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/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index b38032d..f824fdf 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.");
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index b3b4ec1..00845d7 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -29,6 +29,7 @@
 #include "MockComposerHal.h"
 
 #include <binder/Parcel.h>
+#include <gui/AidlStatusUtil.h>
 #include <gui/DisplayEventReceiver.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/LayerDebugInfo.h>
@@ -43,6 +44,7 @@
 #include <hwbinder/ProcessState.h>
 #include <log/log.h>
 #include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 #include <ui/DisplayMode.h>
 #include <ui/DynamicDisplayInfo.h>
 #include <utils/Looper.h>
@@ -243,8 +245,9 @@
         mComposerClient = new SurfaceComposerClient;
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
 
-        mReceiver.reset(new DisplayEventReceiver(ISurfaceComposer::eVsyncSourceApp,
-                                                 ISurfaceComposer::EventRegistration::modeChanged));
+        mReceiver.reset(
+                new DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp,
+                                         gui::ISurfaceComposer::EventRegistration::modeChanged));
         mLooper = new Looper(false);
         mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this);
     }
@@ -992,7 +995,7 @@
 
 // Tests that VSYNC injection can be safely toggled while invalidating.
 TEST_F(DisplayTest_2_1, VsyncInjection) {
-    const auto flinger = ComposerService::getComposerService();
+    const auto flinger = ComposerServiceAIDL::getComposerService();
     bool enable = true;
 
     for (int i = 0; i < 100; i++) {
@@ -1238,9 +1241,10 @@
         sFakeComposer->clearFrames();
         ASSERT_EQ(0, sFakeComposer->getFrameCount());
 
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        std::vector<LayerDebugInfo> layers;
-        status_t result = sf->getLayerDebugInfo(&layers);
+        sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
+        std::vector<gui::LayerDebugInfo> layers;
+        binder::Status status = sf->getLayerDebugInfo(&layers);
+        status_t result = gui::aidl_utils::statusTFromBinderStatus(status);
         if (result != NO_ERROR) {
             ALOGE("Failed to get layers %s %d", strerror(-result), result);
         } else {
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..53de4a6 100644
--- a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
+++ b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
@@ -52,6 +52,8 @@
     void verifyAndClearExpectations();
     void sendActualWorkDurationGroup(std::vector<WorkDuration> durations,
                                      std::chrono::nanoseconds sleepBeforeLastSend);
+    std::chrono::nanoseconds mAllowedDeviation;
+    std::chrono::nanoseconds mStaleTimeout;
 };
 
 void AidlPowerHalWrapperTest::SetUp() {
@@ -59,6 +61,9 @@
     mMockSession = new NiceMock<MockIPowerHintSession>();
     ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)).WillByDefault(Return(Status::ok()));
     mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal);
+    mWrapper->setAllowedActualDeviation(std::chrono::nanoseconds{10ms}.count());
+    mAllowedDeviation = std::chrono::nanoseconds{mWrapper->mAllowedActualDeviation};
+    mStaleTimeout = AidlPowerHalWrapper::kStaleTimeout;
 }
 
 void AidlPowerHalWrapperTest::verifyAndClearExpectations() {
@@ -76,6 +81,7 @@
         mWrapper->sendActualWorkDuration(duration.durationNanos, duration.timeStampNanos);
     }
 }
+
 WorkDuration toWorkDuration(std::chrono::nanoseconds durationNanos, int64_t timeStampNanos) {
     WorkDuration duration;
     duration.durationNanos = durationNanos.count();
@@ -83,6 +89,10 @@
     return duration;
 }
 
+WorkDuration toWorkDuration(std::pair<std::chrono::nanoseconds, nsecs_t> timePair) {
+    return toWorkDuration(timePair.first, timePair.second);
+}
+
 std::string printWorkDurations(const ::std::vector<WorkDuration>& durations) {
     std::ostringstream os;
     for (auto duration : durations) {
@@ -112,7 +122,7 @@
     EXPECT_FALSE(mWrapper->startPowerHintSession());
 }
 
-TEST_F(AidlPowerHalWrapperTest, restartNewPoserHintSessionWithNewThreadIds) {
+TEST_F(AidlPowerHalWrapperTest, restartNewPowerHintSessionWithNewThreadIds) {
     ASSERT_TRUE(mWrapper->supportsPowerHintSession());
 
     std::vector<int32_t> threadIds = {1, 2};
@@ -149,12 +159,8 @@
 
     std::chrono::nanoseconds base = 100ms;
     // test cases with target work duration and whether it should update hint against baseline 100ms
-    const std::vector<std::pair<std::chrono::nanoseconds, bool>> testCases = {{0ms, false},
-                                                                              {-1ms, false},
-                                                                              {200ms, true},
-                                                                              {2ms, true},
-                                                                              {91ms, false},
-                                                                              {109ms, false}};
+    const std::vector<std::pair<std::chrono::nanoseconds, bool>> testCases =
+            {{0ms, true}, {-1ms, true}, {200ms, true}, {2ms, true}, {100ms, false}, {109ms, true}};
 
     for (const auto& test : testCases) {
         // reset to 100ms baseline
@@ -200,21 +206,21 @@
     // 100ms
     const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
             testCases = {{{{-1ms, 100}}, false},
-                         {{{91ms, 100}}, false},
-                         {{{109ms, 100}}, false},
+                         {{{100ms - (mAllowedDeviation / 2), 100}}, false},
+                         {{{100ms + (mAllowedDeviation / 2), 100}}, false},
+                         {{{100ms + (mAllowedDeviation + 1ms), 100}}, true},
+                         {{{100ms - (mAllowedDeviation + 1ms), 100}}, true},
                          {{{100ms, 100}, {200ms, 200}}, true},
                          {{{100ms, 500}, {100ms, 600}, {3ms, 600}}, true}};
 
     for (const auto& test : testCases) {
         // reset actual duration
-        sendActualWorkDurationGroup({base}, 80ms);
+        sendActualWorkDurationGroup({base}, mStaleTimeout);
 
         auto raw = test.first;
         std::vector<WorkDuration> durations(raw.size());
         std::transform(raw.begin(), raw.end(), durations.begin(),
-                       [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
-                           return toWorkDuration(d.first, d.second);
-                       });
+                       [](auto d) { return toWorkDuration(d); });
         EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
                 .Times(test.second ? 1 : 0);
         sendActualWorkDurationGroup(durations, 0ms);
@@ -222,40 +228,6 @@
     }
 }
 
-TEST_F(AidlPowerHalWrapperTest, sendAdjustedActualWorkDuration) {
-    ASSERT_TRUE(mWrapper->supportsPowerHintSession());
-
-    std::vector<int32_t> threadIds = {1, 2};
-    mWrapper->setPowerHintSessionThreadIds(threadIds);
-    EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
-            .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
-    ASSERT_TRUE(mWrapper->startPowerHintSession());
-    verifyAndClearExpectations();
-
-    std::chrono::nanoseconds lastTarget = 100ms;
-    EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(lastTarget.count())).Times(1);
-    mWrapper->setTargetWorkDuration(lastTarget.count());
-    std::chrono::nanoseconds newTarget = 105ms;
-    mWrapper->setTargetWorkDuration(newTarget.count());
-    EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(newTarget.count())).Times(0);
-    std::chrono::nanoseconds actual = 21ms;
-    // 100 / 105 * 21ms = 20ms
-    std::chrono::nanoseconds expectedActualSent = 20ms;
-    std::vector<WorkDuration> expectedDurations = {toWorkDuration(expectedActualSent, 1)};
-
-    EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_))
-            .WillOnce(DoAll(
-                    [expectedDurations](const ::std::vector<WorkDuration>& durationsSent) {
-                        EXPECT_EQ(expectedDurations, durationsSent)
-                                << base::StringPrintf("actual sent: %s vs expected: %s",
-                                                      printWorkDurations(durationsSent).c_str(),
-                                                      printWorkDurations(expectedDurations)
-                                                              .c_str());
-                    },
-                    Return(Status::ok())));
-    mWrapper->sendActualWorkDuration(actual.count(), 1);
-}
-
 TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_exceedsStaleTime) {
     ASSERT_TRUE(mWrapper->supportsPowerHintSession());
 
@@ -269,22 +241,23 @@
     auto base = toWorkDuration(100ms, 0);
     // test cases with actual work durations and whether it should update hint against baseline
     // 100ms
-    const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
-            testCases = {{{{91ms, 100}}, true}, {{{109ms, 100}}, true}};
+    const std::vector<std::tuple<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>,
+                                 std::chrono::nanoseconds, bool>>
+            testCases = {{{{100ms, 100}}, mStaleTimeout, true},
+                         {{{100ms + (mAllowedDeviation / 2), 100}}, mStaleTimeout, true},
+                         {{{100ms, 100}}, mStaleTimeout / 2, false}};
 
     for (const auto& test : testCases) {
         // reset actual duration
-        sendActualWorkDurationGroup({base}, 80ms);
+        sendActualWorkDurationGroup({base}, mStaleTimeout);
 
-        auto raw = test.first;
+        auto raw = std::get<0>(test);
         std::vector<WorkDuration> durations(raw.size());
         std::transform(raw.begin(), raw.end(), durations.begin(),
-                       [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
-                           return toWorkDuration(d.first, d.second);
-                       });
+                       [](auto d) { return toWorkDuration(d); });
         EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
-                .Times(test.second ? 1 : 0);
-        sendActualWorkDurationGroup(durations, 80ms);
+                .Times(std::get<2>(test) ? 1 : 0);
+        sendActualWorkDurationGroup(durations, std::get<1>(test));
         verifyAndClearExpectations();
     }
 }
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index bbfedc7..19eaa19 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -37,7 +37,6 @@
 #include <system/window.h>
 #include <utils/String8.h>
 
-#include "BufferQueueLayer.h"
 #include "ContainerLayer.h"
 #include "DisplayRenderArea.h"
 #include "EffectLayer.h"
@@ -492,65 +491,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);
         Mock::VerifyAndClear(test->mRenderEngine);
     }
 
-    static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+    static void setupLayerState(CompositionTest* test, sp<BufferStateLayer> layer) {
         setupLatchedBuffer(test, layer);
     }
 
@@ -736,7 +701,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);
@@ -818,14 +783,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) {}
@@ -932,17 +897,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 new BufferStateLayer(args);
                 });
 
         LayerProperties::setupLayerState(test, layer);
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index c033af8..7ee04b0 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,8 +190,8 @@
 }
 
 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);
diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
index bb1f432..3a9b805 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"
@@ -51,6 +50,7 @@
 using android::Hwc2::IComposerClient;
 
 using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using gui::LayerMetadata;
 
 struct TestableFpsListener : public gui::BnFpsListener {
     TestableFpsListener() {}
@@ -153,7 +153,7 @@
     mParent = createBufferStateLayer();
     constexpr int32_t kTaskId = 12;
     LayerMetadata targetMetadata;
-    targetMetadata.setInt32(METADATA_TASK_ID, kTaskId);
+    targetMetadata.setInt32(gui::METADATA_TASK_ID, kTaskId);
     mTarget = createBufferStateLayer(targetMetadata);
     mChild = createBufferStateLayer();
     mGrandChild = createBufferStateLayer();
@@ -188,7 +188,7 @@
 TEST_F(FpsReporterTest, rateLimits) {
     const constexpr int32_t kTaskId = 12;
     LayerMetadata targetMetadata;
-    targetMetadata.setInt32(METADATA_TASK_ID, kTaskId);
+    targetMetadata.setInt32(gui::METADATA_TASK_ID, kTaskId);
     mTarget = createBufferStateLayer(targetMetadata);
     mFlinger.mutableCurrentState().layersSortedByZ.add(mTarget);
 
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index f1efa92..756db8a 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -217,9 +217,12 @@
 TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) {
     int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0});
     flushTokens();
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = token1;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame =
-            mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
-                                                       sLayerIdOne, sLayerNameOne, sLayerNameOne,
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
                                                        /*isBuffer*/ true, sGameMode);
 
     EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Expired);
@@ -227,9 +230,12 @@
 
 TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validToken) {
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = token1;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame =
-            mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
-                                                       sLayerIdOne, sLayerNameOne, sLayerNameOne,
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
                                                        /*isBuffer*/ true, sGameMode);
 
     EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Valid);
@@ -239,9 +245,12 @@
 TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validInputEventId) {
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     constexpr int32_t inputEventId = 1;
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = token1;
+    ftInfo.inputEventId = inputEventId;
     auto surfaceFrame =
-            mFrameTimeline->createSurfaceFrameForToken({token1, inputEventId}, sPidOne, sUidOne,
-                                                       sLayerIdOne, sLayerNameOne, sLayerNameOne,
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
                                                        /*isBuffer*/ true, sGameMode);
 
     EXPECT_EQ(inputEventId, surfaceFrame->getInputEventId());
@@ -250,9 +259,12 @@
 TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) {
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = token1;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
-                                                       sLayerIdOne, sLayerNameOne, sLayerNameOne,
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
                                                        /*isBuffer*/ true, sGameMode);
 
     // Set up the display frame
@@ -278,14 +290,17 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     auto surfaceFrame2 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdTwo, sLayerNameTwo,
-                                                       sLayerNameTwo, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdTwo,
+                                                       sLayerNameTwo, sLayerNameTwo,
+                                                       /*isBuffer*/ true, sGameMode);
     mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
@@ -324,9 +339,11 @@
                 {10 + frameTimeFactor, 20 + frameTimeFactor, 30 + frameTimeFactor});
         int64_t sfToken = mTokenManager->generateTokenForPredictions(
                 {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor});
+        FrameTimelineInfo ftInfo;
+        ftInfo.vsyncId = surfaceFrameToken;
+        ftInfo.inputEventId = sInputEventId;
         auto surfaceFrame =
-                mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId},
-                                                           sPidOne, sUidOne, sLayerIdOne,
+                mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
                                                            sLayerNameOne, sLayerNameOne,
                                                            /*isBuffer*/ true, sGameMode);
         mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11));
@@ -347,10 +364,13 @@
             {10 + frameTimeFactor, 20 + frameTimeFactor, 30 + frameTimeFactor});
     int64_t sfToken = mTokenManager->generateTokenForPredictions(
             {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11));
     surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame);
@@ -442,11 +462,14 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
 
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
     surfaceFrame1->setAcquireFenceTime(20);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -470,11 +493,14 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = -1;
     int64_t sfToken1 = -1;
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
 
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
     surfaceFrame1->setAcquireFenceTime(20);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -495,11 +521,14 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
 
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
     surfaceFrame1->setAcquireFenceTime(20);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -521,11 +550,14 @@
     auto gpuFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
 
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
     surfaceFrame1->setAcquireFenceTime(20);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -546,11 +578,14 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
 
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     surfaceFrame1->setAcquireFenceTime(20);
@@ -570,11 +605,14 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
 
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setAcquireFenceTime(45);
     mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
 
@@ -596,11 +634,14 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({40, 60, 92});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
 
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setAcquireFenceTime(50);
     mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
 
@@ -622,11 +663,14 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 60});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
 
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setAcquireFenceTime(40);
     mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
 
@@ -648,11 +692,14 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 58});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
 
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setAcquireFenceTime(40);
     mFrameTimeline->setSfWakeUp(sfToken1, 82, refreshRate);
 
@@ -676,11 +723,14 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
 
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setAcquireFenceTime(45);
     mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
 
@@ -706,11 +756,14 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
 
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setAcquireFenceTime(45);
     // Trigger a prediction expiry
     flushTokens();
@@ -744,9 +797,12 @@
     auto tracingSession = getTracingSessionForTest();
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = token1;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
-                                                       sLayerIdOne, sLayerNameOne, sLayerNameOne,
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
                                                        /*isBuffer*/ true, sGameMode);
 
     // Set up the display frame
@@ -771,9 +827,12 @@
     tracingSession->StartBlocking();
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = token1;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
-                                                       sLayerIdOne, sLayerNameOne, sLayerNameOne,
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
                                                        /*isBuffer*/ true, sGameMode);
 
     // Set up the display frame
@@ -1133,14 +1192,18 @@
     int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 25, 40});
     int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({30, 35, 40});
 
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken;
+    ftInfo.inputEventId = sInputEventId;
+
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     auto surfaceFrame2 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setActualQueueTime(10);
     surfaceFrame1->setDropTime(15);
 
@@ -1293,10 +1356,13 @@
 
     // Flush the token so that it would expire
     flushTokens();
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken;
+    ftInfo.inputEventId = 0;
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0},
-                                                       sPidOne, sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setActualQueueTime(appEndTime);
     surfaceFrame1->setAcquireFenceTime(appEndTime);
 
@@ -1369,10 +1435,13 @@
 
     // Flush the token so that it would expire
     flushTokens();
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken;
+    ftInfo.inputEventId = 0;
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0},
-                                                       sPidOne, sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
 
     constexpr nsecs_t sfStartTime = std::chrono::nanoseconds(22ms).count();
     constexpr nsecs_t sfEndTime = std::chrono::nanoseconds(30ms).count();
@@ -1438,10 +1507,13 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 30});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame);
@@ -1654,10 +1726,13 @@
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70});
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40});
     int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setAcquireFenceTime(16);
     mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1674,10 +1749,13 @@
 
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    FrameTimelineInfo ftInfo2;
+    ftInfo2.vsyncId = surfaceFrameToken2;
+    ftInfo2.inputEventId = sInputEventId;
     auto surfaceFrame2 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame2->setAcquireFenceTime(36);
     mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1734,10 +1812,13 @@
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70});
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40});
     int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setAcquireFenceTime(16);
     mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1754,10 +1835,13 @@
 
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    FrameTimelineInfo ftInfo2;
+    ftInfo2.vsyncId = surfaceFrameToken2;
+    ftInfo2.inputEventId = sInputEventId;
     auto surfaceFrame2 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame2->setAcquireFenceTime(36);
     mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1813,10 +1897,13 @@
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 50, 50});
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setAcquireFenceTime(40);
     mFrameTimeline->setSfWakeUp(sfToken1, 42, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1857,10 +1944,13 @@
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({42, 50, 50});
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 30});
     int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 50});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setAcquireFenceTime(26);
     mFrameTimeline->setSfWakeUp(sfToken1, 32, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1877,10 +1967,13 @@
 
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    FrameTimelineInfo ftInfo2;
+    ftInfo2.vsyncId = surfaceFrameToken2;
+    ftInfo2.inputEventId = sInputEventId;
     auto surfaceFrame2 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame2->setAcquireFenceTime(40);
     mFrameTimeline->setSfWakeUp(sfToken2, 43, Fps::fromPeriodNsecs(11));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1932,10 +2025,13 @@
 
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({112, 120, 120});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setAcquireFenceTime(50);
     mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1952,10 +2048,13 @@
 
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    FrameTimelineInfo ftInfo2;
+    ftInfo2.vsyncId = surfaceFrameToken2;
+    ftInfo2.inputEventId = sInputEventId;
     auto surfaceFrame2 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame2->setAcquireFenceTime(84);
     mFrameTimeline->setSfWakeUp(sfToken2, 112, Fps::fromPeriodNsecs(30));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54);
@@ -2010,10 +2109,13 @@
 
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+    FrameTimelineInfo ftInfo;
+    ftInfo.vsyncId = surfaceFrameToken1;
+    ftInfo.inputEventId = sInputEventId;
     auto surfaceFrame1 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame1->setAcquireFenceTime(50);
     mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -2030,10 +2132,13 @@
 
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    FrameTimelineInfo ftInfo2;
+    ftInfo2.vsyncId = surfaceFrameToken2;
+    ftInfo2.inputEventId = sInputEventId;
     auto surfaceFrame2 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerIdOne, sLayerNameOne,
-                                                       sLayerNameOne, /*isBuffer*/ true, sGameMode);
+            mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne,
+                                                       sLayerNameOne, sLayerNameOne,
+                                                       /*isBuffer*/ true, sGameMode);
     surfaceFrame2->setAcquireFenceTime(80);
     mFrameTimeline->setSfWakeUp(sfToken2, 82, Fps::fromPeriodNsecs(30));
     // Setting previous latch time to 54, adjusted deadline will be 54 + vsyncTime(30) = 84
@@ -2237,4 +2342,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 981ca1d..b79909a 100644
--- a/services/surfaceflinger/tests/unittests/GameModeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp
@@ -34,6 +34,8 @@
 using testing::Mock;
 using testing::Return;
 using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using gui::GameMode;
+using gui::LayerMetadata;
 
 class GameModeTest : public testing::Test {
 public:
@@ -92,7 +94,7 @@
 
     // Mocks the behavior of applying a transaction from WMShell
     void setGameModeMetadata(sp<Layer> layer, GameMode gameMode) {
-        mLayerMetadata.setInt32(METADATA_GAME_MODE, static_cast<int32_t>(gameMode));
+        mLayerMetadata.setInt32(gui::METADATA_GAME_MODE, static_cast<int32_t>(gameMode));
         layer->setMetadata(mLayerMetadata);
         layer->setGameModeForTree(gameMode);
     }
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/LayerMetadataTest.cpp b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
index 373fd74..e6e02c1 100644
--- a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
@@ -27,6 +27,8 @@
 #include <gui/LayerMetadata.h>
 #include <log/log.h>
 
+using android::gui::LayerMetadata;
+
 namespace android {
 namespace {
 
@@ -113,4 +115,4 @@
 } // namespace android
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index aab2795..93c809e 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -159,8 +159,8 @@
     mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
     ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
 
-    constexpr bool kPowerStateNormal = true;
-    mScheduler->setDisplayPowerState(kPowerStateNormal);
+    constexpr hal::PowerMode kPowerModeOn = hal::PowerMode::ON;
+    mScheduler->setDisplayPowerMode(kPowerModeOn);
 
     constexpr uint32_t kDisplayArea = 999'999;
     mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
@@ -226,8 +226,8 @@
 
     mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
 
-    constexpr bool kPowerStateNormal = true;
-    mScheduler->setDisplayPowerState(kPowerStateNormal);
+    constexpr hal::PowerMode kPowerModeOn = hal::PowerMode::ON;
+    mScheduler->setDisplayPowerMode(kPowerModeOn);
 
     constexpr uint32_t kDisplayArea = 999'999;
     mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
index 8de9e4b..c2d87f2 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
@@ -74,6 +74,7 @@
     mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
     mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
     mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+    mFlinger.setPowerHintSessionMode(true, true);
     mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor));
     static constexpr bool kIsPrimary = true;
     FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, hal::DisplayType::PHYSICAL, kIsPrimary)
@@ -142,10 +143,7 @@
                 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())))
-            .Times(1);
+    EXPECT_CALL(*mPowerAdvisor, sendActualWorkDuration()).Times(1);
     static constexpr bool kVsyncId = 123; // arbitrary
     mFlinger.commitAndComposite(now, kVsyncId, now + mockVsyncPeriod.count());
 }
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index f1a69fb..3a05e2f 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -29,7 +29,6 @@
 #include <compositionengine/mock/DisplaySurface.h>
 #include <gui/ScreenCaptureResults.h>
 
-#include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
 #include "ContainerLayer.h"
 #include "DisplayDevice.h"
@@ -134,10 +133,6 @@
         return compositionengine::impl::createCompositionEngine();
     }
 
-    sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
-        return nullptr;
-    }
-
     sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs&) override {
         return nullptr;
     }
@@ -330,6 +325,10 @@
         layer->mDrawingParent = drawingParent;
     }
 
+    void setPowerHintSessionMode(bool early, bool late) {
+        mFlinger->mPowerHintSessionMode = {.late = late, .early = early};
+    }
+
     /* ------------------------------------------------------------------------
      * Forwarding for functions being tested
      */
@@ -456,7 +455,7 @@
         return mFlinger->onTransact(code, data, reply, flags);
     }
 
-    auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); }
+    auto getGpuContextPriority() { return mFlinger->getGpuContextPriority(); }
 
     auto calculateMaxAcquiredBufferCount(Fps refreshRate,
                                          std::chrono::nanoseconds presentLatency) const {
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index ded7531..84f1170 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -107,22 +107,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) {
+    void NotPlacedOnTransactionQueue(uint32_t flags) {
         ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
         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,12 +131,10 @@
                                      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());
@@ -148,7 +144,7 @@
         EXPECT_EQ(1u, transactionQueue.size());
     }
 
-    void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
+    void PlaceOnTransactionQueue(uint32_t flags) {
         ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
         EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
@@ -156,8 +152,8 @@
         // 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 +163,7 @@
                                      transaction.id);
 
         nsecs_t returnedTime = systemTime();
-        if ((flags & ISurfaceComposer::eSynchronous) || syncInputWindows) {
+        if (flags & ISurfaceComposer::eSynchronous) {
             EXPECT_GE(systemTime(),
                       applicationSentTime + mFlinger.getAnimationTransactionTimeout());
         } else {
@@ -179,25 +175,21 @@
         EXPECT_EQ(1u, transactionQueue.size());
     }
 
-    void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
+    void BlockedByPriorTransaction(uint32_t flags) {
         ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
         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 +218,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 {
@@ -253,8 +244,8 @@
     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,
@@ -285,31 +276,23 @@
 }
 
 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) {
@@ -359,13 +342,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);
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index f5e3b77..669fa3a 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -49,8 +49,7 @@
         ComposerState s;
         if (i == 1) {
             layer.parentSurfaceControlForChild =
-                    new SurfaceControl(SurfaceComposerClient::getDefault(), layerHandle, nullptr,
-                                       42);
+                    new SurfaceControl(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 5bb4c92..6d58303 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -100,8 +100,10 @@
 
     void PresentedSurfaceFrameForBufferlessTransaction() {
         sp<BufferStateLayer> layer = createBufferStateLayer();
-        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
-                                                             10);
+        FrameTimelineInfo ftInfo;
+        ftInfo.vsyncId = 1;
+        ftInfo.inputEventId = 0;
+        layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo, 10);
         EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_TRUE(layer->mDrawingState.bufferSurfaceFrameTX == nullptr);
         const auto surfaceFrame = layer->mDrawingState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
@@ -125,8 +127,10 @@
                                                          1ULL /* bufferId */,
                                                          HAL_PIXEL_FORMAT_RGBA_8888,
                                                          0ULL /*usage*/);
-        layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        FrameTimelineInfo ftInfo;
+        ftInfo.vsyncId = 1;
+        ftInfo.inputEventId = 0;
+        layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo);
         acquireFence->signalForTest(12);
 
         commitTransaction(layer.get());
@@ -159,8 +163,10 @@
                                                          1ULL /* bufferId */,
                                                          HAL_PIXEL_FORMAT_RGBA_8888,
                                                          0ULL /*usage*/);
-        layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        FrameTimelineInfo ftInfo;
+        ftInfo.vsyncId = 1;
+        ftInfo.inputEventId = 0;
+        layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo);
         EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -177,8 +183,7 @@
                                                          2ULL /* bufferId */,
                                                          HAL_PIXEL_FORMAT_RGBA_8888,
                                                          0ULL /*usage*/);
-        layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfo);
         nsecs_t end = systemTime();
         acquireFence2->signalForTest(12);
 
@@ -204,9 +209,11 @@
 
     void BufferlessSurfaceFramePromotedToBufferSurfaceFrame() {
         sp<BufferStateLayer> layer = createBufferStateLayer();
+        FrameTimelineInfo ftInfo;
+        ftInfo.vsyncId = 1;
+        ftInfo.inputEventId = 0;
 
-        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
-                                                             10);
+        layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo, 10);
 
         EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_EQ(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -223,8 +230,7 @@
                                                          1ULL /* bufferId */,
                                                          HAL_PIXEL_FORMAT_RGBA_8888,
                                                          0ULL /*usage*/);
-        layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo);
         acquireFence->signalForTest(12);
 
         EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
@@ -257,28 +263,33 @@
                                                          1ULL /* bufferId */,
                                                          HAL_PIXEL_FORMAT_RGBA_8888,
                                                          0ULL /*usage*/);
-        layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        FrameTimelineInfo ftInfo;
+        ftInfo.vsyncId = 1;
+        ftInfo.inputEventId = 0;
+        layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo);
         EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
 
-        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
-                                                             10);
+        layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo, 10);
         EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
     }
 
     void MultipleSurfaceFramesPresentedTogether() {
         sp<BufferStateLayer> layer = createBufferStateLayer();
-        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
-                                                             10);
+        FrameTimelineInfo ftInfo;
+        ftInfo.vsyncId = 1;
+        ftInfo.inputEventId = 0;
+        layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo, 10);
         EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_EQ(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto bufferlessSurfaceFrame1 =
                 layer->mDrawingState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
 
-        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 4, /*inputEventId*/ 0},
-                                                             10);
+        FrameTimelineInfo ftInfo2;
+        ftInfo2.vsyncId = 4;
+        ftInfo2.inputEventId = 0;
+        layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo2, 10);
         EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_EQ(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto bufferlessSurfaceFrame2 = layer->mDrawingState.bufferlessSurfaceFramesTX[4];
@@ -295,8 +306,10 @@
                                                          1ULL /* bufferId */,
                                                          HAL_PIXEL_FORMAT_RGBA_8888,
                                                          0ULL /*usage*/);
-        layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt,
-                         {/*vsyncId*/ 3, /*inputEventId*/ 0});
+        FrameTimelineInfo ftInfo3;
+        ftInfo3.vsyncId = 3;
+        ftInfo3.inputEventId = 0;
+        layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo3);
         EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto bufferSurfaceFrameTX = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -339,8 +352,10 @@
                                                          1ULL /* bufferId */,
                                                          HAL_PIXEL_FORMAT_RGBA_8888,
                                                          0ULL /*usage*/);
-        layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        FrameTimelineInfo ftInfo;
+        ftInfo.vsyncId = 1;
+        ftInfo.inputEventId = 0;
+        layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo);
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
 
@@ -355,8 +370,7 @@
                                                          1ULL /* bufferId */,
                                                          HAL_PIXEL_FORMAT_RGBA_8888,
                                                          0ULL /*usage*/);
-        layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfo);
         acquireFence2->signalForTest(12);
 
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -391,8 +405,10 @@
                                                          1ULL /* bufferId */,
                                                          HAL_PIXEL_FORMAT_RGBA_8888,
                                                          0ULL /*usage*/);
-        layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        FrameTimelineInfo ftInfo;
+        ftInfo.vsyncId = 1;
+        ftInfo.inputEventId = 0;
+        layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo);
         EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto droppedSurfaceFrame1 = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -409,8 +425,10 @@
                                                          1ULL /* bufferId */,
                                                          HAL_PIXEL_FORMAT_RGBA_8888,
                                                          0ULL /*usage*/);
-        layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt,
-                         {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0});
+        FrameTimelineInfo ftInfoInv;
+        ftInfoInv.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID;
+        ftInfoInv.inputEventId = 0;
+        layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfoInv);
         auto dropEndTime1 = systemTime();
         EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -428,8 +446,10 @@
                                                          1ULL /* bufferId */,
                                                          HAL_PIXEL_FORMAT_RGBA_8888,
                                                          0ULL /*usage*/);
-        layer->setBuffer(externalTexture3, bufferData, 10, 20, false, std::nullopt,
-                         {/*vsyncId*/ 2, /*inputEventId*/ 0});
+        FrameTimelineInfo ftInfo2;
+        ftInfo2.vsyncId = 2;
+        ftInfo2.inputEventId = 0;
+        layer->setBuffer(externalTexture3, bufferData, 10, 20, false, std::nullopt, ftInfo2);
         auto dropEndTime2 = systemTime();
         acquireFence3->signalForTest(12);
 
@@ -476,11 +496,14 @@
                                                              1ULL /* bufferId */,
                                                              HAL_PIXEL_FORMAT_RGBA_8888,
                                                              0ULL /*usage*/);
-            layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt,
-                             {/*vsyncId*/ 1, /*inputEventId*/ 0});
-            layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2,
-                                                                  /*inputEventId*/ 0},
-                                                                 10);
+            FrameTimelineInfo ftInfo;
+            ftInfo.vsyncId = 1;
+            ftInfo.inputEventId = 0;
+            layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo);
+            FrameTimelineInfo ftInfo2;
+            ftInfo2.vsyncId = 2;
+            ftInfo2.inputEventId = 0;
+            layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo2, 10);
             ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
             EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
             auto& bufferlessSurfaceFrame =
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index 61b72a0..8ec918d 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -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);
         }
@@ -238,6 +240,8 @@
         const sp<IBinder> fakeMirrorLayerHandle = new BBinder();
         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/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 4eb9055..30a3f9a 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -349,6 +349,23 @@
     }
 }
 
+TEST_F(VSyncReactorTest, addHwVsyncTimestampDozePreempt) {
+    bool periodFlushed = false;
+    nsecs_t const newPeriod = 4000;
+
+    mReactor.startPeriodTransition(newPeriod);
+
+    auto time = 0;
+    // If the power mode is not DOZE or DOZE_SUSPEND, it is still collecting timestamps.
+    EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+
+    // Set power mode to DOZE to trigger period flushing.
+    mReactor.setDisplayPowerMode(hal::PowerMode::DOZE);
+    EXPECT_FALSE(mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed));
+    EXPECT_TRUE(periodFlushed);
+}
+
 TEST_F(VSyncReactorTest, addPresentFenceWhileAwaitingPeriodConfirmationRequestsHwVsync) {
     auto time = 0;
     bool periodFlushed = false;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index c598cbc..d6dca45 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -36,11 +36,32 @@
     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, setPresentFenceTime, (nsecs_t presentFenceTime), (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..d30dc42 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -28,8 +28,7 @@
     ~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 f879430..6ada549 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -15,6 +15,7 @@
  */
 #pragma once
 
+#include <gui/AidlStatusUtil.h>
 #include <gui/SyncScreenCaptureListener.h>
 #include <private/gui/ComposerServiceAIDL.h>
 #include <ui/Rect.h>
@@ -24,6 +25,8 @@
 
 namespace android {
 
+using gui::aidl_utils::statusTFromBinderStatus;
+
 namespace {
 
 // A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
@@ -38,9 +41,9 @@
         captureArgs.dataspace = ui::Dataspace::V0_SRGB;
         const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
         binder::Status status = sf->captureDisplay(captureArgs, captureListener);
-
-        if (status.transactionError() != NO_ERROR) {
-            return status.transactionError();
+        status_t err = statusTFromBinderStatus(status);
+        if (err != NO_ERROR) {
+            return err;
         }
         captureResults = captureListener->waitForResults();
         return captureResults.result;
@@ -72,8 +75,9 @@
         captureArgs.dataspace = ui::Dataspace::V0_SRGB;
         const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
         binder::Status status = sf->captureLayers(captureArgs, captureListener);
-        if (status.transactionError() != NO_ERROR) {
-            return status.transactionError();
+        status_t err = statusTFromBinderStatus(status);
+        if (err != NO_ERROR) {
+            return err;
         }
         captureResults = captureListener->waitForResults();
         return captureResults.result;
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..eb669c0 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -763,7 +763,11 @@
     // We must support R8G8B8A8
     std::vector<VkSurfaceFormatKHR> all_formats = {
         {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}};
+        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+        // Also allow to use PASS_THROUGH + HAL_DATASPACE_ARBITRARY
+        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT},
+        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_PASS_THROUGH_EXT},
+    };
 
     if (colorspace_ext) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
@@ -939,8 +943,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();
@@ -1844,6 +1847,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",