Merge changes from topic "hardware_sensor_privacy_apis"

* changes:
  Upadate sensor service to use new sensor privacy api
  Sync native sensor privacy aidl with frameworks/base
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index a951c4f..1003aae 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1087,7 +1087,7 @@
     RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"});
 }
 
-static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
+static void AddAnrTraceDir(const std::string& anr_traces_dir) {
     MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
            anr_traces_dir.c_str());
 
@@ -1095,13 +1095,9 @@
     // (created with mkostemp or similar) that contains dumps taken earlier
     // on in the process.
     if (dump_traces_path != nullptr) {
-        if (add_to_zip) {
-            ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
-        } else {
-            MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
-                   dump_traces_path);
-            ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
-        }
+        MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
+                dump_traces_path);
+        ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
 
         const int ret = unlink(dump_traces_path);
         if (ret == -1) {
@@ -1112,14 +1108,12 @@
 
     // Add a specific message for the first ANR Dump.
     if (ds.anr_data_.size() > 0) {
+        // The "last" ANR will always be present in the body of the main entry.
         AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
-                 "VM TRACES AT LAST ANR", add_to_zip);
+                 "VM TRACES AT LAST ANR", false /* add_to_zip */);
 
-        // The "last" ANR will always be included as separate entry in the zip file. In addition,
-        // it will be present in the body of the main entry if |add_to_zip| == false.
-        //
         // Historical ANRs are always included as separate entries in the bugreport zip file.
-        AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
+        AddDumps(ds.anr_data_.begin(), ds.anr_data_.end(),
                  "HISTORICAL ANR", true /* add_to_zip */);
     } else {
         printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
@@ -1127,11 +1121,9 @@
 }
 
 static void AddAnrTraceFiles() {
-    const bool add_to_zip = ds.version_ == VERSION_SPLIT_ANR;
-
     std::string anr_traces_dir = "/data/anr";
 
-    AddAnrTraceDir(add_to_zip, anr_traces_dir);
+    AddAnrTraceDir(anr_traces_dir);
 
     RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
 
@@ -1590,7 +1582,6 @@
     DumpFile("BUDDYINFO", "/proc/buddyinfo");
     DumpExternalFragmentationInfo();
 
-    DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
     DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
 
     RunCommand("PROCESSES AND THREADS",
@@ -2906,10 +2897,9 @@
         version_ = VERSION_CURRENT;
     }
 
-    if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
-        MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
-               version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
-               VERSION_SPLIT_ANR.c_str());
+    if (version_ != VERSION_CURRENT) {
+        MYLOGE("invalid version requested ('%s'); supported values are: ('%s', '%s')\n",
+               version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str());
         return RunStatus::INVALID_INPUT;
     }
 
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index d0acb31..4a99cd8 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -157,12 +157,6 @@
 static std::string VERSION_CURRENT = "2.0";
 
 /*
- * Temporary version that adds a anr-traces.txt entry. Once tools support it, the current version
- * will be bumped to 3.0.
- */
-static std::string VERSION_SPLIT_ANR = "3.0-dev-split-anr";
-
-/*
  * "Alias" for the current version.
  */
 static std::string VERSION_DEFAULT = "default";
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 00babc3..fd38ddf 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -10,6 +10,7 @@
 cc_defaults {
     name: "installd_defaults",
 
+    cpp_std: "c++2a",
     cflags: [
         "-Wall",
         "-Werror",
@@ -41,6 +42,7 @@
         "libbinder",
         "libcrypto",
         "libcutils",
+        "libext2_uuid",
         "liblog",
         "liblogwrap",
         "libprocessgroup",
@@ -239,6 +241,8 @@
 
 cc_binary {
     name: "otapreopt",
+
+    cpp_std: "c++2a",
     cflags: [
         "-Wall",
         "-Werror",
@@ -268,6 +272,7 @@
         "libbase",
         "libcrypto",
         "libcutils",
+        "libext2_uuid",
         "liblog",
         "liblogwrap",
         "libprocessgroup",
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 2207405..f0dcd02 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -103,11 +103,6 @@
 static constexpr const char* CACHE_DIR_POSTFIX = "/cache";
 static constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache";
 
-// fsverity assumes the page size is always 4096. If not, the feature can not be
-// enabled.
-static constexpr int kVerityPageSize = 4096;
-static constexpr size_t kSha256Size = 32;
-static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode";
 static constexpr const char* kFuseProp = "persist.sys.fuse";
 
 /**
@@ -261,12 +256,6 @@
     }                                                       \
 }
 
-#define ASSERT_PAGE_SIZE_4K() {                             \
-    if (getpagesize() != kVerityPageSize) {                 \
-        return error("FSVerity only supports 4K pages");     \
-    }                                                       \
-}
-
 #ifdef GRANULAR_LOCKS
 
 /**
@@ -698,9 +687,6 @@
         if (!status.isOk()) {
             return status;
         }
-        if (previousUid != uid) {
-            chown_app_profile_dir(packageName, appId, userId);
-        }
 
         // Remember inode numbers of cache directories so that we can clear
         // contents while CE storage is locked
@@ -726,6 +712,9 @@
         if (!status.isOk()) {
             return status;
         }
+        if (previousUid != uid) {
+            chown_app_profile_dir(packageName, appId, userId);
+        }
 
         if (!prepare_app_profile_dir(packageName, appId, userId)) {
             return error("Failed to prepare profiles for " + packageName);
@@ -968,13 +957,13 @@
     binder::Status res = ok();
     if (flags & FLAG_STORAGE_CE) {
         auto path = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
-        if (delete_dir_contents_and_dir(path) != 0) {
+        if (rename_delete_dir_contents_and_dir(path) != 0) {
             res = error("Failed to delete " + path);
         }
     }
     if (flags & FLAG_STORAGE_DE) {
         auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
-        if (delete_dir_contents_and_dir(path) != 0) {
+        if (rename_delete_dir_contents_and_dir(path) != 0) {
             res = error("Failed to delete " + path);
         }
         if ((flags & FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
@@ -1005,16 +994,15 @@
             }
 
             auto path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
-            if (delete_dir_contents_and_dir(path, true) != 0) {
+            if (rename_delete_dir_contents_and_dir(path, true) != 0) {
                 res = error("Failed to delete contents of " + path);
             }
-
             path = StringPrintf("%s/Android/media/%s", extPath.c_str(), pkgname);
-            if (delete_dir_contents_and_dir(path, true) != 0) {
+            if (rename_delete_dir_contents_and_dir(path, true) != 0) {
                 res = error("Failed to delete contents of " + path);
             }
             path = StringPrintf("%s/Android/obb/%s", extPath.c_str(), pkgname);
-            if (delete_dir_contents_and_dir(path, true) != 0) {
+            if (rename_delete_dir_contents_and_dir(path, true) != 0) {
                 res = error("Failed to delete contents of " + path);
             }
         }
@@ -1562,27 +1550,27 @@
     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) {
+        if (rename_delete_dir_contents_and_dir(path, true) != 0) {
             res = error("Failed to delete " + path);
         }
         if (uuid_ == nullptr) {
             path = create_data_misc_legacy_path(userId);
-            if (delete_dir_contents_and_dir(path, true) != 0) {
+            if (rename_delete_dir_contents_and_dir(path, true) != 0) {
                 res = error("Failed to delete " + path);
             }
             path = create_primary_cur_profile_dir_path(userId);
-            if (delete_dir_contents_and_dir(path, true) != 0) {
+            if (rename_delete_dir_contents_and_dir(path, true) != 0) {
                 res = error("Failed to delete " + path);
             }
         }
     }
     if (flags & FLAG_STORAGE_CE) {
         auto path = create_data_user_ce_path(uuid_, userId);
-        if (delete_dir_contents_and_dir(path, true) != 0) {
+        if (rename_delete_dir_contents_and_dir(path, true) != 0) {
             res = error("Failed to delete " + path);
         }
         path = findDataMediaPath(uuid, userId);
-        if (delete_dir_contents_and_dir(path, true) != 0) {
+        if (rename_delete_dir_contents_and_dir(path, true) != 0) {
             res = error("Failed to delete " + path);
         }
     }
@@ -2972,147 +2960,6 @@
     return *_aidl_return == -1 ? error() : ok();
 }
 
-// This kernel feature is experimental.
-// TODO: remove local definition once upstreamed
-#ifndef FS_IOC_ENABLE_VERITY
-
-#define FS_IOC_ENABLE_VERITY           _IO('f', 133)
-#define FS_IOC_SET_VERITY_MEASUREMENT  _IOW('f', 134, struct fsverity_measurement)
-
-#define FS_VERITY_ALG_SHA256           1
-
-struct fsverity_measurement {
-    __u16 digest_algorithm;
-    __u16 digest_size;
-    __u32 reserved1;
-    __u64 reserved2[3];
-    __u8 digest[];
-};
-
-#endif
-
-binder::Status InstalldNativeService::installApkVerity(const std::string& packageName,
-                                                       const std::string& filePath,
-                                                       android::base::unique_fd verityInputAshmem,
-                                                       int32_t contentSize) {
-    ENFORCE_UID(AID_SYSTEM);
-    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
-    CHECK_ARGUMENT_PATH(filePath);
-    LOCK_PACKAGE();
-
-    if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) {
-        return ok();
-    }
-#ifndef NDEBUG
-    ASSERT_PAGE_SIZE_4K();
-#endif
-    // TODO: also check fsverity support in the current file system if compiled with DEBUG.
-    // TODO: change ashmem to some temporary file to support huge apk.
-    if (!ashmem_valid(verityInputAshmem.get())) {
-        return error("FD is not an ashmem");
-    }
-
-    // 1. Seek to the next page boundary beyond the end of the file.
-    ::android::base::unique_fd wfd(open(filePath.c_str(), O_WRONLY));
-    if (wfd.get() < 0) {
-        return error("Failed to open " + filePath);
-    }
-    struct stat st;
-    if (fstat(wfd.get(), &st) < 0) {
-        return error("Failed to stat " + filePath);
-    }
-    // fsverity starts from the block boundary.
-    off_t padding = kVerityPageSize - st.st_size % kVerityPageSize;
-    if (padding == kVerityPageSize) {
-        padding = 0;
-    }
-    if (lseek(wfd.get(), st.st_size + padding, SEEK_SET) < 0) {
-        return error("Failed to lseek " + filePath);
-    }
-
-    // 2. Write everything in the ashmem to the file.  Note that allocated
-    //    ashmem size is multiple of page size, which is different from the
-    //    actual content size.
-    int shmSize = ashmem_get_size_region(verityInputAshmem.get());
-    if (shmSize < 0) {
-        return error("Failed to get ashmem size: " + std::to_string(shmSize));
-    }
-    if (contentSize < 0) {
-        return error("Invalid content size: " + std::to_string(contentSize));
-    }
-    if (contentSize > shmSize) {
-        return error("Content size overflow: " + std::to_string(contentSize) + " > " +
-                     std::to_string(shmSize));
-    }
-    auto data = std::unique_ptr<void, std::function<void (void *)>>(
-        mmap(nullptr, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0),
-        [contentSize] (void* ptr) {
-          if (ptr != MAP_FAILED) {
-            munmap(ptr, contentSize);
-          }
-        });
-
-    if (data.get() == MAP_FAILED) {
-        return error("Failed to mmap the ashmem");
-    }
-    char* cursor = reinterpret_cast<char*>(data.get());
-    int remaining = contentSize;
-    while (remaining > 0) {
-        int ret = TEMP_FAILURE_RETRY(write(wfd.get(), cursor, remaining));
-        if (ret < 0) {
-            return error("Failed to write to " + filePath + " (" + std::to_string(remaining) +
-                         + "/" + std::to_string(contentSize) + ")");
-        }
-        cursor += ret;
-        remaining -= ret;
-    }
-    wfd.reset();
-
-    // 3. Enable fsverity (needs readonly fd. Once it's done, the file becomes immutable.
-    ::android::base::unique_fd rfd(open(filePath.c_str(), O_RDONLY));
-    if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) {
-        return error("Failed to enable fsverity on " + filePath);
-    }
-    return ok();
-}
-
-binder::Status InstalldNativeService::assertFsverityRootHashMatches(
-        const std::string& packageName, const std::string& filePath,
-        const std::vector<uint8_t>& expectedHash) {
-    ENFORCE_UID(AID_SYSTEM);
-    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
-    CHECK_ARGUMENT_PATH(filePath);
-    LOCK_PACKAGE();
-
-    if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) {
-        return ok();
-    }
-    // TODO: also check fsverity support in the current file system if compiled with DEBUG.
-    if (expectedHash.size() != kSha256Size) {
-        return error("verity hash size should be " + std::to_string(kSha256Size) + " but is " +
-                     std::to_string(expectedHash.size()));
-    }
-
-    ::android::base::unique_fd fd(open(filePath.c_str(), O_RDONLY));
-    if (fd.get() < 0) {
-        return error("Failed to open " + filePath + ": " + strerror(errno));
-    }
-
-    unsigned int buffer_size = sizeof(fsverity_measurement) + kSha256Size;
-    std::vector<char> buffer(buffer_size, 0);
-
-    fsverity_measurement* config = reinterpret_cast<fsverity_measurement*>(buffer.data());
-    config->digest_algorithm = FS_VERITY_ALG_SHA256;
-    config->digest_size = kSha256Size;
-    memcpy(config->digest, expectedHash.data(), kSha256Size);
-    if (ioctl(fd.get(), FS_IOC_SET_VERITY_MEASUREMENT, config) < 0) {
-        // This includes an expected failure case with no FSVerity setup. It normally happens when
-        // the apk does not contains the Merkle tree root hash.
-        return error("Failed to measure fsverity on " + filePath + ": " + strerror(errno));
-    }
-    return ok();  // hashes match
-}
-
 binder::Status InstalldNativeService::reconcileSecondaryDexFile(
         const std::string& dexPath, const std::string& packageName, int32_t uid,
         const std::vector<std::string>& isas, const std::optional<std::string>& volumeUuid,
@@ -3342,5 +3189,22 @@
     return ok();
 }
 
+binder::Status InstalldNativeService::cleanupInvalidPackageDirs(
+        const std::optional<std::string>& uuid, int32_t userId, int32_t flags) {
+    const char* uuid_cstr = uuid ? uuid->c_str() : nullptr;
+
+    if (flags & FLAG_STORAGE_CE) {
+        auto ce_path = create_data_user_ce_path(uuid_cstr, userId);
+        cleanup_invalid_package_dirs_under_path(ce_path);
+    }
+
+    if (flags & FLAG_STORAGE_DE) {
+        auto de_path = create_data_user_de_path(uuid_cstr, userId);
+        cleanup_invalid_package_dirs_under_path(de_path);
+    }
+
+    return ok();
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 04662ea..ecc60b5 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -165,11 +165,6 @@
     binder::Status deleteOdex(const std::string& packageName, const std::string& apkPath,
                               const std::string& instructionSet,
                               const std::optional<std::string>& outputPath, int64_t* _aidl_return);
-    binder::Status installApkVerity(const std::string& packageName, const std::string& filePath,
-                                    android::base::unique_fd verityInput, int32_t contentSize);
-    binder::Status assertFsverityRootHashMatches(const std::string& packageName,
-                                                 const std::string& filePath,
-                                                 const std::vector<uint8_t>& expectedHash);
     binder::Status reconcileSecondaryDexFile(const std::string& dexPath,
         const std::string& packageName, int32_t uid, const std::vector<std::string>& isa,
         const std::optional<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return);
@@ -190,6 +185,9 @@
 
     binder::Status migrateLegacyObbData();
 
+    binder::Status cleanupInvalidPackageDirs(const std::optional<std::string>& uuid, int32_t userId,
+                                             int32_t flags);
+
 private:
     std::recursive_mutex mLock;
     std::unordered_map<userid_t, std::weak_ptr<std::shared_mutex>> mUserIdLock;
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 684a311..afedcc6 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -97,10 +97,6 @@
             @utf8InCpp String instructionSet, @utf8InCpp String outputPath);
     long deleteOdex(@utf8InCpp String packageName, @utf8InCpp String apkPath,
             @utf8InCpp String instructionSet, @nullable @utf8InCpp String outputPath);
-    void installApkVerity(@utf8InCpp String packageName, @utf8InCpp String filePath,
-            in FileDescriptor verityInput, int contentSize);
-    void assertFsverityRootHashMatches(@utf8InCpp String packageName, @utf8InCpp String filePath,
-            in byte[] expectedHash);
 
     boolean reconcileSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName,
         int uid, in @utf8InCpp String[] isas, @nullable @utf8InCpp String volume_uuid,
@@ -130,6 +126,8 @@
 
     void migrateLegacyObbData();
 
+    void cleanupInvalidPackageDirs(@nullable @utf8InCpp String uuid, int userId, int flags);
+
     const int FLAG_STORAGE_DE = 0x1;
     const int FLAG_STORAGE_CE = 0x2;
     const int FLAG_STORAGE_EXTERNAL = 0x4;
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 51f7716..a16587e 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -8,46 +8,47 @@
     default_applicable_licenses: ["frameworks_native_license"],
 }
 
-cc_test {
-    name: "installd_utils_test",
+cc_defaults {
+    name: "installd_tests_defaults",
     test_suites: ["device-tests"],
     clang: true,
-    srcs: ["installd_utils_test.cpp"],
+    cpp_std: "c++2a",
     cflags: [
         "-Wall",
         "-Werror",
     ],
     shared_libs: [
         "libbase",
-        "libutils",
         "libcutils",
+        "libext2_uuid",
+        "libutils",
     ],
     static_libs: [
+        "liblog",
+    ],
+}
+
+cc_test {
+    name: "installd_utils_test",
+    defaults: ["installd_tests_defaults"],
+    srcs: ["installd_utils_test.cpp"],
+    static_libs: [
         "libasync_safe",
         "libdiskusage",
         "libinstalld",
-        "liblog",
     ],
     test_config: "installd_utils_test.xml",
 }
 
 cc_test {
     name: "installd_cache_test",
-    test_suites: ["device-tests"],
-    clang: true,
+    defaults: ["installd_tests_defaults"],
     srcs: ["installd_cache_test.cpp"],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
     shared_libs: [
-        "libbase",
         "libbinder",
         "libcrypto",
-        "libcutils",
         "libprocessgroup",
         "libselinux",
-        "libutils",
         "server_configurable_flags",
     ],
     static_libs: [
@@ -55,7 +56,6 @@
         "libdiskusage",
         "libinstalld",
         "libziparchive",
-        "liblog",
         "liblogwrap",
     ],
     test_config: "installd_cache_test.xml",
@@ -78,21 +78,13 @@
 
 cc_test {
     name: "installd_service_test",
-    test_suites: ["device-tests"],
-    clang: true,
+    defaults: ["installd_tests_defaults"],
     srcs: ["installd_service_test.cpp"],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
     shared_libs: [
-        "libbase",
         "libbinder",
         "libcrypto",
-        "libcutils",
         "libprocessgroup",
         "libselinux",
-        "libutils",
         "packagemanager_aidl-cpp",
         "server_configurable_flags",
     ],
@@ -101,7 +93,6 @@
         "libdiskusage",
         "libinstalld",
         "libziparchive",
-        "liblog",
         "liblogwrap",
     ],
     test_config: "installd_service_test.xml",
@@ -124,28 +115,19 @@
 
 cc_test {
     name: "installd_dexopt_test",
-    test_suites: ["device-tests"],
-    clang: true,
+    defaults: ["installd_tests_defaults"],
     srcs: ["installd_dexopt_test.cpp"],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
     shared_libs: [
-        "libbase",
         "libbinder",
         "libcrypto",
-        "libcutils",
         "libprocessgroup",
         "libselinux",
-        "libutils",
         "server_configurable_flags",
     ],
     static_libs: [
         "libasync_safe",
         "libdiskusage",
         "libinstalld",
-        "liblog",
         "liblogwrap",
         "libziparchive",
         "libz",
@@ -170,41 +152,21 @@
 
 cc_test {
     name: "installd_otapreopt_test",
-    test_suites: ["device-tests"],
-    clang: true,
+    defaults: ["installd_tests_defaults"],
     srcs: ["installd_otapreopt_test.cpp"],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
     shared_libs: [
-        "libbase",
-        "libcutils",
-        "libutils",
         "server_configurable_flags",
     ],
     static_libs: [
-        "liblog",
         "libotapreoptparameters",
     ],
 }
 
 cc_test {
     name: "installd_file_test",
-    test_suites: ["device-tests"],
-    clang: true,
+    defaults: ["installd_tests_defaults"],
     srcs: ["installd_file_test.cpp"],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-    shared_libs: [
-        "libbase",
-        "libcutils",
-        "libutils",
-    ],
     static_libs: [
         "libinstalld",
-        "liblog",
     ],
 }
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index b831515..806797f 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -75,6 +75,7 @@
 namespace installd {
 
 constexpr const char* kTestUuid = "TEST";
+constexpr const char* kTestPath = "/data/local/tmp/user/0";
 
 #define FLAG_FORCE InstalldNativeService::FLAG_FORCE
 
@@ -97,7 +98,7 @@
 }
 
 static std::string get_full_path(const char* path) {
-    return StringPrintf("/data/local/tmp/user/0/%s", path);
+    return StringPrintf("%s/%s", kTestPath, path);
 }
 
 static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
@@ -107,12 +108,16 @@
     EXPECT_EQ(::chmod(fullPath.c_str(), mode), 0);
 }
 
-static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
+static int create(const char* path, uid_t owner, gid_t group, mode_t mode) {
     int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
     EXPECT_NE(fd, -1);
     EXPECT_EQ(::fchown(fd, owner, group), 0);
     EXPECT_EQ(::fchmod(fd, mode), 0);
-    EXPECT_EQ(::close(fd), 0);
+    return fd;
+}
+
+static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
+    EXPECT_EQ(::close(create(path, owner, group, mode)), 0);
 }
 
 static int stat_gid(const char* path) {
@@ -127,6 +132,35 @@
     return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
 }
 
+static bool exists(const char* path) {
+    return ::access(get_full_path(path).c_str(), F_OK) == 0;
+}
+
+template <class Pred>
+static bool find_file(const char* path, Pred&& pred) {
+    bool result = false;
+    auto d = opendir(path);
+    if (d == nullptr) {
+        return result;
+    }
+    struct dirent* de;
+    while ((de = readdir(d))) {
+        const char* name = de->d_name;
+        if (pred(name, de->d_type == DT_DIR)) {
+            result = true;
+            break;
+        }
+    }
+    closedir(d);
+    return result;
+}
+
+static bool exists_renamed_deleted_dir() {
+    return find_file(kTestPath, [](std::string_view name, bool is_dir) {
+        return is_dir && is_renamed_deleted_dir(name);
+    });
+}
+
 class ServiceTest : public testing::Test {
 protected:
     InstalldNativeService* service;
@@ -193,6 +227,134 @@
     EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
 }
 
+TEST_F(ServiceTest, DestroyUserData) {
+    LOG(INFO) << "DestroyUserData";
+
+    mkdir("com.example", 10000, 10000, 0700);
+    mkdir("com.example/foo", 10000, 10000, 0700);
+    touch("com.example/foo/file", 10000, 20000, 0700);
+    mkdir("com.example/bar", 10000, 20000, 0700);
+    touch("com.example/bar/file", 10000, 20000, 0700);
+
+    EXPECT_TRUE(exists("com.example/foo"));
+    EXPECT_TRUE(exists("com.example/foo/file"));
+    EXPECT_TRUE(exists("com.example/bar"));
+    EXPECT_TRUE(exists("com.example/bar/file"));
+
+    service->destroyUserData(testUuid, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE);
+
+    EXPECT_FALSE(exists("com.example/foo"));
+    EXPECT_FALSE(exists("com.example/foo/file"));
+    EXPECT_FALSE(exists("com.example/bar"));
+    EXPECT_FALSE(exists("com.example/bar/file"));
+
+    EXPECT_FALSE(exists_renamed_deleted_dir());
+}
+
+TEST_F(ServiceTest, DestroyAppData) {
+    LOG(INFO) << "DestroyAppData";
+
+    mkdir("com.example", 10000, 10000, 0700);
+    mkdir("com.example/foo", 10000, 10000, 0700);
+    touch("com.example/foo/file", 10000, 20000, 0700);
+    mkdir("com.example/bar", 10000, 20000, 0700);
+    touch("com.example/bar/file", 10000, 20000, 0700);
+
+    EXPECT_TRUE(exists("com.example/foo"));
+    EXPECT_TRUE(exists("com.example/foo/file"));
+    EXPECT_TRUE(exists("com.example/bar"));
+    EXPECT_TRUE(exists("com.example/bar/file"));
+
+    service->destroyAppData(testUuid, "com.example", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, 0);
+
+    EXPECT_FALSE(exists("com.example/foo"));
+    EXPECT_FALSE(exists("com.example/foo/file"));
+    EXPECT_FALSE(exists("com.example/bar"));
+    EXPECT_FALSE(exists("com.example/bar/file"));
+
+    EXPECT_FALSE(exists_renamed_deleted_dir());
+}
+
+TEST_F(ServiceTest, CleanupInvalidPackageDirs) {
+    LOG(INFO) << "CleanupInvalidPackageDirs";
+
+    mkdir("5b14b6458a44==deleted==", 10000, 10000, 0700);
+    mkdir("5b14b6458a44==deleted==/foo", 10000, 10000, 0700);
+    touch("5b14b6458a44==deleted==/foo/file", 10000, 20000, 0700);
+    mkdir("5b14b6458a44==deleted==/bar", 10000, 20000, 0700);
+    touch("5b14b6458a44==deleted==/bar/file", 10000, 20000, 0700);
+
+    auto fd = create("5b14b6458a44==deleted==/bar/opened_file", 10000, 20000, 0700);
+
+    mkdir("b14b6458a44NOTdeleted", 10000, 10000, 0700);
+    mkdir("b14b6458a44NOTdeleted/foo", 10000, 10000, 0700);
+    touch("b14b6458a44NOTdeleted/foo/file", 10000, 20000, 0700);
+    mkdir("b14b6458a44NOTdeleted/bar", 10000, 20000, 0700);
+    touch("b14b6458a44NOTdeleted/bar/file", 10000, 20000, 0700);
+
+    mkdir("com.example", 10000, 10000, 0700);
+    mkdir("com.example/foo", 10000, 10000, 0700);
+    touch("com.example/foo/file", 10000, 20000, 0700);
+    mkdir("com.example/bar", 10000, 20000, 0700);
+    touch("com.example/bar/file", 10000, 20000, 0700);
+
+    mkdir("==deleted==", 10000, 10000, 0700);
+    mkdir("==deleted==/foo", 10000, 10000, 0700);
+    touch("==deleted==/foo/file", 10000, 20000, 0700);
+    mkdir("==deleted==/bar", 10000, 20000, 0700);
+    touch("==deleted==/bar/file", 10000, 20000, 0700);
+
+    EXPECT_TRUE(exists("5b14b6458a44==deleted==/foo"));
+    EXPECT_TRUE(exists("5b14b6458a44==deleted==/foo/file"));
+    EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar"));
+    EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar/file"));
+    EXPECT_TRUE(exists("5b14b6458a44==deleted==/bar/opened_file"));
+
+    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo"));
+    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo/file"));
+    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar"));
+    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar/file"));
+
+    EXPECT_TRUE(exists("com.example/foo"));
+    EXPECT_TRUE(exists("com.example/foo/file"));
+    EXPECT_TRUE(exists("com.example/bar"));
+    EXPECT_TRUE(exists("com.example/bar/file"));
+
+    EXPECT_TRUE(exists("==deleted==/foo"));
+    EXPECT_TRUE(exists("==deleted==/foo/file"));
+    EXPECT_TRUE(exists("==deleted==/bar"));
+    EXPECT_TRUE(exists("==deleted==/bar/file"));
+
+    EXPECT_TRUE(exists_renamed_deleted_dir());
+
+    service->cleanupInvalidPackageDirs(testUuid, 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE);
+
+    EXPECT_EQ(::close(fd), 0);
+
+    EXPECT_FALSE(exists("5b14b6458a44==deleted==/foo"));
+    EXPECT_FALSE(exists("5b14b6458a44==deleted==/foo/file"));
+    EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar"));
+    EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar/file"));
+    EXPECT_FALSE(exists("5b14b6458a44==deleted==/bar/opened_file"));
+
+    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo"));
+    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/foo/file"));
+    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar"));
+    EXPECT_TRUE(exists("b14b6458a44NOTdeleted/bar/file"));
+
+    EXPECT_TRUE(exists("com.example/foo"));
+    EXPECT_TRUE(exists("com.example/foo/file"));
+    EXPECT_TRUE(exists("com.example/bar"));
+    EXPECT_TRUE(exists("com.example/bar/file"));
+
+    EXPECT_FALSE(exists("==deleted==/foo"));
+    EXPECT_FALSE(exists("==deleted==/foo/file"));
+    EXPECT_FALSE(exists("==deleted==/bar"));
+    EXPECT_FALSE(exists("==deleted==/bar/file"));
+
+    EXPECT_FALSE(exists_renamed_deleted_dir());
+}
+
 TEST_F(ServiceTest, HashSecondaryDex) {
     LOG(INFO) << "HashSecondaryDex";
 
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 0f8a732..8a00be9 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -22,9 +22,10 @@
 #include <stdlib.h>
 #include <sys/capability.h>
 #include <sys/stat.h>
+#include <sys/statvfs.h>
 #include <sys/wait.h>
 #include <sys/xattr.h>
-#include <sys/statvfs.h>
+#include <uuid/uuid.h>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -47,6 +48,7 @@
 
 #define DEBUG_XATTRS 0
 
+using android::base::Dirname;
 using android::base::EndsWith;
 using android::base::Fdopendir;
 using android::base::StringPrintf;
@@ -55,6 +57,10 @@
 namespace android {
 namespace installd {
 
+using namespace std::literals;
+
+static constexpr auto deletedSuffix = "==deleted=="sv;
+
 /**
  * Check that given string is valid filename, and that it attempts no
  * parent or child directory traversal.
@@ -595,6 +601,93 @@
     return res;
 }
 
+static std::string make_unique_name(std::string_view suffix) {
+    static constexpr auto uuidStringSize = 36;
+
+    uuid_t guid;
+    uuid_generate(guid);
+
+    std::string name;
+    const auto suffixSize = suffix.size();
+    name.reserve(uuidStringSize + suffixSize);
+
+    name.resize(uuidStringSize);
+    uuid_unparse(guid, name.data());
+    name.append(suffix);
+
+    return name;
+}
+
+static int rename_delete_dir_contents(const std::string& pathname,
+                                      int (*exclusion_predicate)(const char*, const int),
+                                      bool ignore_if_missing) {
+    auto temp_dir_name = make_unique_name(deletedSuffix);
+    auto temp_dir_path =
+            base::StringPrintf("%s/%s", Dirname(pathname).c_str(), temp_dir_name.c_str());
+
+    if (::rename(pathname.c_str(), temp_dir_path.c_str())) {
+        if (ignore_if_missing && (errno == ENOENT)) {
+            return 0;
+        }
+        ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), temp_dir_path.c_str(),
+              strerror(errno));
+        return -errno;
+    }
+
+    return delete_dir_contents(temp_dir_path.c_str(), 1, exclusion_predicate, ignore_if_missing);
+}
+
+bool is_renamed_deleted_dir(std::string_view path) {
+    return path.ends_with(deletedSuffix);
+}
+
+int rename_delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing) {
+    return rename_delete_dir_contents(pathname, nullptr, ignore_if_missing);
+}
+
+static auto open_dir(const char* dir) {
+    struct DirCloser {
+        void operator()(DIR* d) const noexcept { ::closedir(d); }
+    };
+    return std::unique_ptr<DIR, DirCloser>(::opendir(dir));
+}
+
+void cleanup_invalid_package_dirs_under_path(const std::string& pathname) {
+    auto dir = open_dir(pathname.c_str());
+    if (!dir) {
+        return;
+    }
+    int dfd = dirfd(dir.get());
+    if (dfd < 0) {
+        ALOGE("Couldn't dirfd %s: %s\n", pathname.c_str(), strerror(errno));
+        return;
+    }
+
+    struct dirent* de;
+    while ((de = readdir(dir.get()))) {
+        if (de->d_type != DT_DIR) {
+            continue;
+        }
+
+        std::string name{de->d_name};
+        // always skip "." and ".."
+        if (name == "." || name == "..") {
+            continue;
+        }
+
+        if (is_renamed_deleted_dir(name) || !is_valid_filename(name) ||
+            !is_valid_package_name(name)) {
+            ALOGI("Deleting renamed or invalid data directory: %s\n", name.c_str());
+            // Deleting the content.
+            delete_dir_contents_fd(dfd, name.c_str());
+            // Deleting the directory
+            if (unlinkat(dfd, name.c_str(), AT_REMOVEDIR) < 0) {
+                ALOGE("Couldn't unlinkat %s: %s\n", name.c_str(), strerror(errno));
+            }
+        }
+    }
+}
+
 int delete_dir_contents_fd(int dfd, const char *name)
 {
     int fd, res;
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 549fc6c..ffde562 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -120,6 +120,11 @@
 int delete_dir_contents(const std::string& pathname, bool ignore_if_missing = false);
 int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false);
 
+bool is_renamed_deleted_dir(std::string_view path);
+int rename_delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false);
+
+void cleanup_invalid_package_dirs_under_path(const std::string& pathname);
+
 int delete_dir_contents(const char *pathname,
                         int also_delete_dir,
                         int (*exclusion_predicate)(const char *name, const int is_dir),
diff --git a/data/etc/android.software.window_magnification.xml b/data/etc/android.software.window_magnification.xml
new file mode 100644
index 0000000..10a2de1
--- /dev/null
+++ b/data/etc/android.software.window_magnification.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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 is the feature indicating device supports window magnifier.
+     And the hand-held and PC platform should support this.
+-->
+<permissions>
+    <feature name="android.software.window_magnification" />
+</permissions>
diff --git a/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml
index d601931..8df7fdb 100644
--- a/data/etc/go_handheld_core_hardware.xml
+++ b/data/etc/go_handheld_core_hardware.xml
@@ -46,6 +46,7 @@
     <feature name="android.software.autofill" />
     <feature name="android.software.cant_save_state" />
     <feature name="android.software.secure_lock_screen" />
+    <feature name="android.software.window_magnification" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 68b8def..8fdd8d0 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -54,6 +54,7 @@
     <feature name="android.software.autofill" />
     <feature name="android.software.cant_save_state" />
     <feature name="android.software.secure_lock_screen" />
+    <feature name="android.software.window_magnification" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/data/etc/pc_core_hardware.xml b/data/etc/pc_core_hardware.xml
index b490ba0..3155710 100644
--- a/data/etc/pc_core_hardware.xml
+++ b/data/etc/pc_core_hardware.xml
@@ -49,6 +49,7 @@
     <feature name="android.software.autofill" />
     <feature name="android.software.cant_save_state" />
     <feature name="android.software.secure_lock_screen" />
+    <feature name="android.software.window_magnification" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
@@ -62,4 +63,4 @@
     <!-- Feature to specify if the device supports freeform. -->
     <feature name="android.software.freeform_window_management" />
     <feature name="android.hardware.type.pc" />
-</permissions>
\ No newline at end of file
+</permissions>
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 8c369de..59d5b10 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -54,6 +54,7 @@
     <feature name="android.software.autofill" />
     <feature name="android.software.cant_save_state" />
     <feature name="android.software.secure_lock_screen" />
+    <feature name="android.software.window_magnification" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/include/android/sensor.h b/include/android/sensor.h
index cf1ca02..c714b05 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -743,11 +743,36 @@
 ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName) __INTRODUCED_IN(26);
 
 /**
- * Returns the list of available sensors.
+ * Returns the list of available sensors. The returned list is owned by the
+ * sensor manager and will not change between calls to this function.
+ *
+ * \param manager the {@link ASensorManager} instance obtained from
+ *                {@link ASensorManager_getInstanceForPackage}.
+ * \param list    the returned list of sensors.
+ * \return positive number of returned sensors or negative error code.
+ *         BAD_VALUE: manager is NULL.
  */
 int ASensorManager_getSensorList(ASensorManager* manager, ASensorList* list);
 
 /**
+ * Returns the list of available dynamic sensors. If there are no dynamic
+ * sensors available, returns nullptr in list.
+ *
+ * Each time this is called, the previously returned list is deallocated and
+ * must no longer be used.
+ *
+ * Available since API level 33.
+ *
+ * \param manager the {@link ASensorManager} instance obtained from
+ *                {@link ASensorManager_getInstanceForPackage}.
+ * \param list    the returned list of dynamic sensors.
+ * \return positive number of returned sensors or negative error code.
+ *         BAD_VALUE: manager is NULL.
+ */
+ssize_t ASensorManager_getDynamicSensorList(
+        ASensorManager* manager, ASensorList* list) __INTRODUCED_IN(33);
+
+/**
  * Returns the default sensor for the given type, or NULL if no sensor
  * of that type exists.
  */
diff --git a/include/ftl/Flags.h b/include/ftl/Flags.h
index 932af2d..708eaf5 100644
--- a/include/ftl/Flags.h
+++ b/include/ftl/Flags.h
@@ -120,10 +120,10 @@
     }
 
     /* Tests whether any of the given flags are set */
-    bool any(Flags<F> f) { return (mFlags & f.mFlags) != 0; }
+    bool any(Flags<F> f) const { return (mFlags & f.mFlags) != 0; }
 
     /* Tests whether all of the given flags are set */
-    bool all(Flags<F> f) { return (mFlags & f.mFlags) == f.mFlags; }
+    bool all(Flags<F> f) const { return (mFlags & f.mFlags) == f.mFlags; }
 
     Flags<F> operator|(Flags<F> rhs) const { return static_cast<F>(mFlags | rhs.mFlags); }
     Flags<F>& operator|=(Flags<F> rhs) {
@@ -153,6 +153,10 @@
         return *this;
     }
 
+    inline Flags<F>& clear(Flags<F> f = static_cast<F>(~static_cast<U>(0))) {
+        return *this &= ~f;
+    }
+
     Iterator begin() const { return Iterator(*this); }
 
     Iterator end() const { return Iterator(); }
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 269b086..1821729 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -368,7 +368,7 @@
     int32_t s = android_atomic_add(1, &mThreadPoolSeq);
     pid_t pid = getpid();
     String8 name;
-    name.appendFormat("Binder:%d_%X", pid, s);
+    name.appendFormat("%d_%X:%s", pid, s, mDriverName.c_str());
     return name;
 }
 
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index 4f63194..79cc15f 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -13,12 +13,13 @@
     shared_libs: [
         "libbase",
         "libbpf_bcc",
-        "libbpf_android",
         "libbpf_minimal",
         "liblog",
-        "libnetdutils"
     ],
-    header_libs: ["bpf_prog_headers"],
+    header_libs: [
+        "bpf_prog_headers",
+        "bpf_headers",
+    ],
     cflags: [
         "-Werror",
         "-Wall",
@@ -33,12 +34,13 @@
     shared_libs: [
         "libbase",
         "libbpf_bcc",
-        "libbpf_android",
         "libbpf_minimal",
         "libtimeinstate",
-        "libnetdutils",
     ],
-    header_libs: ["bpf_prog_headers"],
+    header_libs: [
+        "bpf_prog_headers",
+        "bpf_headers",
+    ],
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/libs/gralloc/OWNERS b/libs/gralloc/OWNERS
index 93879d8..72ff978 100644
--- a/libs/gralloc/OWNERS
+++ b/libs/gralloc/OWNERS
@@ -1 +1,4 @@
+# Graphics team
+alecmouri@google.com
 chrisforbes@google.com
+jreck@google.com
\ No newline at end of file
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index 61e6657..68b99b0 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -196,6 +196,35 @@
 status_t validateMetadataType(InputHidlVec* input, const MetadataType& expectedMetadataType);
 
 /**
+ * Private helper functions
+ */
+template <class T>
+status_t encodeInteger(const T& input, OutputHidlVec* output) {
+    static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+                  std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+                  std::is_same<T, float>::value || std::is_same<T, double>::value);
+    if (!output) {
+        return BAD_VALUE;
+    }
+
+    const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
+    return output->encode(tmp, sizeof(input));
+}
+
+template <class T>
+status_t decodeInteger(InputHidlVec* input, T* output) {
+    static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+                  std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+                  std::is_same<T, float>::value || std::is_same<T, double>::value);
+    if (!output) {
+        return BAD_VALUE;
+    }
+
+    uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
+    return input->decode(tmp, sizeof(*output));
+}
+
+/**
  * encode/encodeMetadata are the main encoding functions. They take in T and uses the encodeHelper
  * function to turn T into the hidl_vec byte stream.
  *
@@ -251,10 +280,45 @@
 template <class T>
 status_t encodeOptionalMetadata(const MetadataType& metadataType, const std::optional<T>& input,
                         hidl_vec<uint8_t>* output, EncodeHelper<T> encodeHelper) {
-    if (!input) {
-        return NO_ERROR;
+    OutputHidlVec outputHidlVec{output};
+
+    status_t err = encodeMetadataType(metadataType, &outputHidlVec);
+    if (err) {
+        return err;
     }
-    return encodeMetadata(metadataType, *input, output, encodeHelper);
+
+    err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
+    if (err) {
+        return err;
+    }
+
+    if (input) {
+        err = encodeHelper(*input, &outputHidlVec);
+        if (err) {
+            return err;
+        }
+    }
+
+    err = outputHidlVec.resize();
+    if (err) {
+        return err;
+    }
+
+    err = encodeMetadataType(metadataType, &outputHidlVec);
+    if (err) {
+        return err;
+    }
+
+    err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
+    if (err) {
+        return err;
+    }
+
+    if (input) {
+        return encodeHelper(*input, &outputHidlVec);
+    }
+
+    return NO_ERROR;
 }
 
 /**
@@ -315,45 +379,36 @@
     if (!output) {
         return BAD_VALUE;
     }
-    if (input.size() <= 0) {
-        output->reset();
-        return NO_ERROR;
+
+    InputHidlVec inputHidlVec{&input};
+
+    status_t err = validateMetadataType(&inputHidlVec, metadataType);
+    if (err) {
+        return err;
     }
-    T tmp;
-    status_t err = decodeMetadata(metadataType, input, &tmp, decodeHelper);
-    if (!err) {
+
+    uint32_t present = 0;
+    err = decodeInteger<uint32_t>(&inputHidlVec, &present);
+    if (err) {
+        return err;
+    }
+
+    if (present) {
+        T tmp;
+        err = decodeHelper(&inputHidlVec, &tmp);
+        if (err) {
+            return err;
+        }
+
         *output = tmp;
     }
-    return err;
-}
 
-/**
- * Private helper functions
- */
-template <class T>
-status_t encodeInteger(const T& input, OutputHidlVec* output) {
-    static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
-                  std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
-                  std::is_same<T, float>::value || std::is_same<T, double>::value);
-    if (!output) {
+    err = inputHidlVec.hasRemainingData();
+    if (err) {
         return BAD_VALUE;
     }
 
-    const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
-    return output->encode(tmp, sizeof(input));
-}
-
-template <class T>
-status_t decodeInteger(InputHidlVec* input, T* output) {
-    static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
-                  std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
-                  std::is_same<T, float>::value || std::is_same<T, double>::value);
-    if (!output) {
-        return BAD_VALUE;
-    }
-
-    uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
-    return input->decode(tmp, sizeof(*output));
+    return NO_ERROR;
 }
 
 status_t encodeString(const std::string& input, OutputHidlVec* output) {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index ec3587b..d634c58 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -37,6 +37,12 @@
         "android.hardware.graphics.bufferqueue@2.0",
     ],
     min_sdk_version: "29",
+    // TODO(b/218719284) can media use be constrained to libgui_bufferqueue_static?
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
 }
 
 cc_library_headers {
@@ -198,6 +204,7 @@
         "SurfaceComposerClient.cpp",
         "SyncFeatures.cpp",
         "TransactionTracing.cpp",
+        "VsyncEventData.cpp",
         "view/Surface.cpp",
         "WindowInfosListenerReporter.cpp",
         "bufferqueue/1.0/B2HProducerListener.cpp",
@@ -338,6 +345,7 @@
         "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.common@1.2",
+        "android.hardware.graphics.common-V3-ndk",
         "android.hidl.token@1.0-utils",
         "libbase",
         "libcutils",
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index aeb237d..7ce72ff 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -842,6 +842,14 @@
                                mPendingTransactions.end());
 }
 
+SurfaceComposerClient::Transaction* BLASTBufferQueue::gatherPendingTransactions(
+        uint64_t frameNumber) {
+    std::lock_guard _lock{mMutex};
+    SurfaceComposerClient::Transaction* t = new SurfaceComposerClient::Transaction();
+    mergePendingTransactions(t, frameNumber);
+    return t;
+}
+
 // Maintains a single worker thread per process that services a list of runnables.
 class AsyncWorker : public Singleton<AsyncWorker> {
 private:
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index ee80082..26db59b 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -148,14 +148,13 @@
 
 void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event,
                                                     VsyncEventData* outVsyncEventData) const {
-    for (size_t i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) {
+    for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
         DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline =
                 event.vsync.frameTimelines[i];
-        outVsyncEventData->frameTimelines[i] = {.id = receiverTimeline.vsyncId,
-                                                .deadlineTimestamp =
-                                                        receiverTimeline.deadlineTimestamp,
-                                                .expectedPresentTime =
-                                                        receiverTimeline.expectedVSyncTimestamp};
+        outVsyncEventData->frameTimelines[i] =
+                VsyncEventData::FrameTimeline(receiverTimeline.vsyncId,
+                                              receiverTimeline.deadlineTimestamp,
+                                              receiverTimeline.expectedVSyncTimestamp);
     }
 }
 
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index b916e48..bb659bf 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -20,6 +20,7 @@
 
 #include <gui/DisplayEventReceiver.h>
 #include <gui/ISurfaceComposer.h>
+#include <gui/VsyncEventData.h>
 
 #include <private/gui/ComposerService.h>
 
@@ -39,7 +40,13 @@
         mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration);
         if (mEventConnection != nullptr) {
             mDataChannel = std::make_unique<gui::BitTube>();
-            mEventConnection->stealReceiveChannel(mDataChannel.get());
+            const auto status = mEventConnection->stealReceiveChannel(mDataChannel.get());
+            if (!status.isOk()) {
+                ALOGE("stealReceiveChannel failed: %s", status.toString8().c_str());
+                mInitError = std::make_optional<status_t>(status.transactionError());
+                mDataChannel.reset();
+                mEventConnection.clear();
+            }
         }
     }
 }
@@ -50,12 +57,11 @@
 status_t DisplayEventReceiver::initCheck() const {
     if (mDataChannel != nullptr)
         return NO_ERROR;
-    return NO_INIT;
+    return mInitError.has_value() ? mInitError.value() : NO_INIT;
 }
 
 int DisplayEventReceiver::getFd() const {
-    if (mDataChannel == nullptr)
-        return NO_INIT;
+    if (mDataChannel == nullptr) return mInitError.has_value() ? mInitError.value() : NO_INIT;
 
     return mDataChannel->getFd();
 }
@@ -68,7 +74,7 @@
         mEventConnection->setVsyncRate(count);
         return NO_ERROR;
     }
-    return NO_INIT;
+    return mInitError.has_value() ? mInitError.value() : NO_INIT;
 }
 
 status_t DisplayEventReceiver::requestNextVsync() {
@@ -76,6 +82,20 @@
         mEventConnection->requestNextVsync();
         return NO_ERROR;
     }
+    return mInitError.has_value() ? mInitError.value() : NO_INIT;
+}
+
+status_t DisplayEventReceiver::getLatestVsyncEventData(VsyncEventData* outVsyncEventData) const {
+    if (mEventConnection != nullptr) {
+        VsyncEventData vsyncEventData;
+        auto status = mEventConnection->getLatestVsyncEventData(&vsyncEventData);
+        if (!status.isOk()) {
+            ALOGE("Failed to get latest vsync event data: %s", status.exceptionMessage().c_str());
+            return status.transactionError();
+        }
+        *outVsyncEventData = vsyncEventData;
+        return NO_ERROR;
+    }
     return NO_INIT;
 }
 
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index fb9ed22..75c5e26 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -42,6 +42,8 @@
 
 // ---------------------------------------------------------------------------
 
+using namespace aidl::android::hardware::graphics;
+
 namespace android {
 
 using gui::IDisplayEventConnection;
@@ -1201,8 +1203,9 @@
         return NO_ERROR;
     }
 
-    status_t getDisplayDecorationSupport(const sp<IBinder>& displayToken,
-                                         bool* outSupport) const override {
+    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) {
@@ -1225,7 +1228,26 @@
             ALOGE("getDisplayDecorationSupport: failed to read support: %d", error);
             return error;
         }
-        *outSupport = support;
+
+        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;
     }
 
@@ -2164,14 +2186,18 @@
         case GET_DISPLAY_DECORATION_SUPPORT: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> displayToken;
-            status_t error = data.readNullableStrongBinder(&displayToken);
+            SAFE_PARCEL(data.readNullableStrongBinder, &displayToken);
+            std::optional<common::DisplayDecorationSupport> support;
+            auto error = getDisplayDecorationSupport(displayToken, &support);
             if (error != NO_ERROR) {
-                ALOGE("getDisplayDecorationSupport: failed to read display token: %d", error);
+                ALOGE("getDisplayDecorationSupport failed with error %d", error);
                 return error;
             }
-            bool support = false;
-            error = getDisplayDecorationSupport(displayToken, &support);
-            reply->writeBool(support);
+            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: {
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index aa7ebc9..f7392d4 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -111,7 +111,14 @@
 
 status_t SurfaceStats::writeToParcel(Parcel* output) const {
     SAFE_PARCEL(output->writeStrongBinder, surfaceControl);
-    SAFE_PARCEL(output->writeInt64, acquireTime);
+    if (const auto* acquireFence = std::get_if<sp<Fence>>(&acquireTimeOrFence)) {
+        SAFE_PARCEL(output->writeBool, true);
+        SAFE_PARCEL(output->write, **acquireFence);
+    } else {
+        SAFE_PARCEL(output->writeBool, false);
+        SAFE_PARCEL(output->writeInt64, std::get<nsecs_t>(acquireTimeOrFence));
+    }
+
     if (previousReleaseFence) {
         SAFE_PARCEL(output->writeBool, true);
         SAFE_PARCEL(output->write, *previousReleaseFence);
@@ -131,10 +138,20 @@
 
 status_t SurfaceStats::readFromParcel(const Parcel* input) {
     SAFE_PARCEL(input->readStrongBinder, &surfaceControl);
-    SAFE_PARCEL(input->readInt64, &acquireTime);
+
     bool hasFence = false;
     SAFE_PARCEL(input->readBool, &hasFence);
     if (hasFence) {
+        acquireTimeOrFence = sp<Fence>::make();
+        SAFE_PARCEL(input->read, *std::get<sp<Fence>>(acquireTimeOrFence));
+    } else {
+        nsecs_t acquireTime;
+        SAFE_PARCEL(input->readInt64, &acquireTime);
+        acquireTimeOrFence = acquireTime;
+    }
+
+    SAFE_PARCEL(input->readBool, &hasFence);
+    if (hasFence) {
         previousReleaseFence = new Fence();
         SAFE_PARCEL(input->read, *previousReleaseFence);
     }
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index eec4a87..9022e7d 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -35,7 +35,9 @@
 using gui::WindowInfoHandle;
 
 layer_state_t::layer_state_t()
-      : what(0),
+      : surface(nullptr),
+        layerId(-1),
+        what(0),
         x(0),
         y(0),
         z(0),
@@ -153,8 +155,12 @@
     SAFE_PARCEL(output.writeBool, isTrustedOverlay);
 
     SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dropInputMode));
-    SAFE_PARCEL(output.writeNullableParcelable,
-                bufferData ? std::make_optional<BufferData>(*bufferData) : std::nullopt);
+
+    const bool hasBufferData = (bufferData != nullptr);
+    SAFE_PARCEL(output.writeBool, hasBufferData);
+    if (hasBufferData) {
+        SAFE_PARCEL(output.writeParcelable, *bufferData);
+    }
     return NO_ERROR;
 }
 
@@ -264,9 +270,15 @@
     uint32_t mode;
     SAFE_PARCEL(input.readUint32, &mode);
     dropInputMode = static_cast<gui::DropInputMode>(mode);
-    std::optional<BufferData> tmpBufferData;
-    SAFE_PARCEL(input.readParcelable, &tmpBufferData);
-    bufferData = tmpBufferData ? std::make_shared<BufferData>(*tmpBufferData) : nullptr;
+
+    bool hasBufferData;
+    SAFE_PARCEL(input.readBool, &hasBufferData);
+    if (hasBufferData) {
+        bufferData = std::make_shared<BufferData>();
+        SAFE_PARCEL(input.readParcelable, bufferData.get());
+    } else {
+        bufferData = nullptr;
+    }
     return NO_ERROR;
 }
 
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 91b2fb1..9269c3e 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -52,6 +52,7 @@
 
 namespace android {
 
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
 using gui::FocusRequest;
 using gui::IRegionSamplingListener;
 using gui::WindowInfo;
@@ -296,7 +297,7 @@
                 surfaceControlStats
                         .emplace_back(callbacksMap[callbackId]
                                               .surfaceControls[surfaceStats.surfaceControl],
-                                      transactionStats.latchTime, surfaceStats.acquireTime,
+                                      transactionStats.latchTime, surfaceStats.acquireTimeOrFence,
                                       transactionStats.presentFence,
                                       surfaceStats.previousReleaseFence, surfaceStats.transformHint,
                                       surfaceStats.eventStats);
@@ -321,7 +322,7 @@
                 surfaceControlStats
                         .emplace_back(callbacksMap[callbackId]
                                               .surfaceControls[surfaceStats.surfaceControl],
-                                      transactionStats.latchTime, surfaceStats.acquireTime,
+                                      transactionStats.latchTime, surfaceStats.acquireTimeOrFence,
                                       transactionStats.presentFence,
                                       surfaceStats.previousReleaseFence, surfaceStats.transformHint,
                                       surfaceStats.eventStats);
@@ -2239,8 +2240,9 @@
                                                                           lightRadius);
 }
 
-bool SurfaceComposerClient::getDisplayDecorationSupport(const sp<IBinder>& displayToken) {
-    bool support = false;
+std::optional<DisplayDecorationSupport> SurfaceComposerClient::getDisplayDecorationSupport(
+        const sp<IBinder>& displayToken) {
+    std::optional<DisplayDecorationSupport> support;
     ComposerService::getComposerService()->getDisplayDecorationSupport(displayToken, &support);
     return support;
 }
diff --git a/libs/gui/VsyncEventData.cpp b/libs/gui/VsyncEventData.cpp
new file mode 100644
index 0000000..aad81d0
--- /dev/null
+++ b/libs/gui/VsyncEventData.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 "gui/VsyncEventData.h"
+#include <gui/DisplayEventReceiver.h>
+#include <private/gui/ParcelUtils.h>
+#include <utils/Log.h>
+#include <utils/Looper.h>
+#include <cstdint>
+
+namespace android::gui {
+
+status_t VsyncEventData::readFromParcel(const Parcel* parcel) {
+    if (parcel == nullptr) {
+        ALOGE("%s: Null parcel", __func__);
+        return BAD_VALUE;
+    }
+
+    SAFE_PARCEL(parcel->readInt64, &id)
+    SAFE_PARCEL(parcel->readInt64, &deadlineTimestamp);
+    SAFE_PARCEL(parcel->readInt64, &frameInterval);
+
+    uint64_t uintPreferredFrameTimelineIndex;
+    SAFE_PARCEL(parcel->readUint64, &uintPreferredFrameTimelineIndex);
+    preferredFrameTimelineIndex = static_cast<size_t>(uintPreferredFrameTimelineIndex);
+
+    std::vector<FrameTimeline> timelines;
+    SAFE_PARCEL(parcel->readParcelableVector, &timelines);
+    std::copy_n(timelines.begin(), timelines.size(), frameTimelines.begin());
+
+    return OK;
+}
+status_t VsyncEventData::writeToParcel(Parcel* parcel) const {
+    SAFE_PARCEL(parcel->writeInt64, id)
+    SAFE_PARCEL(parcel->writeInt64, deadlineTimestamp);
+    SAFE_PARCEL(parcel->writeInt64, frameInterval);
+    SAFE_PARCEL(parcel->writeUint64, preferredFrameTimelineIndex);
+    SAFE_PARCEL(parcel->writeParcelableVector,
+                std::vector(frameTimelines.begin(), frameTimelines.end()));
+
+    return OK;
+}
+status_t VsyncEventData::FrameTimeline::readFromParcel(const Parcel* parcel) {
+    if (parcel == nullptr) {
+        ALOGE("%s: Null parcel", __func__);
+        return BAD_VALUE;
+    }
+
+    SAFE_PARCEL(parcel->readInt64, &id)
+    SAFE_PARCEL(parcel->readInt64, &deadlineTimestamp);
+    SAFE_PARCEL(parcel->readInt64, &expectedPresentTime);
+
+    return OK;
+}
+status_t VsyncEventData::FrameTimeline::writeToParcel(Parcel* parcel) const {
+    SAFE_PARCEL(parcel->writeInt64, id);
+    SAFE_PARCEL(parcel->writeInt64, deadlineTimestamp);
+    SAFE_PARCEL(parcel->writeInt64, expectedPresentTime);
+
+    return OK;
+}
+
+}; // namespace android::gui
diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp
index c32b9ab..4112f74 100644
--- a/libs/gui/WindowInfosListenerReporter.cpp
+++ b/libs/gui/WindowInfosListenerReporter.cpp
@@ -68,8 +68,7 @@
 binder::Status WindowInfosListenerReporter::onWindowInfosChanged(
         const std::vector<WindowInfo>& windowInfos, const std::vector<DisplayInfo>& displayInfos,
         const sp<IWindowInfosReportedListener>& windowInfosReportedListener) {
-    std::unordered_set<sp<WindowInfosListener>, ISurfaceComposer::SpHash<WindowInfosListener>>
-            windowInfosListeners;
+    std::unordered_set<sp<WindowInfosListener>, SpHash<WindowInfosListener>> windowInfosListeners;
 
     {
         std::scoped_lock lock(mListenersMutex);
@@ -96,4 +95,4 @@
     }
 }
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl
index 9f41593..e9a6a0c 100644
--- a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl
+++ b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl
@@ -17,6 +17,7 @@
 package android.gui;
 
 import android.gui.BitTube;
+import android.gui.VsyncEventData;
 
 /** @hide */
 interface IDisplayEventConnection {
@@ -38,4 +39,9 @@
      * requestNextVsync() schedules the next vsync event. It has no effect if the vsync rate is > 0.
      */
     oneway void requestNextVsync(); // Asynchronous
+
+    /*
+     * getLatestVsyncEventData() gets the latest vsync event data.
+     */
+    VsyncEventData getLatestVsyncEventData();
 }
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/VsyncEventData.aidl
new file mode 100644
index 0000000..7343515
--- /dev/null
+++ b/libs/gui/aidl/android/gui/VsyncEventData.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index f77cfe6..1ed592b 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -98,6 +98,7 @@
     void setSyncTransaction(SurfaceComposerClient::Transaction* t, bool acquireSingleBuffer = true);
     void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
     void applyPendingTransactions(uint64_t frameNumber);
+    SurfaceComposerClient::Transaction* gatherPendingTransactions(uint64_t frameNumber);
 
     void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format,
                 SurfaceComposerClient::Transaction* outTransaction = nullptr);
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 40621dd..71968fa 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -17,45 +17,10 @@
 #include <gui/DisplayEventReceiver.h>
 #include <utils/Log.h>
 #include <utils/Looper.h>
-#include <array>
 
 namespace android {
 using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
 
-struct VsyncEventData {
-    // The Vsync Id corresponsing to this vsync event. This will be used to
-    // populate ISurfaceComposer::setFrameTimelineVsync and
-    // SurfaceComposerClient::setFrameTimelineVsync
-    int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID;
-
-    // The deadline in CLOCK_MONOTONIC that the app needs to complete its
-    // frame by (both on the CPU and the GPU)
-    int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max();
-
-    // The current frame interval in ns when this frame was scheduled.
-    int64_t frameInterval = 0;
-
-    struct FrameTimeline {
-        // The Vsync Id corresponsing to this vsync event. This will be used to
-        // populate ISurfaceComposer::setFrameTimelineVsync and
-        // SurfaceComposerClient::setFrameTimelineVsync
-        int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID;
-
-        // The deadline in CLOCK_MONOTONIC that the app needs to complete its
-        // frame by (both on the CPU and the GPU)
-        int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max();
-
-        // The anticipated Vsync present time.
-        int64_t expectedPresentTime = 0;
-    };
-
-    // Sorted possible frame timelines.
-    std::array<FrameTimeline, DisplayEventReceiver::kFrameTimelinesLength> frameTimelines;
-
-    // Index into the frameTimelines that represents the platform's preferred frame timeline.
-    size_t preferredFrameTimelineIndex = std::numeric_limits<size_t>::max();
-};
-
 class DisplayEventDispatcher : public LooperCallback {
 public:
     explicit DisplayEventDispatcher(
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 456bbfb..e752062 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -26,6 +26,7 @@
 
 #include <binder/IInterface.h>
 #include <gui/ISurfaceComposer.h>
+#include <gui/VsyncEventData.h>
 
 // ----------------------------------------------------------------------------
 
@@ -34,6 +35,7 @@
 // ----------------------------------------------------------------------------
 
 using gui::IDisplayEventConnection;
+using gui::VsyncEventData;
 
 namespace gui {
 class BitTube;
@@ -49,8 +51,6 @@
 // ----------------------------------------------------------------------------
 class DisplayEventReceiver {
 public:
-    // Max amount of frame timelines is arbitrarily set to be reasonable.
-    static constexpr int64_t kFrameTimelinesLength = 7;
 
     enum {
         DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
@@ -85,7 +85,7 @@
                 nsecs_t expectedVSyncTimestamp __attribute__((aligned(8)));
                 nsecs_t deadlineTimestamp __attribute__((aligned(8)));
                 int64_t vsyncId;
-            } frameTimelines[kFrameTimelinesLength];
+            } frameTimelines[VsyncEventData::kFrameTimelinesLength];
         };
 
         struct Hotplug {
@@ -172,11 +172,22 @@
      */
     status_t requestNextVsync();
 
+    /**
+     * getLatestVsyncEventData() gets the latest vsync event data.
+     */
+    status_t getLatestVsyncEventData(VsyncEventData* outVsyncEventData) const;
+
 private:
     sp<IDisplayEventConnection> mEventConnection;
     std::unique_ptr<gui::BitTube> mDataChannel;
+    std::optional<status_t> mInitError;
 };
 
+inline bool operator==(DisplayEventReceiver::Event::FrameRateOverride lhs,
+                       DisplayEventReceiver::Event::FrameRateOverride rhs) {
+    return (lhs.uid == rhs.uid) && std::abs(lhs.frameRateHz - rhs.frameRateHz) < 0.001f;
+}
+
 // ----------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h
index 1e9c3e7..0bdffac 100644
--- a/libs/gui/include/gui/HdrMetadata.h
+++ b/libs/gui/include/gui/HdrMetadata.h
@@ -44,6 +44,7 @@
     status_t unflatten(void const* buffer, size_t size);
 
     bool operator==(const HdrMetadata& rhs) const;
+    bool operator!=(const HdrMetadata& rhs) const { return !(*this == rhs); }
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 4b5cee2..0a59f52 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -30,6 +30,7 @@
 #include <ftl/Flags.h>
 #include <gui/FrameTimelineInfo.h>
 #include <gui/ITransactionCompletedListener.h>
+#include <gui/SpHash.h>
 #include <math/vec4.h>
 #include <stdint.h>
 #include <sys/types.h>
@@ -51,6 +52,8 @@
 #include <unordered_set>
 #include <vector>
 
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+
 namespace android {
 
 struct client_cache_t;
@@ -70,6 +73,7 @@
 using gui::IDisplayEventConnection;
 using gui::IRegionSamplingListener;
 using gui::IScreenCaptureListener;
+using gui::SpHash;
 
 namespace ui {
 
@@ -118,11 +122,6 @@
 
     using EventRegistrationFlags = Flags<EventRegistration>;
 
-    template <typename T>
-    struct SpHash {
-        size_t operator()(const sp<T>& k) const { return std::hash<T*>()(k.get()); }
-    };
-
     /*
      * Create a connection with SurfaceFlinger.
      */
@@ -536,15 +535,17 @@
      * displayToken
      *      The token of the display.
      * outSupport
-     *      An output parameter for whether the display supports
+     *      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,
-                                                 bool* outSupport) const = 0;
+    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.
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 0df5822..a791c66 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -30,6 +30,7 @@
 #include <cstdint>
 #include <unordered_map>
 #include <unordered_set>
+#include <variant>
 
 namespace android {
 
@@ -130,12 +131,12 @@
     status_t readFromParcel(const Parcel* input) override;
 
     SurfaceStats() = default;
-    SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
-                 uint32_t hint, uint32_t currentMaxAcquiredBuffersCount,
-                 FrameEventHistoryStats frameEventStats, std::vector<JankData> jankData,
-                 ReleaseCallbackId previousReleaseCallbackId)
+    SurfaceStats(const sp<IBinder>& sc, std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence,
+                 const sp<Fence>& prevReleaseFence, uint32_t hint,
+                 uint32_t currentMaxAcquiredBuffersCount, FrameEventHistoryStats frameEventStats,
+                 std::vector<JankData> jankData, ReleaseCallbackId previousReleaseCallbackId)
           : surfaceControl(sc),
-            acquireTime(time),
+            acquireTimeOrFence(std::move(acquireTimeOrFence)),
             previousReleaseFence(prevReleaseFence),
             transformHint(hint),
             currentMaxAcquiredBufferCount(currentMaxAcquiredBuffersCount),
@@ -144,7 +145,7 @@
             previousReleaseCallbackId(previousReleaseCallbackId) {}
 
     sp<IBinder> surfaceControl;
-    nsecs_t acquireTime = -1;
+    std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence = -1;
     sp<Fence> previousReleaseFence;
     uint32_t transformHint = 0;
     uint32_t currentMaxAcquiredBufferCount = 0;
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index cd6afd2..f720619 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -31,6 +31,7 @@
 
 #include <gui/ISurfaceComposer.h>
 #include <gui/LayerMetadata.h>
+#include <gui/SpHash.h>
 #include <gui/SurfaceControl.h>
 #include <gui/WindowInfo.h>
 #include <math/vec3.h>
@@ -412,7 +413,7 @@
 
 struct LayerCaptureArgs : CaptureArgs {
     sp<IBinder> layerHandle;
-    std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> excludeHandles;
+    std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles;
     bool childrenOnly{false};
 
     status_t write(Parcel& output) const override;
diff --git a/libs/gui/include/gui/SpHash.h b/libs/gui/include/gui/SpHash.h
new file mode 100644
index 0000000..5162f01
--- /dev/null
+++ b/libs/gui/include/gui/SpHash.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 <stdint.h>
+#include <sys/types.h>
+
+#include <functional>
+
+namespace android::gui {
+
+template <typename T>
+struct SpHash {
+    size_t operator()(const sp<T>& k) const { return std::hash<T*>()(k.get()); }
+};
+
+}; // namespace android::gui
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 61eeab3..25637ef 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -47,6 +47,8 @@
 #include <gui/WindowInfosListenerReporter.h>
 #include <math/vec3.h>
 
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+
 namespace android {
 
 class HdrCapabilities;
@@ -58,12 +60,13 @@
 using gui::IRegionSamplingListener;
 
 struct SurfaceControlStats {
-    SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime, nsecs_t acquireTime,
+    SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime,
+                        std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence,
                         const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
                         uint32_t hint, FrameEventHistoryStats eventStats)
           : surfaceControl(sc),
             latchTime(latchTime),
-            acquireTime(acquireTime),
+            acquireTimeOrFence(std::move(acquireTimeOrFence)),
             presentFence(presentFence),
             previousReleaseFence(prevReleaseFence),
             transformHint(hint),
@@ -71,7 +74,7 @@
 
     sp<SurfaceControl> surfaceControl;
     nsecs_t latchTime = -1;
-    nsecs_t acquireTime = -1;
+    std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence = -1;
     sp<Fence> presentFence;
     sp<Fence> previousReleaseFence;
     uint32_t transformHint = 0;
@@ -285,14 +288,16 @@
                                             float lightPosY, float lightPosZ, float lightRadius);
 
     /*
-     * Returns whether a display supports DISPLAY_DECORATION layers.
+     * Returns whether and how a display supports DISPLAY_DECORATION layers.
      *
      * displayToken
      *      The token of the display.
      *
-     * Returns whether a display supports DISPLAY_DECORATION layers.
+     * Returns how a display supports DISPLAY_DECORATION layers, or nullopt if
+     * it does not.
      */
-    static bool getDisplayDecorationSupport(const sp<IBinder>& displayToken);
+    static std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>
+    getDisplayDecorationSupport(const sp<IBinder>& displayToken);
 
     // ------------------------------------------------------------------------
     // surface creation / destruction
diff --git a/libs/gui/include/gui/VsyncEventData.h b/libs/gui/include/gui/VsyncEventData.h
new file mode 100644
index 0000000..abac61c
--- /dev/null
+++ b/libs/gui/include/gui/VsyncEventData.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gui/FrameTimelineInfo.h>
+
+#include <array>
+
+namespace android::gui {
+struct VsyncEventData : public Parcelable {
+    // Max amount of frame timelines is arbitrarily set to be reasonable.
+    static constexpr int64_t kFrameTimelinesLength = 7;
+
+    // The Vsync Id corresponsing to this vsync event. This will be used to
+    // populate ISurfaceComposer::setFrameTimelineVsync and
+    // SurfaceComposerClient::setFrameTimelineVsync
+    // TODO(b/198191703): Remove when JNI DisplayEventReceiver uses frameTimelines array.
+    int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID;
+
+    // The deadline in CLOCK_MONOTONIC that the app needs to complete its
+    // frame by (both on the CPU and the GPU)
+    // TODO(b/198191703): Remove when JNI DisplayEventReceiver uses frameTimelines array.
+    int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max();
+
+    // The current frame interval in ns when this frame was scheduled.
+    int64_t frameInterval = 0;
+
+    struct FrameTimeline : public Parcelable {
+        FrameTimeline() = default;
+        FrameTimeline(int64_t id, int64_t deadlineTimestamp, int64_t expectedPresentTime)
+              : id(id),
+                deadlineTimestamp(deadlineTimestamp),
+                expectedPresentTime(expectedPresentTime) {}
+
+        // The Vsync Id corresponsing to this vsync event. This will be used to
+        // populate ISurfaceComposer::setFrameTimelineVsync and
+        // SurfaceComposerClient::setFrameTimelineVsync
+        int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID;
+
+        // The deadline in CLOCK_MONOTONIC that the app needs to complete its
+        // frame by (both on the CPU and the GPU)
+        int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max();
+
+        // The anticipated Vsync present time.
+        int64_t expectedPresentTime = 0;
+
+        status_t readFromParcel(const Parcel*) override;
+        status_t writeToParcel(Parcel*) const override;
+    };
+
+    // Sorted possible frame timelines.
+    std::array<FrameTimeline, kFrameTimelinesLength> frameTimelines;
+
+    // Index into the frameTimelines that represents the platform's preferred frame timeline.
+    size_t preferredFrameTimelineIndex = std::numeric_limits<size_t>::max();
+
+    status_t readFromParcel(const Parcel*) override;
+    status_t writeToParcel(Parcel*) const override;
+};
+} // namespace android::gui
diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h
index 157a804..96bd0b1 100644
--- a/libs/gui/include/gui/WindowInfosListenerReporter.h
+++ b/libs/gui/include/gui/WindowInfosListenerReporter.h
@@ -20,6 +20,7 @@
 #include <android/gui/IWindowInfosReportedListener.h>
 #include <binder/IBinder.h>
 #include <gui/ISurfaceComposer.h>
+#include <gui/SpHash.h>
 #include <gui/WindowInfosListener.h>
 #include <unordered_set>
 
@@ -41,8 +42,7 @@
 
 private:
     std::mutex mListenersMutex;
-    std::unordered_set<sp<gui::WindowInfosListener>,
-                       ISurfaceComposer::SpHash<gui::WindowInfosListener>>
+    std::unordered_set<sp<gui::WindowInfosListener>, SpHash<gui::WindowInfosListener>>
             mWindowInfosListeners GUARDED_BY(mListenersMutex);
 };
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/gui/include/gui/test/CallbackUtils.h b/libs/gui/include/gui/test/CallbackUtils.h
index 6403208..62d1496 100644
--- a/libs/gui/include/gui/test/CallbackUtils.h
+++ b/libs/gui/include/gui/test/CallbackUtils.h
@@ -134,12 +134,15 @@
 
         void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
                                        nsecs_t latchTime) const {
-            const auto& [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence,
-                         transformHint, frameEvents] = surfaceControlStats;
+            const auto& [surfaceControl, latch, acquireTimeOrFence, presentFence,
+                         previousReleaseFence, transformHint, frameEvents] = surfaceControlStats;
 
-            ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
+            ASSERT_TRUE(std::holds_alternative<nsecs_t>(acquireTimeOrFence));
+            ASSERT_EQ(std::get<nsecs_t>(acquireTimeOrFence) > 0,
+                      mBufferResult == ExpectedResult::Buffer::ACQUIRED)
                     << "bad acquire time";
-            ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
+            ASSERT_LE(std::get<nsecs_t>(acquireTimeOrFence), latchTime)
+                    << "acquire time should be <= latch time";
 
             if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
                 ASSERT_NE(previousReleaseFence, nullptr)
diff --git a/libs/gui/sysprop/Android.bp b/libs/gui/sysprop/Android.bp
index bddb0ac..cc33e4c 100644
--- a/libs/gui/sysprop/Android.bp
+++ b/libs/gui/sysprop/Android.bp
@@ -16,4 +16,9 @@
     cpp: {
         min_sdk_version: "29",
     },
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
 }
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 6dd1073..e58543a 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -44,6 +44,7 @@
         "SurfaceTextureMultiContextGL_test.cpp",
         "Surface_test.cpp",
         "TextureRenderer.cpp",
+        "VsyncEventData_test.cpp",
         "WindowInfo_test.cpp",
     ],
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 120ed48..6056280 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -47,6 +47,7 @@
 // retrieve wide-color and hdr settings from configstore
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
 using gui::IDisplayEventConnection;
 using gui::IRegionSamplingListener;
 using ui::ColorMode;
@@ -889,8 +890,9 @@
         return NO_ERROR;
     }
 
-    status_t getDisplayDecorationSupport(const sp<IBinder>& /*displayToken*/,
-                                         bool* /*outSupport*/) const override {
+    status_t getDisplayDecorationSupport(
+            const sp<IBinder>& /*displayToken*/,
+            std::optional<DisplayDecorationSupport>* /*outSupport*/) const override {
         return NO_ERROR;
     }
 
diff --git a/libs/gui/tests/VsyncEventData_test.cpp b/libs/gui/tests/VsyncEventData_test.cpp
new file mode 100644
index 0000000..a670d42
--- /dev/null
+++ b/libs/gui/tests/VsyncEventData_test.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+
+#include <gui/VsyncEventData.h>
+
+namespace android {
+
+using gui::VsyncEventData;
+using FrameTimeline = gui::VsyncEventData::FrameTimeline;
+
+namespace test {
+
+TEST(VsyncEventData, Parcelling) {
+    VsyncEventData data;
+    data.id = 123;
+    data.deadlineTimestamp = 456;
+    data.frameInterval = 789;
+    data.preferredFrameTimelineIndex = 1;
+    FrameTimeline timeline0 = FrameTimeline(1, 2, 3);
+    FrameTimeline timeline1 = FrameTimeline(4, 5, 6);
+    data.frameTimelines[0] = timeline0;
+    data.frameTimelines[1] = timeline1;
+
+    Parcel p;
+    data.writeToParcel(&p);
+    p.setDataPosition(0);
+
+    VsyncEventData data2;
+    data2.readFromParcel(&p);
+    ASSERT_EQ(data.id, data2.id);
+    ASSERT_EQ(data.deadlineTimestamp, data2.deadlineTimestamp);
+    ASSERT_EQ(data.frameInterval, data2.frameInterval);
+    ASSERT_EQ(data.preferredFrameTimelineIndex, data2.preferredFrameTimelineIndex);
+    for (int i = 0; i < data.frameTimelines.size(); i++) {
+        ASSERT_EQ(data.frameTimelines[i].id, data2.frameTimelines[i].id);
+        ASSERT_EQ(data.frameTimelines[i].deadlineTimestamp,
+                  data2.frameTimelines[i].deadlineTimestamp);
+        ASSERT_EQ(data.frameTimelines[i].expectedPresentTime,
+                  data2.frameTimelines[i].expectedPresentTime);
+    }
+}
+
+TEST(FrameTimeline, Parcelling) {
+    FrameTimeline timeline = FrameTimeline(1, 2, 3);
+
+    Parcel p;
+    timeline.writeToParcel(&p);
+    p.setDataPosition(0);
+
+    FrameTimeline timeline2;
+    timeline2.readFromParcel(&p);
+    ASSERT_EQ(timeline.id, timeline2.id);
+    ASSERT_EQ(timeline.deadlineTimestamp, timeline2.deadlineTimestamp);
+    ASSERT_EQ(timeline.expectedPresentTime, timeline2.expectedPresentTime);
+}
+
+} // namespace test
+} // namespace android
diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp
index 1a4729c..77b23db 100644
--- a/libs/nativebase/Android.bp
+++ b/libs/nativebase/Android.bp
@@ -45,5 +45,9 @@
             enabled: true,
         },
     },
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+    ],
     min_sdk_version: "29",
 }
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index d90ee57..b182a4a 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -73,6 +73,7 @@
 } // namespace
 
 namespace android {
+using gui::VsyncEventData;
 
 struct FrameCallback {
     AChoreographer_frameCallback callback;
@@ -102,8 +103,7 @@
 struct ChoreographerFrameCallbackDataImpl {
     int64_t frameTimeNanos{0};
 
-    std::array<VsyncEventData::FrameTimeline, DisplayEventReceiver::kFrameTimelinesLength>
-            frameTimelines;
+    std::array<VsyncEventData::FrameTimeline, VsyncEventData::kFrameTimelinesLength> frameTimelines;
 
     size_t preferredFrameTimelineIndex;
 
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 9286009..d30efa1 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -47,6 +47,11 @@
     // TODO(b/153609531): remove when no longer needed.
     native_bridge_supported: true,
     min_sdk_version: "29",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
     host_supported: true,
 }
 
@@ -64,7 +69,7 @@
         symbol_file: "libnativewindow.map.txt",
         unversioned: true,
         override_export_include_dirs: [
-            "include"
+            "include",
         ],
     },
     export_include_dirs: [
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index faa84fc..3e7f69c 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -194,6 +194,8 @@
     // Returns the tid of the renderengine thread if it's threaded, and std::nullopt otherwise
     virtual std::optional<pid_t> getRenderEngineTid() const { return std::nullopt; }
 
+    virtual void setEnableTracing(bool /*tracingEnabled*/) {}
+
 protected:
     RenderEngine() : RenderEngine(RenderEngineType::GLES) {}
 
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index 29175a2..1fb24f5 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -20,15 +20,15 @@
 
 #include "SkiaRenderEngine.h"
 
-#include <android-base/properties.h>
 #include <src/core/SkTraceEventCommon.h>
 
 namespace android {
 namespace renderengine {
 namespace skia {
-SkiaRenderEngine::SkiaRenderEngine(RenderEngineType type) : RenderEngine(type) {
-    SkAndroidFrameworkTraceUtil::setEnableTracing(
-            base::GetBoolProperty(PROPERTY_SKIA_ATRACE_ENABLED, false));
+SkiaRenderEngine::SkiaRenderEngine(RenderEngineType type) : RenderEngine(type) {}
+
+void SkiaRenderEngine::setEnableTracing(bool tracingEnabled) {
+    SkAndroidFrameworkTraceUtil::setEnableTracing(tracingEnabled);
 }
 } // namespace skia
 } // namespace renderengine
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index eb65e83..5d10b6f 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -47,6 +47,7 @@
     virtual int getContextPriority() override { return 0; }
     virtual void assertShadersCompiled(int numShaders) {}
     virtual int reportShadersCompiled() { return 0; }
+    virtual void setEnableTracing(bool tracingEnabled) override;
 
 protected:
     virtual void mapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/,
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 6746e47..63cc02b 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -38,7 +38,7 @@
         uniform float mixFactor;
 
         half4 main(float2 xy) {
-            return half4(mix(originalInput.eval(xy), blurredInput.eval(xy), mixFactor));
+            return half4(mix(originalInput.eval(xy), blurredInput.eval(xy), mixFactor)).rgb1;
         }
     )");
 
@@ -103,7 +103,7 @@
                                   inputMatrix);
         blurBuilder.uniform("mixFactor") = blurRadius / mMaxCrossFadeRadius;
 
-        paint.setShader(blurBuilder.makeShader(nullptr, true));
+        paint.setShader(blurBuilder.makeShader());
     } else {
         paint.setShader(blurShader);
     }
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index 6077c2e..a46329d 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -58,7 +58,7 @@
         effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size());
     }
 
-    return effectBuilder.makeShader(nullptr, false);
+    return effectBuilder.makeShader();
 }
 
 } // namespace skia
diff --git a/libs/renderengine/skia/filters/StretchShaderFactory.cpp b/libs/renderengine/skia/filters/StretchShaderFactory.cpp
index c262e35..beec3ec 100644
--- a/libs/renderengine/skia/filters/StretchShaderFactory.cpp
+++ b/libs/renderengine/skia/filters/StretchShaderFactory.cpp
@@ -238,7 +238,7 @@
     mBuilder->uniform("viewportWidth").set(&viewportWidth, 1);
     mBuilder->uniform("viewportHeight").set(&viewportHeight, 1);
 
-    return mBuilder->makeShader(nullptr, false);
+    return mBuilder->makeShader();
 }
 
 } // namespace skia
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index a7176d3..203bb54 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -403,6 +403,18 @@
     return std::make_optional(tidFuture.get());
 }
 
+void RenderEngineThreaded::setEnableTracing(bool tracingEnabled) {
+    // This function is designed so it can run asynchronously, so we do not need to wait
+    // for the futures.
+    {
+        std::lock_guard lock(mThreadMutex);
+        mFunctionCalls.push([tracingEnabled](renderengine::RenderEngine& instance) {
+            ATRACE_NAME("REThreaded::setEnableTracing");
+            instance.setEnableTracing(tracingEnabled);
+        });
+    }
+    mCondition.notify_one();
+}
 } // namespace threaded
 } // namespace renderengine
 } // namespace android
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 1ba72dd..1340902 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -67,6 +67,7 @@
     bool supportsBackgroundBlur() override;
     void onActiveDisplaySizeChanged(ui::Size size) override;
     std::optional<pid_t> getRenderEngineTid() const override;
+    void setEnableTracing(bool tracingEnabled) override;
 
 protected:
     void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 62f4b4e..0ba9704 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -100,6 +100,7 @@
 
 SensorManager::~SensorManager() {
     free(mSensorList);
+    free(mDynamicSensorList);
 }
 
 status_t SensorManager::waitForSensorService(sp<ISensorServer> *server) {
@@ -130,6 +131,9 @@
     free(mSensorList);
     mSensorList = nullptr;
     mSensors.clear();
+    free(mDynamicSensorList);
+    mDynamicSensorList = nullptr;
+    mDynamicSensors.clear();
 }
 
 status_t SensorManager::assertStateLocked() {
@@ -197,6 +201,35 @@
     return static_cast<ssize_t>(count);
 }
 
+ssize_t SensorManager::getDynamicSensorList(Sensor const* const** list) {
+    Mutex::Autolock _l(mLock);
+    status_t err = assertStateLocked();
+    if (err < 0) {
+        return static_cast<ssize_t>(err);
+    }
+
+    free(mDynamicSensorList);
+    mDynamicSensorList = nullptr;
+    mDynamicSensors = mSensorServer->getDynamicSensorList(mOpPackageName);
+    size_t dynamicCount = mDynamicSensors.size();
+    if (dynamicCount > 0) {
+        mDynamicSensorList = static_cast<Sensor const**>(
+                malloc(dynamicCount * sizeof(Sensor*)));
+        if (mDynamicSensorList == nullptr) {
+          ALOGE("Failed to allocate dynamic sensor list for %zu sensors.",
+                dynamicCount);
+          return static_cast<ssize_t>(NO_MEMORY);
+        }
+
+        for (size_t i = 0; i < dynamicCount; i++) {
+            mDynamicSensorList[i] = mDynamicSensors.array() + i;
+        }
+    }
+
+    *list = mDynamicSensorList;
+    return static_cast<ssize_t>(mDynamicSensors.size());
+}
+
 Sensor const* SensorManager::getDefaultSensor(int type)
 {
     Mutex::Autolock _l(mLock);
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index 09ac7ed..8d0a8a4 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -58,6 +58,7 @@
 
     ssize_t getSensorList(Sensor const* const** list);
     ssize_t getDynamicSensorList(Vector<Sensor>& list);
+    ssize_t getDynamicSensorList(Sensor const* const** list);
     Sensor const* getDefaultSensor(int type);
     sp<SensorEventQueue> createEventQueue(
         String8 packageName = String8(""), int mode = 0, String16 attributionTag = String16(""));
@@ -83,6 +84,8 @@
     sp<ISensorServer> mSensorServer;
     Sensor const** mSensorList;
     Vector<Sensor> mSensors;
+    Sensor const** mDynamicSensorList = nullptr;
+    Vector<Sensor> mDynamicSensors;
     sp<IBinder::DeathRecipient> mDeathObserver;
     const String16 mOpPackageName;
     std::unordered_map<int, sp<ISensorEventConnection>> mDirectConnection;
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index f5a22ec..a9380c6 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -235,6 +235,12 @@
         "libui_headers",
     ],
     min_sdk_version: "29",
+    // TODO(b/214400477) to remove use of GraphicBuffer
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
 
     afdo: true,
 }
@@ -258,6 +264,11 @@
         "libmath_headers",
     ],
     min_sdk_version: "29",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
 }
 
 // defaults to enable VALIDATE_REGIONS traces
diff --git a/libs/ui/include/ui/StretchEffect.h b/libs/ui/include/ui/StretchEffect.h
index cf08acb..123b275 100644
--- a/libs/ui/include/ui/StretchEffect.h
+++ b/libs/ui/include/ui/StretchEffect.h
@@ -44,6 +44,8 @@
         mappedChildBounds == other.mappedChildBounds;
   }
 
+  bool operator!=(const StretchEffect& other) const { return !(*this == other); }
+
   static bool isZero(float value) {
     constexpr float NON_ZERO_EPSILON = 0.001f;
     return fabsf(value) <= NON_ZERO_EPSILON;
diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp
index 9842ed7..076affd 100644
--- a/services/gpuservice/bpfprogs/Android.bp
+++ b/services/gpuservice/bpfprogs/Android.bp
@@ -24,6 +24,7 @@
 bpf {
     name: "gpu_mem.o",
     srcs: ["gpu_mem.c"],
+    btf: true,
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/services/gpuservice/gpumem/Android.bp b/services/gpuservice/gpumem/Android.bp
index 24087ac..d0ea856 100644
--- a/services/gpuservice/gpumem/Android.bp
+++ b/services/gpuservice/gpumem/Android.bp
@@ -26,19 +26,17 @@
     srcs: [
         "GpuMem.cpp",
     ],
+    header_libs: ["bpf_headers"],
     shared_libs: [
         "libbase",
         "libbpf_bcc",
-        "libbpf_android",
         "libcutils",
         "liblog",
         "libutils",
     ],
     export_include_dirs: ["include"],
-    export_shared_lib_headers: [
-        "libbase",
-        "libbpf_android",
-    ],
+    export_header_lib_headers: ["bpf_headers"],
+    export_shared_lib_headers: ["libbase"],
     cppflags: [
         "-Wall",
         "-Werror",
diff --git a/services/gpuservice/gpuwork/Android.bp b/services/gpuservice/gpuwork/Android.bp
index 89b31a6..a9a59bc 100644
--- a/services/gpuservice/gpuwork/Android.bp
+++ b/services/gpuservice/gpuwork/Android.bp
@@ -22,13 +22,13 @@
         "GpuWork.cpp",
     ],
     header_libs: [
+        "bpf_headers",
         "gpu_work_structs",
     ],
     shared_libs: [
         "libbase",
         "libbinder",
         "libbpf_bcc",
-        "libbpf_android",
         "libcutils",
         "liblog",
         "libstatslog",
@@ -43,7 +43,6 @@
     ],
     export_shared_lib_headers: [
         "libbase",
-        "libbpf_android",
         "libstatspull",
     ],
     cppflags: [
diff --git a/services/gpuservice/gpuwork/GpuWork.cpp b/services/gpuservice/gpuwork/GpuWork.cpp
index e7b1cd4..67ce9f2 100644
--- a/services/gpuservice/gpuwork/GpuWork.cpp
+++ b/services/gpuservice/gpuwork/GpuWork.cpp
@@ -24,7 +24,6 @@
 #include <binder/PermissionCache.h>
 #include <bpf/WaitForProgsLoaded.h>
 #include <libbpf.h>
-#include <libbpf_android.h>
 #include <log/log.h>
 #include <random>
 #include <stats_event.h>
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index 5b69f96..4fb0d2e 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -32,10 +32,10 @@
         "GpuMemTracerTest.cpp",
         "GpuStatsTest.cpp",
     ],
+    header_libs: ["bpf_headers"],
     shared_libs: [
         "libbase",
         "libbpf_bcc",
-        "libbpf_android",
         "libcutils",
         "libgfxstats",
         "libgpumem",
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 22a69e5..ed9bfd2 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -22,6 +22,10 @@
     default_applicable_licenses: ["frameworks_native_license"],
 }
 
+inputflinger_tidy_checks = [
+    "android-*",
+]
+
 cc_defaults {
     name: "inputflinger_defaults",
     cpp_std: "c++20",
@@ -38,6 +42,11 @@
     sanitize: {
         misc_undefined: ["bounds"],
     },
+    tidy: true,
+    tidy_checks: [
+        "-*", // Disable all checks not explicitly enabled for now
+    ] + inputflinger_tidy_checks,
+    tidy_checks_as_errors: inputflinger_tidy_checks,
 }
 
 /////////////////////////////////////////////////
@@ -48,7 +57,7 @@
     name: "libinputflinger_sources",
     srcs: [
         "InputClassifier.cpp",
-        "InputClassifierConverter.cpp",
+        "InputCommonConverter.cpp",
         "UnwantedInteractionBlocker.cpp",
         "InputManager.cpp",
     ],
@@ -58,9 +67,10 @@
     name: "libinputflinger_defaults",
     srcs: [":libinputflinger_sources"],
     shared_libs: [
-        "android.hardware.input.classifier@1.0",
+        "android.hardware.input.processor-V1-ndk",
         "libbase",
         "libbinder",
+        "libbinder_ndk",
         "libchrome",
         "libcrypto",
         "libcutils",
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 6c4b11e..3ea0986 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -17,13 +17,15 @@
 #define LOG_TAG "InputClassifier"
 
 #include "InputClassifier.h"
-#include "InputClassifierConverter.h"
+#include "InputCommonConverter.h"
 
-#include <algorithm>
 #include <android-base/stringprintf.h>
-#include <cmath>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
 #include <inttypes.h>
 #include <log/log.h>
+#include <algorithm>
+#include <cmath>
 #if defined(__linux__)
     #include <pthread.h>
 #endif
@@ -36,10 +38,9 @@
 #define INDENT5 "          "
 
 using android::base::StringPrintf;
-using android::hardware::hidl_bitfield;
-using android::hardware::hidl_vec;
-using android::hardware::Return;
-using namespace android::hardware::input;
+using namespace std::chrono_literals;
+using namespace ::aidl::android::hardware::input;
+using aidl::android::hardware::input::processor::IInputProcessor;
 
 namespace android {
 
@@ -55,13 +56,13 @@
     return it->second;
 }
 
-static MotionClassification getMotionClassification(common::V1_0::Classification classification) {
+static MotionClassification getMotionClassification(common::Classification classification) {
     static_assert(MotionClassification::NONE ==
-            static_cast<MotionClassification>(common::V1_0::Classification::NONE));
+                  static_cast<MotionClassification>(common::Classification::NONE));
     static_assert(MotionClassification::AMBIGUOUS_GESTURE ==
-            static_cast<MotionClassification>(common::V1_0::Classification::AMBIGUOUS_GESTURE));
+                  static_cast<MotionClassification>(common::Classification::AMBIGUOUS_GESTURE));
     static_assert(MotionClassification::DEEP_PRESS ==
-            static_cast<MotionClassification>(common::V1_0::Classification::DEEP_PRESS));
+                  static_cast<MotionClassification>(common::Classification::DEEP_PRESS));
     return static_cast<MotionClassification>(classification);
 }
 
@@ -70,6 +71,56 @@
             isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN);
 }
 
+static void setCurrentThreadName(const char* name) {
+#if defined(__linux__)
+    // Set the thread name for debugging
+    pthread_setname_np(pthread_self(), name);
+#else
+    (void*)(name); // prevent unused variable warning
+#endif
+}
+
+static std::shared_ptr<IInputProcessor> getService() {
+    const std::string aidl_instance_name = std::string(IInputProcessor::descriptor) + "/default";
+
+    if (!AServiceManager_isDeclared(aidl_instance_name.c_str())) {
+        ALOGI("HAL %s is not declared", aidl_instance_name.c_str());
+        return nullptr;
+    }
+
+    ndk::SpAIBinder binder(AServiceManager_waitForService(aidl_instance_name.c_str()));
+    return IInputProcessor::fromBinder(binder);
+}
+
+// Temporarily releases a held mutex for the lifetime of the instance.
+// Named to match std::scoped_lock
+class scoped_unlock {
+public:
+    explicit scoped_unlock(std::mutex& mutex) : mMutex(mutex) { mMutex.unlock(); }
+    ~scoped_unlock() { mMutex.lock(); }
+
+private:
+    std::mutex& mMutex;
+};
+
+// --- ScopedDeathRecipient ---
+ScopedDeathRecipient::ScopedDeathRecipient(AIBinder_DeathRecipient_onBinderDied onBinderDied,
+                                           void* cookie)
+      : mCookie(cookie) {
+    mRecipient = AIBinder_DeathRecipient_new(onBinderDied);
+}
+
+void ScopedDeathRecipient::linkToDeath(AIBinder* binder) {
+    binder_status_t linked = AIBinder_linkToDeath(binder, mRecipient, mCookie);
+    if (linked != STATUS_OK) {
+        ALOGE("Could not link death recipient to the HAL death");
+    }
+}
+
+ScopedDeathRecipient::~ScopedDeathRecipient() {
+    AIBinder_DeathRecipient_delete(mRecipient);
+}
+
 // --- ClassifierEvent ---
 
 ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) :
@@ -118,9 +169,8 @@
 
 // --- MotionClassifier ---
 
-MotionClassifier::MotionClassifier(
-        sp<android::hardware::input::classifier::V1_0::IInputClassifier> service)
-      : mEvents(MAX_EVENTS), mService(service) {
+MotionClassifier::MotionClassifier(std::shared_ptr<IInputProcessor> service)
+      : mEvents(MAX_EVENTS), mService(std::move(service)) {
     // Under normal operation, we do not need to reset the HAL here. But in the case where system
     // crashed, but HAL didn't, we may be connecting to an existing HAL process that might already
     // have received events in the past. That means, that HAL could be in an inconsistent state
@@ -135,23 +185,10 @@
 }
 
 std::unique_ptr<MotionClassifierInterface> MotionClassifier::create(
-        sp<android::hardware::hidl_death_recipient> deathRecipient) {
-    sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
-            classifier::V1_0::IInputClassifier::getService();
-    if (!service) {
-        // Not really an error, maybe the device does not have this HAL,
-        // but somehow the feature flag is flipped
-        ALOGI("Could not obtain InputClassifier HAL");
-        return nullptr;
-    }
-
-    const bool linked = service->linkToDeath(deathRecipient, 0 /* cookie */).withDefault(false);
-    if (!linked) {
-        ALOGE("Could not link death recipient to the HAL death");
-        return nullptr;
-    }
+        std::shared_ptr<IInputProcessor> service) {
+    LOG_ALWAYS_FATAL_IF(service == nullptr);
     // Using 'new' to access a non-public constructor
-    return std::unique_ptr<MotionClassifier>(new MotionClassifier(service));
+    return std::unique_ptr<MotionClassifier>(new MotionClassifier(std::move(service)));
 }
 
 MotionClassifier::~MotionClassifier() {
@@ -176,14 +213,12 @@
         switch (event.type) {
             case ClassifierEventType::MOTION: {
                 NotifyMotionArgs* motionArgs = static_cast<NotifyMotionArgs*>(event.args.get());
-                common::V1_0::MotionEvent motionEvent =
-                        notifyMotionArgsToHalMotionEvent(*motionArgs);
-                Return<common::V1_0::Classification> response = mService->classify(motionEvent);
-                halResponseOk = response.isOk();
-                if (halResponseOk) {
-                    common::V1_0::Classification halClassification = response;
+                common::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(*motionArgs);
+                common::Classification classification;
+                ndk::ScopedAStatus response = mService->classify(motionEvent, &classification);
+                if (response.isOk()) {
                     updateClassification(motionArgs->deviceId, motionArgs->eventTime,
-                            getMotionClassification(halClassification));
+                                         getMotionClassification(classification));
                 }
                 break;
             }
@@ -300,7 +335,8 @@
     if (!mService) {
         return "null";
     }
-    if (mService->ping().isOk()) {
+
+    if (AIBinder_ping(mService->asBinder().get()) == STATUS_OK) {
         return "running";
     }
     return "not responding";
@@ -329,40 +365,53 @@
     }
 }
 
-// --- HalDeathRecipient
-
-InputClassifier::HalDeathRecipient::HalDeathRecipient(InputClassifier& parent) : mParent(parent) {}
-
-void InputClassifier::HalDeathRecipient::serviceDied(
-        uint64_t cookie, const wp<android::hidl::base::V1_0::IBase>& who) {
-    sp<android::hidl::base::V1_0::IBase> service = who.promote();
-    if (service) {
-        service->unlinkToDeath(this);
-    }
-    mParent.setMotionClassifier(nullptr);
-}
-
 // --- InputClassifier ---
 
-InputClassifier::InputClassifier(InputListenerInterface& listener)
-      : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {}
+InputClassifier::InputClassifier(InputListenerInterface& listener) : mListener(listener) {}
+
+void InputClassifier::onBinderDied(void* cookie) {
+    InputClassifier* classifier = static_cast<InputClassifier*>(cookie);
+    if (classifier == nullptr) {
+        LOG_ALWAYS_FATAL("Cookie is not valid");
+        return;
+    }
+    classifier->setMotionClassifierEnabled(false);
+}
 
 void InputClassifier::setMotionClassifierEnabled(bool enabled) {
+    std::scoped_lock lock(mLock);
     if (enabled) {
         ALOGI("Enabling motion classifier");
-        if (mInitializeMotionClassifierThread.joinable()) {
-            mInitializeMotionClassifierThread.join();
+        if (mInitializeMotionClassifier.valid()) {
+            scoped_unlock unlock(mLock);
+            std::future_status status = mInitializeMotionClassifier.wait_for(5s);
+            if (status != std::future_status::ready) {
+                /**
+                 * We don't have a better option here than to crash. We can't stop the thread,
+                 * and we can't continue because 'mInitializeMotionClassifier' will block in its
+                 * destructor.
+                 */
+                LOG_ALWAYS_FATAL("The thread to load IInputClassifier is stuck!");
+            }
         }
-        mInitializeMotionClassifierThread = std::thread(
-                [this] { setMotionClassifier(MotionClassifier::create(mHalDeathRecipient)); });
-#if defined(__linux__)
-        // Set the thread name for debugging
-        pthread_setname_np(mInitializeMotionClassifierThread.native_handle(),
-                           "Create MotionClassifier");
-#endif
+        mInitializeMotionClassifier = std::async(std::launch::async, [this] {
+            setCurrentThreadName("Create MotionClassifier");
+            std::shared_ptr<IInputProcessor> service = getService();
+            if (service == nullptr) {
+                // Keep the MotionClassifier null, no service was found
+                return;
+            }
+            { // acquire lock
+                std::scoped_lock threadLock(mLock);
+                mHalDeathRecipient =
+                        std::make_unique<ScopedDeathRecipient>(onBinderDied, this /*cookie*/);
+                mHalDeathRecipient->linkToDeath(service->asBinder().get());
+                setMotionClassifierLocked(MotionClassifier::create(std::move(service)));
+            } // release lock
+        });
     } else {
         ALOGI("Disabling motion classifier");
-        setMotionClassifier(nullptr);
+        setMotionClassifierLocked(nullptr);
     }
 }
 
@@ -419,9 +468,13 @@
     mListener.notifyPointerCaptureChanged(args);
 }
 
-void InputClassifier::setMotionClassifier(
-        std::unique_ptr<MotionClassifierInterface> motionClassifier) {
-    std::scoped_lock lock(mLock);
+void InputClassifier::setMotionClassifierLocked(
+        std::unique_ptr<MotionClassifierInterface> motionClassifier) REQUIRES(mLock) {
+    if (motionClassifier == nullptr) {
+        // Destroy the ScopedDeathRecipient object, which will cause it to unlinkToDeath.
+        // We can't call 'unlink' here because we don't have the binder handle.
+        mHalDeathRecipient = nullptr;
+    }
     mMotionClassifier = std::move(motionClassifier);
 }
 
@@ -438,9 +491,6 @@
 }
 
 InputClassifier::~InputClassifier() {
-    if (mInitializeMotionClassifierThread.joinable()) {
-        mInitializeMotionClassifierThread.join();
-    }
 }
 
 } // namespace android
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index deeae7c..e2a0bc2 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -18,13 +18,13 @@
 #define _UI_INPUT_CLASSIFIER_H
 
 #include <android-base/thread_annotations.h>
+#include <future>
 #include <thread>
 #include <unordered_map>
 
+#include <aidl/android/hardware/input/processor/IInputProcessor.h>
 #include "BlockingQueue.h"
 #include "InputListener.h"
-#include <android/hardware/input/classifier/1.0/IInputClassifier.h>
-
 namespace android {
 
 enum class ClassifierEventType : uint8_t {
@@ -102,6 +102,19 @@
 
 // --- Implementations ---
 
+class ScopedDeathRecipient {
+public:
+    explicit ScopedDeathRecipient(AIBinder_DeathRecipient_onBinderDied onBinderDied, void* cookie);
+    ScopedDeathRecipient(const ScopedDeathRecipient&) = delete;
+    ScopedDeathRecipient& operator=(ScopedDeathRecipient const&) = delete;
+    void linkToDeath(AIBinder* binder);
+    ~ScopedDeathRecipient();
+
+private:
+    AIBinder_DeathRecipient* mRecipient;
+    void* mCookie;
+};
+
 /**
  * Implementation of MotionClassifierInterface that calls the InputClassifier HAL
  * in order to determine the classification for the current gesture.
@@ -121,7 +134,7 @@
      * This function should be called asynchronously, because getService takes a long time.
      */
     static std::unique_ptr<MotionClassifierInterface> create(
-            sp<android::hardware::hidl_death_recipient> deathRecipient);
+            std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service);
 
     ~MotionClassifier();
 
@@ -143,7 +156,7 @@
 private:
     friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation
     explicit MotionClassifier(
-            sp<android::hardware::input::classifier::V1_0::IInputClassifier> service);
+            std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service);
 
     // The events that need to be sent to the HAL.
     BlockingQueue<ClassifierEvent> mEvents;
@@ -162,14 +175,14 @@
      */
     void processEvents();
     /**
-     * Access to the InputClassifier HAL. May be null if init() hasn't completed yet.
+     * Access to the InputProcessor HAL. May be null if init() hasn't completed yet.
      * When init() successfully completes, mService is guaranteed to remain non-null and to not
      * change its value until MotionClassifier is destroyed.
      * This variable is *not* guarded by mLock in the InputClassifier thread, because
      * that thread knows exactly when this variable is initialized.
      * When accessed in any other thread, mService is checked for nullness with a lock.
      */
-    sp<android::hardware::input::classifier::V1_0::IInputClassifier> mService;
+    std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> mService;
     std::mutex mLock;
     /**
      * Per-device input classifications. Should only be accessed using the
@@ -224,21 +237,21 @@
 public:
     explicit InputClassifier(InputListenerInterface& listener);
 
-    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
-    virtual void notifyKey(const NotifyKeyArgs* args) override;
-    virtual void notifyMotion(const NotifyMotionArgs* args) override;
-    virtual void notifySwitch(const NotifySwitchArgs* args) override;
-    virtual void notifySensor(const NotifySensorArgs* args) override;
-    virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
-    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+    void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
+    void notifyKey(const NotifyKeyArgs* args) override;
+    void notifyMotion(const NotifyMotionArgs* args) override;
+    void notifySwitch(const NotifySwitchArgs* args) override;
+    void notifySensor(const NotifySensorArgs* args) override;
+    void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
+    void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
     void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
-    virtual void dump(std::string& dump) override;
+    void dump(std::string& dump) override;
 
     ~InputClassifier();
 
     // Called from InputManager
-    virtual void setMotionClassifierEnabled(bool enabled) override;
+    void setMotionClassifierEnabled(bool enabled) override;
 
 private:
     // Protect access to mMotionClassifier, since it may become null via a hidl callback
@@ -247,7 +260,8 @@
     InputListenerInterface& mListener;
 
     std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock);
-    std::thread mInitializeMotionClassifierThread;
+    std::future<void> mInitializeMotionClassifier GUARDED_BY(mLock);
+
     /**
      * Set the value of mMotionClassifier.
      * This is called from 2 different threads:
@@ -255,25 +269,12 @@
      * 2) A binder thread of the HalDeathRecipient, which is created when HAL dies. This would cause
      *    mMotionClassifier to become nullptr.
      */
-    void setMotionClassifier(std::unique_ptr<MotionClassifierInterface> motionClassifier);
+    void setMotionClassifierLocked(std::unique_ptr<MotionClassifierInterface> motionClassifier)
+            REQUIRES(mLock);
 
-    /**
-     * The deathRecipient will call setMotionClassifier(null) when the HAL dies.
-     */
-    class HalDeathRecipient : public android::hardware::hidl_death_recipient {
-    public:
-        explicit HalDeathRecipient(InputClassifier& parent);
-        virtual void serviceDied(uint64_t cookie,
-                                 const wp<android::hidl::base::V1_0::IBase>& who) override;
+    static void onBinderDied(void* cookie);
 
-    private:
-        InputClassifier& mParent;
-    };
-    // We retain a reference to death recipient, because the death recipient will be calling
-    // ~MotionClassifier if the HAL dies.
-    // If we don't retain a reference, and MotionClassifier is the only owner of the death
-    // recipient, the serviceDied call will cause death recipient to call its own destructor.
-    sp<HalDeathRecipient> mHalDeathRecipient;
+    std::unique_ptr<ScopedDeathRecipient> mHalDeathRecipient GUARDED_BY(mLock);
 };
 
 } // namespace android
diff --git a/services/inputflinger/InputClassifierConverter.cpp b/services/inputflinger/InputClassifierConverter.cpp
deleted file mode 100644
index b58a188..0000000
--- a/services/inputflinger/InputClassifierConverter.cpp
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "InputClassifierConverter.h"
-
-using android::hardware::hidl_bitfield;
-using namespace android::hardware::input;
-
-namespace android {
-
-static common::V1_0::Source getSource(uint32_t source) {
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_UNKNOWN) ==
-            common::V1_0::Source::UNKNOWN, "SOURCE_UNKNOWN mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_KEYBOARD) ==
-            common::V1_0::Source::KEYBOARD, "SOURCE_KEYBOARD mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_DPAD) ==
-            common::V1_0::Source::DPAD, "SOURCE_DPAD mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_GAMEPAD) ==
-            common::V1_0::Source::GAMEPAD, "SOURCE_GAMEPAD mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_TOUCHSCREEN) ==
-            common::V1_0::Source::TOUCHSCREEN, "SOURCE_TOUCHSCREEN mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_MOUSE) ==
-            common::V1_0::Source::MOUSE, "SOURCE_MOUSE mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_STYLUS) ==
-            common::V1_0::Source::STYLUS, "SOURCE_STYLUS mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_BLUETOOTH_STYLUS) ==
-            common::V1_0::Source::BLUETOOTH_STYLUS, "SOURCE_BLUETOOTH_STYLUS mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_TRACKBALL) ==
-            common::V1_0::Source::TRACKBALL, "SOURCE_TRACKBALL mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_MOUSE_RELATIVE) ==
-            common::V1_0::Source::MOUSE_RELATIVE, "SOURCE_MOUSE_RELATIVE mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_TOUCHPAD) ==
-            common::V1_0::Source::TOUCHPAD, "SOURCE_TOUCHPAD mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_TOUCH_NAVIGATION) ==
-            common::V1_0::Source::TOUCH_NAVIGATION, "SOURCE_TOUCH_NAVIGATION mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_JOYSTICK) ==
-            common::V1_0::Source::JOYSTICK, "SOURCE_JOYSTICK mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_ROTARY_ENCODER) ==
-            common::V1_0::Source::ROTARY_ENCODER, "SOURCE_ROTARY_ENCODER mismatch");
-    static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_ANY) ==
-            common::V1_0::Source::ANY, "SOURCE_ANY mismatch");
-    return static_cast<common::V1_0::Source>(source);
-}
-
-static common::V1_0::Action getAction(int32_t actionMasked) {
-    static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_DOWN) ==
-            common::V1_0::Action::DOWN, "ACTION_DOWN mismatch");
-    static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_UP) ==
-            common::V1_0::Action::UP, "ACTION_UP mismatch");
-    static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_MOVE) ==
-            common::V1_0::Action::MOVE, "ACTION_MOVE mismatch");
-    static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_CANCEL) ==
-            common::V1_0::Action::CANCEL, "ACTION_CANCEL mismatch");
-    static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_OUTSIDE) ==
-            common::V1_0::Action::OUTSIDE, "ACTION_OUTSIDE mismatch");
-    static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_POINTER_DOWN) ==
-            common::V1_0::Action::POINTER_DOWN, "ACTION_POINTER_DOWN mismatch");
-    static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_POINTER_UP) ==
-            common::V1_0::Action::POINTER_UP, "ACTION_POINTER_UP mismatch");
-    static_assert(static_cast<common::V1_0::Action>( AMOTION_EVENT_ACTION_HOVER_MOVE) ==
-            common::V1_0::Action::HOVER_MOVE, "ACTION_HOVER_MOVE mismatch");
-    static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_SCROLL) ==
-            common::V1_0::Action::SCROLL, "ACTION_SCROLL mismatch");
-    static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_HOVER_ENTER) ==
-            common::V1_0::Action::HOVER_ENTER, "ACTION_HOVER_ENTER mismatch");
-    static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_HOVER_EXIT) ==
-            common::V1_0::Action::HOVER_EXIT, "ACTION_HOVER_EXIT mismatch");
-    static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_BUTTON_PRESS) ==
-            common::V1_0::Action::BUTTON_PRESS, "ACTION_BUTTON_PRESS mismatch");
-    static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_BUTTON_RELEASE) ==
-            common::V1_0::Action::BUTTON_RELEASE, "ACTION_BUTTON_RELEASE mismatch");
-    return static_cast<common::V1_0::Action>(actionMasked);
-}
-
-static common::V1_0::Button getActionButton(int32_t actionButton) {
-    static_assert(static_cast<common::V1_0::Button>(0) ==
-            common::V1_0::Button::NONE, "BUTTON_NONE mismatch");
-    static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_PRIMARY) ==
-            common::V1_0::Button::PRIMARY, "BUTTON_PRIMARY mismatch");
-    static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_SECONDARY) ==
-            common::V1_0::Button::SECONDARY, "BUTTON_SECONDARY mismatch");
-    static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_TERTIARY) ==
-            common::V1_0::Button::TERTIARY, "BUTTON_TERTIARY mismatch");
-    static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_BACK) ==
-            common::V1_0::Button::BACK, "BUTTON_BACK mismatch");
-    static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_FORWARD) ==
-            common::V1_0::Button::FORWARD, "BUTTON_FORWARD mismatch");
-    static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) ==
-            common::V1_0::Button::STYLUS_PRIMARY, "BUTTON_STYLUS_PRIMARY mismatch");
-    static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_STYLUS_SECONDARY) ==
-            common::V1_0::Button::STYLUS_SECONDARY, "BUTTON_STYLUS_SECONDARY mismatch");
-    return static_cast<common::V1_0::Button>(actionButton);
-}
-
-static hidl_bitfield<common::V1_0::Flag> getFlags(int32_t flags) {
-    static_assert(static_cast<common::V1_0::Flag>(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED) ==
-            common::V1_0::Flag::WINDOW_IS_OBSCURED);
-    static_assert(static_cast<common::V1_0::Flag>(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE) ==
-            common::V1_0::Flag::IS_GENERATED_GESTURE);
-    static_assert(static_cast<common::V1_0::Flag>(AMOTION_EVENT_FLAG_TAINTED) ==
-            common::V1_0::Flag::TAINTED);
-    return static_cast<hidl_bitfield<common::V1_0::Flag>>(flags);
-}
-
-static hidl_bitfield<common::V1_0::PolicyFlag> getPolicyFlags(int32_t flags) {
-    static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_WAKE) ==
-            common::V1_0::PolicyFlag::WAKE);
-    static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_VIRTUAL) ==
-            common::V1_0::PolicyFlag::VIRTUAL);
-    static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_FUNCTION) ==
-            common::V1_0::PolicyFlag::FUNCTION);
-    static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_GESTURE) ==
-            common::V1_0::PolicyFlag::GESTURE);
-    static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_INJECTED) ==
-            common::V1_0::PolicyFlag::INJECTED);
-    static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_TRUSTED) ==
-            common::V1_0::PolicyFlag::TRUSTED);
-    static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_FILTERED) ==
-            common::V1_0::PolicyFlag::FILTERED);
-    static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_DISABLE_KEY_REPEAT) ==
-            common::V1_0::PolicyFlag::DISABLE_KEY_REPEAT);
-    static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_INTERACTIVE) ==
-            common::V1_0::PolicyFlag::INTERACTIVE);
-    static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_PASS_TO_USER) ==
-            common::V1_0::PolicyFlag::PASS_TO_USER);
-    return static_cast<hidl_bitfield<common::V1_0::PolicyFlag>>(flags);
-}
-
-static hidl_bitfield<common::V1_0::EdgeFlag> getEdgeFlags(int32_t flags) {
-    static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_NONE) ==
-            common::V1_0::EdgeFlag::NONE);
-    static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_TOP) ==
-            common::V1_0::EdgeFlag::TOP);
-    static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_BOTTOM) ==
-            common::V1_0::EdgeFlag::BOTTOM);
-    static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_LEFT) ==
-            common::V1_0::EdgeFlag::LEFT);
-    static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_RIGHT) ==
-            common::V1_0::EdgeFlag::RIGHT);
-    return static_cast<hidl_bitfield<common::V1_0::EdgeFlag>>(flags);
-}
-
-static hidl_bitfield<common::V1_0::Meta> getMetastate(int32_t state) {
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_NONE) ==
-            common::V1_0::Meta::NONE);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_ALT_ON) ==
-            common::V1_0::Meta::ALT_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_ALT_LEFT_ON) ==
-            common::V1_0::Meta::ALT_LEFT_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_ALT_RIGHT_ON) ==
-            common::V1_0::Meta::ALT_RIGHT_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_SHIFT_ON) ==
-            common::V1_0::Meta::SHIFT_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_SHIFT_LEFT_ON) ==
-            common::V1_0::Meta::SHIFT_LEFT_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_SHIFT_RIGHT_ON) ==
-            common::V1_0::Meta::SHIFT_RIGHT_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_SYM_ON) ==
-            common::V1_0::Meta::SYM_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_FUNCTION_ON) ==
-            common::V1_0::Meta::FUNCTION_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_CTRL_ON) ==
-            common::V1_0::Meta::CTRL_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_CTRL_LEFT_ON) ==
-            common::V1_0::Meta::CTRL_LEFT_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_CTRL_RIGHT_ON) ==
-            common::V1_0::Meta::CTRL_RIGHT_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_META_ON) ==
-            common::V1_0::Meta::META_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_META_LEFT_ON) ==
-            common::V1_0::Meta::META_LEFT_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_META_RIGHT_ON) ==
-            common::V1_0::Meta::META_RIGHT_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_CAPS_LOCK_ON) ==
-            common::V1_0::Meta::CAPS_LOCK_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_NUM_LOCK_ON) ==
-            common::V1_0::Meta::NUM_LOCK_ON);
-    static_assert(static_cast<common::V1_0::Meta>(AMETA_SCROLL_LOCK_ON) ==
-            common::V1_0::Meta::SCROLL_LOCK_ON);
-    return static_cast<hidl_bitfield<common::V1_0::Meta>>(state);
-}
-
-static hidl_bitfield<common::V1_0::Button> getButtonState(int32_t buttonState) {
-    // No need for static_assert here.
-    // The button values have already been asserted in getActionButton(..) above
-    return static_cast<hidl_bitfield<common::V1_0::Button>>(buttonState);
-}
-
-static common::V1_0::ToolType getToolType(int32_t toolType) {
-    static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_UNKNOWN) ==
-            common::V1_0::ToolType::UNKNOWN);
-    static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_FINGER) ==
-            common::V1_0::ToolType::FINGER);
-    static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_STYLUS) ==
-            common::V1_0::ToolType::STYLUS);
-    static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_MOUSE) ==
-            common::V1_0::ToolType::MOUSE);
-    static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_ERASER) ==
-            common::V1_0::ToolType::ERASER);
-    return static_cast<common::V1_0::ToolType>(toolType);
-}
-
-// MotionEvent axes asserts
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_X) ==
-        common::V1_0::Axis::X);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_Y) ==
-        common::V1_0::Axis::Y);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_PRESSURE) ==
-        common::V1_0::Axis::PRESSURE);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_SIZE) ==
-        common::V1_0::Axis::SIZE);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TOUCH_MAJOR) ==
-        common::V1_0::Axis::TOUCH_MAJOR);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TOUCH_MINOR) ==
-        common::V1_0::Axis::TOUCH_MINOR);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TOOL_MAJOR) ==
-        common::V1_0::Axis::TOOL_MAJOR);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TOOL_MINOR) ==
-        common::V1_0::Axis::TOOL_MINOR);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_ORIENTATION) ==
-        common::V1_0::Axis::ORIENTATION);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_VSCROLL) ==
-        common::V1_0::Axis::VSCROLL);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_HSCROLL) ==
-        common::V1_0::Axis::HSCROLL);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_Z) ==
-        common::V1_0::Axis::Z);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RX) ==
-        common::V1_0::Axis::RX);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RY) ==
-        common::V1_0::Axis::RY);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RZ) ==
-        common::V1_0::Axis::RZ);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_HAT_X) ==
-        common::V1_0::Axis::HAT_X);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_HAT_Y) ==
-        common::V1_0::Axis::HAT_Y);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_LTRIGGER) ==
-        common::V1_0::Axis::LTRIGGER);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RTRIGGER) ==
-        common::V1_0::Axis::RTRIGGER);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_THROTTLE) ==
-        common::V1_0::Axis::THROTTLE);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RUDDER) ==
-        common::V1_0::Axis::RUDDER);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_WHEEL) ==
-        common::V1_0::Axis::WHEEL);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GAS) ==
-        common::V1_0::Axis::GAS);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_BRAKE) ==
-        common::V1_0::Axis::BRAKE);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_DISTANCE) ==
-        common::V1_0::Axis::DISTANCE);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TILT) ==
-        common::V1_0::Axis::TILT);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_SCROLL) ==
-        common::V1_0::Axis::SCROLL);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RELATIVE_X) ==
-        common::V1_0::Axis::RELATIVE_X);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RELATIVE_Y) ==
-        common::V1_0::Axis::RELATIVE_Y);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_1) ==
-        common::V1_0::Axis::GENERIC_1);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_2) ==
-        common::V1_0::Axis::GENERIC_2);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_3) ==
-        common::V1_0::Axis::GENERIC_3);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_4) ==
-        common::V1_0::Axis::GENERIC_4);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_5) ==
-        common::V1_0::Axis::GENERIC_5);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_6) ==
-        common::V1_0::Axis::GENERIC_6);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_7) ==
-        common::V1_0::Axis::GENERIC_7);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_8) ==
-        common::V1_0::Axis::GENERIC_8);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_9) ==
-        common::V1_0::Axis::GENERIC_9);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_10) ==
-        common::V1_0::Axis::GENERIC_10);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_11) ==
-        common::V1_0::Axis::GENERIC_11);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_12) ==
-        common::V1_0::Axis::GENERIC_12);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_13) ==
-        common::V1_0::Axis::GENERIC_13);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_14) ==
-        common::V1_0::Axis::GENERIC_14);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_15) ==
-        common::V1_0::Axis::GENERIC_15);
-static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_16) ==
-        common::V1_0::Axis::GENERIC_16);
-
-static common::V1_0::VideoFrame getHalVideoFrame(const TouchVideoFrame& frame) {
-    common::V1_0::VideoFrame out;
-    out.width = frame.getWidth();
-    out.height = frame.getHeight();
-    out.data = frame.getData();
-    struct timeval timestamp = frame.getTimestamp();
-    out.timestamp = seconds_to_nanoseconds(timestamp.tv_sec) +
-             microseconds_to_nanoseconds(timestamp.tv_usec);
-    return out;
-}
-
-static std::vector<common::V1_0::VideoFrame> convertVideoFrames(
-        const std::vector<TouchVideoFrame>& frames) {
-    std::vector<common::V1_0::VideoFrame> out;
-    for (const TouchVideoFrame& frame : frames) {
-        out.push_back(getHalVideoFrame(frame));
-    }
-    return out;
-}
-
-static void getHidlPropertiesAndCoords(const NotifyMotionArgs& args,
-        std::vector<common::V1_0::PointerProperties>* outPointerProperties,
-        std::vector<common::V1_0::PointerCoords>* outPointerCoords) {
-    outPointerProperties->reserve(args.pointerCount);
-    outPointerCoords->reserve(args.pointerCount);
-    for (size_t i = 0; i < args.pointerCount; i++) {
-        common::V1_0::PointerProperties properties;
-        properties.id = args.pointerProperties[i].id;
-        properties.toolType = getToolType(args.pointerProperties[i].toolType);
-        outPointerProperties->push_back(properties);
-
-        common::V1_0::PointerCoords coords;
-        // OK to copy bits because we have static_assert for pointerCoords axes
-        coords.bits = args.pointerCoords[i].bits;
-        coords.values = std::vector<float>(
-                args.pointerCoords[i].values,
-                args.pointerCoords[i].values + BitSet64::count(args.pointerCoords[i].bits));
-        outPointerCoords->push_back(coords);
-    }
-}
-
-common::V1_0::MotionEvent notifyMotionArgsToHalMotionEvent(const NotifyMotionArgs& args) {
-    common::V1_0::MotionEvent event;
-    event.deviceId = args.deviceId;
-    event.source = getSource(args.source);
-    event.displayId = args.displayId;
-    event.downTime = args.downTime;
-    event.eventTime = args.eventTime;
-    event.deviceTimestamp = 0;
-    event.action = getAction(args.action & AMOTION_EVENT_ACTION_MASK);
-    event.actionIndex = MotionEvent::getActionIndex(args.action);
-    event.actionButton = getActionButton(args.actionButton);
-    event.flags = getFlags(args.flags);
-    event.policyFlags = getPolicyFlags(args.policyFlags);
-    event.edgeFlags = getEdgeFlags(args.edgeFlags);
-    event.metaState = getMetastate(args.metaState);
-    event.buttonState = getButtonState(args.buttonState);
-    event.xPrecision = args.xPrecision;
-    event.yPrecision = args.yPrecision;
-
-    std::vector<common::V1_0::PointerProperties> pointerProperties;
-    std::vector<common::V1_0::PointerCoords> pointerCoords;
-    getHidlPropertiesAndCoords(args, /*out*/&pointerProperties, /*out*/&pointerCoords);
-    event.pointerProperties = pointerProperties;
-    event.pointerCoords = pointerCoords;
-
-    event.frames = convertVideoFrames(args.videoFrames);
-
-    return event;
-}
-
-} // namespace android
diff --git a/services/inputflinger/InputCommonConverter.cpp b/services/inputflinger/InputCommonConverter.cpp
new file mode 100644
index 0000000..8aee39f
--- /dev/null
+++ b/services/inputflinger/InputCommonConverter.cpp
@@ -0,0 +1,339 @@
+/*
+ * 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 "InputCommonConverter.h"
+
+using namespace ::aidl::android::hardware::input;
+
+namespace android {
+
+static common::Source getSource(uint32_t source) {
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_UNKNOWN) == common::Source::UNKNOWN,
+                  "SOURCE_UNKNOWN mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_KEYBOARD) == common::Source::KEYBOARD,
+                  "SOURCE_KEYBOARD mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_DPAD) == common::Source::DPAD,
+                  "SOURCE_DPAD mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_GAMEPAD) == common::Source::GAMEPAD,
+                  "SOURCE_GAMEPAD mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_TOUCHSCREEN) ==
+                          common::Source::TOUCHSCREEN,
+                  "SOURCE_TOUCHSCREEN mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_MOUSE) == common::Source::MOUSE,
+                  "SOURCE_MOUSE mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_STYLUS) == common::Source::STYLUS,
+                  "SOURCE_STYLUS mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_BLUETOOTH_STYLUS) ==
+                          common::Source::BLUETOOTH_STYLUS,
+                  "SOURCE_BLUETOOTH_STYLUS mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_TRACKBALL) == common::Source::TRACKBALL,
+                  "SOURCE_TRACKBALL mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_MOUSE_RELATIVE) ==
+                          common::Source::MOUSE_RELATIVE,
+                  "SOURCE_MOUSE_RELATIVE mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_TOUCHPAD) == common::Source::TOUCHPAD,
+                  "SOURCE_TOUCHPAD mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_TOUCH_NAVIGATION) ==
+                          common::Source::TOUCH_NAVIGATION,
+                  "SOURCE_TOUCH_NAVIGATION mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_JOYSTICK) == common::Source::JOYSTICK,
+                  "SOURCE_JOYSTICK mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_ROTARY_ENCODER) ==
+                          common::Source::ROTARY_ENCODER,
+                  "SOURCE_ROTARY_ENCODER mismatch");
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_HDMI) == common::Source::HDMI);
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_SENSOR) == common::Source::SENSOR);
+    static_assert(static_cast<common::Source>(AINPUT_SOURCE_ANY) == common::Source::ANY,
+                  "SOURCE_ANY mismatch");
+    return static_cast<common::Source>(source);
+}
+
+static common::Action getAction(int32_t actionMasked) {
+    static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_DOWN) == common::Action::DOWN,
+                  "ACTION_DOWN mismatch");
+    static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_UP) == common::Action::UP,
+                  "ACTION_UP mismatch");
+    static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_MOVE) == common::Action::MOVE,
+                  "ACTION_MOVE mismatch");
+    static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_CANCEL) ==
+                          common::Action::CANCEL,
+                  "ACTION_CANCEL mismatch");
+    static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_OUTSIDE) ==
+                          common::Action::OUTSIDE,
+                  "ACTION_OUTSIDE mismatch");
+    static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_POINTER_DOWN) ==
+                          common::Action::POINTER_DOWN,
+                  "ACTION_POINTER_DOWN mismatch");
+    static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_POINTER_UP) ==
+                          common::Action::POINTER_UP,
+                  "ACTION_POINTER_UP mismatch");
+    static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_HOVER_MOVE) ==
+                          common::Action::HOVER_MOVE,
+                  "ACTION_HOVER_MOVE mismatch");
+    static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_SCROLL) ==
+                          common::Action::SCROLL,
+                  "ACTION_SCROLL mismatch");
+    static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_HOVER_ENTER) ==
+                          common::Action::HOVER_ENTER,
+                  "ACTION_HOVER_ENTER mismatch");
+    static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_HOVER_EXIT) ==
+                          common::Action::HOVER_EXIT,
+                  "ACTION_HOVER_EXIT mismatch");
+    static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_BUTTON_PRESS) ==
+                          common::Action::BUTTON_PRESS,
+                  "ACTION_BUTTON_PRESS mismatch");
+    static_assert(static_cast<common::Action>(AMOTION_EVENT_ACTION_BUTTON_RELEASE) ==
+                          common::Action::BUTTON_RELEASE,
+                  "ACTION_BUTTON_RELEASE mismatch");
+    return static_cast<common::Action>(actionMasked);
+}
+
+static common::Button getActionButton(int32_t actionButton) {
+    static_assert(static_cast<common::Button>(0) == common::Button::NONE, "BUTTON_NONE mismatch");
+    static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_PRIMARY) ==
+                          common::Button::PRIMARY,
+                  "BUTTON_PRIMARY mismatch");
+    static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_SECONDARY) ==
+                          common::Button::SECONDARY,
+                  "BUTTON_SECONDARY mismatch");
+    static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_TERTIARY) ==
+                          common::Button::TERTIARY,
+                  "BUTTON_TERTIARY mismatch");
+    static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_BACK) == common::Button::BACK,
+                  "BUTTON_BACK mismatch");
+    static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_FORWARD) ==
+                          common::Button::FORWARD,
+                  "BUTTON_FORWARD mismatch");
+    static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) ==
+                          common::Button::STYLUS_PRIMARY,
+                  "BUTTON_STYLUS_PRIMARY mismatch");
+    static_assert(static_cast<common::Button>(AMOTION_EVENT_BUTTON_STYLUS_SECONDARY) ==
+                          common::Button::STYLUS_SECONDARY,
+                  "BUTTON_STYLUS_SECONDARY mismatch");
+    return static_cast<common::Button>(actionButton);
+}
+
+static common::Flag getFlags(int32_t flags) {
+    static_assert(static_cast<common::Flag>(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED) ==
+                  common::Flag::WINDOW_IS_OBSCURED);
+    static_assert(static_cast<common::Flag>(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE) ==
+                  common::Flag::IS_GENERATED_GESTURE);
+    static_assert(static_cast<common::Flag>(AMOTION_EVENT_FLAG_TAINTED) == common::Flag::TAINTED);
+    return static_cast<common::Flag>(flags);
+}
+
+static common::PolicyFlag getPolicyFlags(int32_t flags) {
+    static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_WAKE) == common::PolicyFlag::WAKE);
+    static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_VIRTUAL) ==
+                  common::PolicyFlag::VIRTUAL);
+    static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_FUNCTION) ==
+                  common::PolicyFlag::FUNCTION);
+    static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_GESTURE) ==
+                  common::PolicyFlag::GESTURE);
+    static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_INJECTED) ==
+                  common::PolicyFlag::INJECTED);
+    static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_TRUSTED) ==
+                  common::PolicyFlag::TRUSTED);
+    static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_FILTERED) ==
+                  common::PolicyFlag::FILTERED);
+    static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_DISABLE_KEY_REPEAT) ==
+                  common::PolicyFlag::DISABLE_KEY_REPEAT);
+    static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_INTERACTIVE) ==
+                  common::PolicyFlag::INTERACTIVE);
+    static_assert(static_cast<common::PolicyFlag>(POLICY_FLAG_PASS_TO_USER) ==
+                  common::PolicyFlag::PASS_TO_USER);
+    return static_cast<common::PolicyFlag>(flags);
+}
+
+static common::EdgeFlag getEdgeFlags(int32_t flags) {
+    static_assert(static_cast<common::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_NONE) ==
+                  common::EdgeFlag::NONE);
+    static_assert(static_cast<common::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_TOP) ==
+                  common::EdgeFlag::TOP);
+    static_assert(static_cast<common::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_BOTTOM) ==
+                  common::EdgeFlag::BOTTOM);
+    static_assert(static_cast<common::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_LEFT) ==
+                  common::EdgeFlag::LEFT);
+    static_assert(static_cast<common::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_RIGHT) ==
+                  common::EdgeFlag::RIGHT);
+    return static_cast<common::EdgeFlag>(flags);
+}
+
+static common::Meta getMetastate(int32_t state) {
+    static_assert(static_cast<common::Meta>(AMETA_NONE) == common::Meta::NONE);
+    static_assert(static_cast<common::Meta>(AMETA_ALT_ON) == common::Meta::ALT_ON);
+    static_assert(static_cast<common::Meta>(AMETA_ALT_LEFT_ON) == common::Meta::ALT_LEFT_ON);
+    static_assert(static_cast<common::Meta>(AMETA_ALT_RIGHT_ON) == common::Meta::ALT_RIGHT_ON);
+    static_assert(static_cast<common::Meta>(AMETA_SHIFT_ON) == common::Meta::SHIFT_ON);
+    static_assert(static_cast<common::Meta>(AMETA_SHIFT_LEFT_ON) == common::Meta::SHIFT_LEFT_ON);
+    static_assert(static_cast<common::Meta>(AMETA_SHIFT_RIGHT_ON) == common::Meta::SHIFT_RIGHT_ON);
+    static_assert(static_cast<common::Meta>(AMETA_SYM_ON) == common::Meta::SYM_ON);
+    static_assert(static_cast<common::Meta>(AMETA_FUNCTION_ON) == common::Meta::FUNCTION_ON);
+    static_assert(static_cast<common::Meta>(AMETA_CTRL_ON) == common::Meta::CTRL_ON);
+    static_assert(static_cast<common::Meta>(AMETA_CTRL_LEFT_ON) == common::Meta::CTRL_LEFT_ON);
+    static_assert(static_cast<common::Meta>(AMETA_CTRL_RIGHT_ON) == common::Meta::CTRL_RIGHT_ON);
+    static_assert(static_cast<common::Meta>(AMETA_META_ON) == common::Meta::META_ON);
+    static_assert(static_cast<common::Meta>(AMETA_META_LEFT_ON) == common::Meta::META_LEFT_ON);
+    static_assert(static_cast<common::Meta>(AMETA_META_RIGHT_ON) == common::Meta::META_RIGHT_ON);
+    static_assert(static_cast<common::Meta>(AMETA_CAPS_LOCK_ON) == common::Meta::CAPS_LOCK_ON);
+    static_assert(static_cast<common::Meta>(AMETA_NUM_LOCK_ON) == common::Meta::NUM_LOCK_ON);
+    static_assert(static_cast<common::Meta>(AMETA_SCROLL_LOCK_ON) == common::Meta::SCROLL_LOCK_ON);
+    return static_cast<common::Meta>(state);
+}
+
+static common::Button getButtonState(int32_t buttonState) {
+    // No need for static_assert here.
+    // The button values have already been asserted in getActionButton(..) above
+    return static_cast<common::Button>(buttonState);
+}
+
+static common::ToolType getToolType(int32_t toolType) {
+    static_assert(static_cast<common::ToolType>(AMOTION_EVENT_TOOL_TYPE_UNKNOWN) ==
+                  common::ToolType::UNKNOWN);
+    static_assert(static_cast<common::ToolType>(AMOTION_EVENT_TOOL_TYPE_FINGER) ==
+                  common::ToolType::FINGER);
+    static_assert(static_cast<common::ToolType>(AMOTION_EVENT_TOOL_TYPE_STYLUS) ==
+                  common::ToolType::STYLUS);
+    static_assert(static_cast<common::ToolType>(AMOTION_EVENT_TOOL_TYPE_MOUSE) ==
+                  common::ToolType::MOUSE);
+    static_assert(static_cast<common::ToolType>(AMOTION_EVENT_TOOL_TYPE_ERASER) ==
+                  common::ToolType::ERASER);
+    return static_cast<common::ToolType>(toolType);
+}
+
+// MotionEvent axes asserts
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_X) == common::Axis::X);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_Y) == common::Axis::Y);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_PRESSURE) == common::Axis::PRESSURE);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_SIZE) == common::Axis::SIZE);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_TOUCH_MAJOR) ==
+              common::Axis::TOUCH_MAJOR);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_TOUCH_MINOR) ==
+              common::Axis::TOUCH_MINOR);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_TOOL_MAJOR) == common::Axis::TOOL_MAJOR);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_TOOL_MINOR) == common::Axis::TOOL_MINOR);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_ORIENTATION) ==
+              common::Axis::ORIENTATION);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_VSCROLL) == common::Axis::VSCROLL);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_HSCROLL) == common::Axis::HSCROLL);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_Z) == common::Axis::Z);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RX) == common::Axis::RX);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RY) == common::Axis::RY);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RZ) == common::Axis::RZ);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_HAT_X) == common::Axis::HAT_X);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_HAT_Y) == common::Axis::HAT_Y);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_LTRIGGER) == common::Axis::LTRIGGER);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RTRIGGER) == common::Axis::RTRIGGER);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_THROTTLE) == common::Axis::THROTTLE);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RUDDER) == common::Axis::RUDDER);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_WHEEL) == common::Axis::WHEEL);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GAS) == common::Axis::GAS);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_BRAKE) == common::Axis::BRAKE);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_DISTANCE) == common::Axis::DISTANCE);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_TILT) == common::Axis::TILT);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_SCROLL) == common::Axis::SCROLL);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RELATIVE_X) == common::Axis::RELATIVE_X);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_RELATIVE_Y) == common::Axis::RELATIVE_Y);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_1) == common::Axis::GENERIC_1);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_2) == common::Axis::GENERIC_2);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_3) == common::Axis::GENERIC_3);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_4) == common::Axis::GENERIC_4);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_5) == common::Axis::GENERIC_5);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_6) == common::Axis::GENERIC_6);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_7) == common::Axis::GENERIC_7);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_8) == common::Axis::GENERIC_8);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_9) == common::Axis::GENERIC_9);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_10) == common::Axis::GENERIC_10);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_11) == common::Axis::GENERIC_11);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_12) == common::Axis::GENERIC_12);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_13) == common::Axis::GENERIC_13);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_14) == common::Axis::GENERIC_14);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_15) == common::Axis::GENERIC_15);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_16) == common::Axis::GENERIC_16);
+
+static common::VideoFrame getHalVideoFrame(const TouchVideoFrame& frame) {
+    common::VideoFrame out;
+    out.width = frame.getWidth();
+    out.height = frame.getHeight();
+    std::vector<char16_t> unsignedData(frame.getData().begin(), frame.getData().end());
+    out.data = unsignedData;
+    struct timeval timestamp = frame.getTimestamp();
+    out.timestamp = seconds_to_nanoseconds(timestamp.tv_sec) +
+            microseconds_to_nanoseconds(timestamp.tv_usec);
+    return out;
+}
+
+static std::vector<common::VideoFrame> convertVideoFrames(
+        const std::vector<TouchVideoFrame>& frames) {
+    std::vector<common::VideoFrame> out;
+    for (const TouchVideoFrame& frame : frames) {
+        out.push_back(getHalVideoFrame(frame));
+    }
+    return out;
+}
+
+static void getHalPropertiesAndCoords(const NotifyMotionArgs& args,
+                                      std::vector<common::PointerProperties>& outPointerProperties,
+                                      std::vector<common::PointerCoords>& outPointerCoords) {
+    outPointerProperties.reserve(args.pointerCount);
+    outPointerCoords.reserve(args.pointerCount);
+    for (size_t i = 0; i < args.pointerCount; i++) {
+        common::PointerProperties properties;
+        properties.id = args.pointerProperties[i].id;
+        properties.toolType = getToolType(args.pointerProperties[i].toolType);
+        outPointerProperties.push_back(properties);
+
+        common::PointerCoords coords;
+        // OK to copy bits because we have static_assert for pointerCoords axes
+        coords.bits = args.pointerCoords[i].bits;
+        coords.values = std::vector<float>(args.pointerCoords[i].values,
+                                           args.pointerCoords[i].values +
+                                                   BitSet64::count(args.pointerCoords[i].bits));
+        outPointerCoords.push_back(coords);
+    }
+}
+
+common::MotionEvent notifyMotionArgsToHalMotionEvent(const NotifyMotionArgs& args) {
+    common::MotionEvent event;
+    event.deviceId = args.deviceId;
+    event.source = getSource(args.source);
+    event.displayId = args.displayId;
+    event.downTime = args.downTime;
+    event.eventTime = args.eventTime;
+    event.deviceTimestamp = 0;
+    event.action = getAction(args.action & AMOTION_EVENT_ACTION_MASK);
+    event.actionIndex = MotionEvent::getActionIndex(args.action);
+    event.actionButton = getActionButton(args.actionButton);
+    event.flags = getFlags(args.flags);
+    event.policyFlags = getPolicyFlags(args.policyFlags);
+    event.edgeFlags = getEdgeFlags(args.edgeFlags);
+    event.metaState = getMetastate(args.metaState);
+    event.buttonState = getButtonState(args.buttonState);
+    event.xPrecision = args.xPrecision;
+    event.yPrecision = args.yPrecision;
+
+    std::vector<common::PointerProperties> pointerProperties;
+    std::vector<common::PointerCoords> pointerCoords;
+    getHalPropertiesAndCoords(args, /*out*/ pointerProperties, /*out*/ pointerCoords);
+    event.pointerProperties = pointerProperties;
+    event.pointerCoords = pointerCoords;
+
+    event.frames = convertVideoFrames(args.videoFrames);
+
+    return event;
+}
+
+} // namespace android
diff --git a/services/inputflinger/InputClassifierConverter.h b/services/inputflinger/InputCommonConverter.h
similarity index 65%
rename from services/inputflinger/InputClassifierConverter.h
rename to services/inputflinger/InputCommonConverter.h
index 5154b0b..4d3b768 100644
--- a/services/inputflinger/InputClassifierConverter.h
+++ b/services/inputflinger/InputCommonConverter.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 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,21 +14,18 @@
  * limitations under the License.
  */
 
-#ifndef _UI_INPUT_CLASSIFIER_CONVERTER_H
-#define _UI_INPUT_CLASSIFIER_CONVERTER_H
+#pragma once
 
+#include <aidl/android/hardware/input/common/Axis.h>
+#include <aidl/android/hardware/input/common/MotionEvent.h>
 #include "InputListener.h"
-#include <android/hardware/input/common/1.0/types.h>
-
 
 namespace android {
 
 /**
- * Convert from framework's NotifyMotionArgs to hidl's common::V1_0::MotionEvent
+ * Convert from framework's NotifyMotionArgs to hidl's common::MotionEvent
  */
-::android::hardware::input::common::V1_0::MotionEvent notifyMotionArgsToHalMotionEvent(
+::aidl::android::hardware::input::common::MotionEvent notifyMotionArgsToHalMotionEvent(
         const NotifyMotionArgs& args);
 
 } // namespace android
-
-#endif // _UI_INPUT_CLASSIFIER_CONVERTER_H
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 7a9862d..7b03631 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -33,8 +33,6 @@
 namespace android {
 
 using gui::FocusRequest;
-using gui::WindowInfo;
-using gui::WindowInfoHandle;
 
 static int32_t exceptionCodeFromStatusT(status_t status) {
     switch (status) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6c321bc..7062aef 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -4920,7 +4920,7 @@
             const sp<IBinder> focusedToken =
                     mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
 
-            //  TODO(b/198487159): if no window is currently focused, then we need to check the last
+            //  TODO(b/218541064): if no window is currently focused, then we need to check the last
             //      interacted window (within 1 second timeout). We should allow touch mode change
             //      if the last interacted window owner's pid/uid match the calling ones.
             if (focusedToken == nullptr) {
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 51546ce..3bd3275 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -71,6 +71,7 @@
         "libstatslog",
         "libui",
         "libutils",
+        "PlatformProperties",
     ],
     static_libs: [
         "libc++fs",
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index db67877..8bd3899 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -685,7 +685,7 @@
     mEpollFd = epoll_create1(EPOLL_CLOEXEC);
     LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
 
-    mINotifyFd = inotify_init();
+    mINotifyFd = inotify_init1(IN_CLOEXEC);
 
     std::error_code errorCode;
     bool isDeviceInotifyAdded = false;
@@ -713,7 +713,7 @@
     LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance.  errno=%d", errno);
 
     int wakeFds[2];
-    result = pipe(wakeFds);
+    result = pipe2(wakeFds, O_CLOEXEC);
     LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
 
     mWakeReadPipeFd = wakeFds[0];
diff --git a/services/inputflinger/reader/TouchVideoDevice.cpp b/services/inputflinger/reader/TouchVideoDevice.cpp
index c7c8e28..2f8138b 100644
--- a/services/inputflinger/reader/TouchVideoDevice.cpp
+++ b/services/inputflinger/reader/TouchVideoDevice.cpp
@@ -49,7 +49,7 @@
 };
 
 std::unique_ptr<TouchVideoDevice> TouchVideoDevice::create(std::string devicePath) {
-    unique_fd fd(open(devicePath.c_str(), O_RDWR | O_NONBLOCK));
+    unique_fd fd(open(devicePath.c_str(), O_RDWR | O_NONBLOCK | O_CLOEXEC));
     if (fd.get() == INVALID_FD) {
         ALOGE("Could not open video device %s: %s", devicePath.c_str(), strerror(errno));
         return nullptr;
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index ff3a592..41a8426 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -18,6 +18,8 @@
 
 #include "MultiTouchInputMapper.h"
 
+#include <android/sysprop/InputProperties.sysprop.h>
+
 namespace android {
 
 // --- Constants ---
@@ -309,6 +311,10 @@
                 outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
             }
         }
+        if (shouldSimulateStylusWithTouch() &&
+            outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER) {
+            outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+        }
 
         bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE &&
                 (mTouchButtonAccumulator.isHovering() ||
@@ -385,7 +391,15 @@
 }
 
 bool MultiTouchInputMapper::hasStylus() const {
-    return mMultiTouchMotionAccumulator.hasStylus() || mTouchButtonAccumulator.hasStylus();
+    return mMultiTouchMotionAccumulator.hasStylus() || mTouchButtonAccumulator.hasStylus() ||
+            shouldSimulateStylusWithTouch();
+}
+
+bool MultiTouchInputMapper::shouldSimulateStylusWithTouch() const {
+    static const bool SIMULATE_STYLUS_WITH_TOUCH =
+            sysprop::InputProperties::simulate_stylus_with_touch().value_or(false);
+    return SIMULATE_STYLUS_WITH_TOUCH &&
+            mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN;
 }
 
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index 225ad49..b7c3457 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -104,6 +104,14 @@
     bool hasStylus() const override;
 
 private:
+    // simulate_stylus_with_touch is a debug mode that converts all finger pointers reported by this
+    // mapper's touchscreen into stylus pointers, and adds SOURCE_STYLUS to the input device.
+    // It is used to simulate stylus events for debugging and testing on a device that does not
+    // support styluses. It can be enabled using
+    // "adb shell setprop persist.debug.input.simulate_stylus_with_touch true",
+    // and requires a reboot to take effect.
+    inline bool shouldSimulateStylusWithTouch() const;
+
     // If the slot is in use, return the bit id. Return std::nullopt otherwise.
     std::optional<int32_t> getActiveBitId(const MultiTouchMotionAccumulator::Slot& inSlot);
     MultiTouchMotionAccumulator mMultiTouchMotionAccumulator;
diff --git a/services/inputflinger/tests/InputClassifierConverter_test.cpp b/services/inputflinger/tests/InputClassifierConverter_test.cpp
index f626d56..81ef9b9 100644
--- a/services/inputflinger/tests/InputClassifierConverter_test.cpp
+++ b/services/inputflinger/tests/InputClassifierConverter_test.cpp
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-#include "../InputClassifierConverter.h"
+#include "../InputCommonConverter.h"
 
 #include <gtest/gtest.h>
 #include <gui/constants.h>
 #include <utils/BitSet.h>
 
-using namespace android::hardware::input;
+using namespace aidl::android::hardware::input;
 
 namespace android {
 
@@ -50,8 +50,7 @@
     return motionArgs;
 }
 
-static float getMotionEventAxis(common::V1_0::PointerCoords coords,
-        common::V1_0::Axis axis) {
+static float getMotionEventAxis(common::PointerCoords coords, common::Axis axis) {
     uint32_t index = BitSet64::getIndexOfBit(static_cast<uint64_t>(coords.bits),
             static_cast<uint64_t>(axis));
     return coords.values[index];
@@ -68,14 +67,14 @@
     ASSERT_EQ(0.5, motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SIZE));
     ASSERT_EQ(3U, BitSet64::count(motionArgs.pointerCoords[0].bits));
 
-    common::V1_0::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(motionArgs);
+    common::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(motionArgs);
 
-    ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::V1_0::Axis::X),
-            motionArgs.pointerCoords[0].getX());
-    ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::V1_0::Axis::Y),
-            motionArgs.pointerCoords[0].getY());
-    ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::V1_0::Axis::SIZE),
-            motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SIZE));
+    ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::Axis::X),
+              motionArgs.pointerCoords[0].getX());
+    ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::Axis::Y),
+              motionArgs.pointerCoords[0].getY());
+    ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::Axis::SIZE),
+              motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SIZE));
     ASSERT_EQ(BitSet64::count(motionArgs.pointerCoords[0].bits),
             BitSet64::count(motionEvent.pointerCoords[0].bits));
 }
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp
index f13187d..3a77127 100644
--- a/services/inputflinger/tests/InputClassifier_test.cpp
+++ b/services/inputflinger/tests/InputClassifier_test.cpp
@@ -20,12 +20,14 @@
 
 #include "TestInputListener.h"
 
-#include <android/hardware/input/classifier/1.0/IInputClassifier.h>
+#include <aidl/android/hardware/input/processor/BnInputProcessor.h>
+#include <aidl/android/hardware/input/processor/IInputProcessor.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
 
-using namespace android::hardware::input;
-using android::hardware::Return;
-using android::hardware::Void;
-using android::hardware::input::common::V1_0::Classification;
+using namespace aidl::android::hardware::input;
+using aidl::android::hardware::input::common::Classification;
+using aidl::android::hardware::input::processor::IInputProcessor;
 
 namespace android {
 
@@ -154,22 +156,17 @@
 /**
  * A minimal implementation of IInputClassifier.
  */
-struct TestHal : public android::hardware::input::classifier::V1_0::IInputClassifier {
-    Return<Classification> classify(
-            const android::hardware::input::common::V1_0::MotionEvent& event) override {
-        return Classification::NONE;
-    };
-    Return<void> reset() override { return Void(); };
-    Return<void> resetDevice(int32_t deviceId) override { return Void(); };
-};
-
-/**
- * An entity that will be subscribed to the HAL death.
- */
-class TestDeathRecipient : public android::hardware::hidl_death_recipient {
-public:
-    virtual void serviceDied(uint64_t cookie,
-                             const wp<android::hidl::base::V1_0::IBase>& who) override{};
+class TestHal : public aidl::android::hardware::input::processor::BnInputProcessor {
+    ::ndk::ScopedAStatus classify(
+            const ::aidl::android::hardware::input::common::MotionEvent& in_event,
+            ::aidl::android::hardware::input::common::Classification* _aidl_return) override {
+        *_aidl_return = Classification::NONE;
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus reset() override { return ndk::ScopedAStatus::ok(); }
+    ::ndk::ScopedAStatus resetDevice(int32_t in_deviceId) override {
+        return ndk::ScopedAStatus::ok();
+    }
 };
 
 // --- MotionClassifierTest ---
@@ -178,15 +175,9 @@
 protected:
     std::unique_ptr<MotionClassifierInterface> mMotionClassifier;
 
-    virtual void SetUp() override {
-        mMotionClassifier = MotionClassifier::create(new TestDeathRecipient());
-        if (mMotionClassifier == nullptr) {
-            // If the device running this test does not have IInputClassifier service,
-            // use the test HAL instead.
-            // Using 'new' to access non-public constructor
-            mMotionClassifier =
-                    std::unique_ptr<MotionClassifier>(new MotionClassifier(new TestHal()));
-        }
+    void SetUp() override {
+        std::shared_ptr<IInputProcessor> service = ndk::SharedRefBase::make<TestHal>();
+        mMotionClassifier = MotionClassifier::create(std::move(service));
     }
 };
 
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 872882e..813acd8 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -21,6 +21,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/thread_annotations.h>
 #include <binder/Binder.h>
+#include <fcntl.h>
 #include <gtest/gtest.h>
 #include <input/Input.h>
 #include <linux/input.h>
@@ -6224,33 +6225,57 @@
         mApp = std::make_shared<FakeApplicationHandle>();
         mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
         mWindow->setFocusable(true);
+        setFocusedWindow(mWindow);
         mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
         mSecondWindow->setFocusable(true);
 
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
         mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
-
-        setFocusedWindow(mWindow);
         mWindow->consumeFocusEvent(true);
+
+        // Set initial touch mode to InputDispatcher::kDefaultInTouchMode.
+        mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
+                                    INJECTOR_UID, /* hasPermission */ true);
     }
 
     void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) {
-        mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission);
+        ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission));
         mWindow->consumeTouchModeEvent(inTouchMode);
         mSecondWindow->consumeTouchModeEvent(inTouchMode);
     }
 };
 
-TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchModeOnFocusedWindow) {
+TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
     const WindowInfo& windowInfo = *mWindow->getInfo();
     changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid,
                              windowInfo.ownerUid, /* hasPermission */ false);
 }
 
+TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
+    const WindowInfo& windowInfo = *mWindow->getInfo();
+    int32_t ownerPid = windowInfo.ownerPid;
+    int32_t ownerUid = windowInfo.ownerUid;
+    mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1);
+    ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
+                                             ownerUid, /* hasPermission */ false));
+    mWindow->assertNoEvents();
+    mSecondWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) {
+    const WindowInfo& windowInfo = *mWindow->getInfo();
+    int32_t ownerPid = windowInfo.ownerPid;
+    int32_t ownerUid = windowInfo.ownerUid;
+    mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1);
+    changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, ownerPid, ownerUid,
+                             /* hasPermission */ true);
+}
+
 TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
     const WindowInfo& windowInfo = *mWindow->getInfo();
-    mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid,
-                                windowInfo.ownerUid, /* hasPermission */ true);
+    ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode,
+                                             windowInfo.ownerPid, windowInfo.ownerUid,
+                                             /* hasPermission */ true));
     mWindow->assertNoEvents();
     mSecondWindow->assertNoEvents();
 }
@@ -6331,7 +6356,7 @@
     const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
     const size_t numChannels = channels.size();
 
-    base::unique_fd epollFd(epoll_create1(0 /*flags*/));
+    base::unique_fd epollFd(epoll_create1(EPOLL_CLOEXEC));
     if (!epollFd.ok()) {
         FAIL() << "Failed to create epoll fd";
     }
@@ -6820,7 +6845,4 @@
     window->assertNoEvents();
 }
 
-// TODO(b/198487159): Add permission tests for touch mode switch once the validation is put in
-//     place.
-
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp
index 132b877..9c93919 100644
--- a/services/inputflinger/tests/UinputDevice.cpp
+++ b/services/inputflinger/tests/UinputDevice.cpp
@@ -17,6 +17,7 @@
 #include "UinputDevice.h"
 
 #include <android-base/stringprintf.h>
+#include <fcntl.h>
 
 namespace android {
 
@@ -32,7 +33,7 @@
 }
 
 void UinputDevice::init() {
-    mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK));
+    mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK | O_CLOEXEC));
     if (mDeviceFd < 0) {
         FAIL() << "Can't open /dev/uinput :" << strerror(errno);
     }
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 40fc342..02e444d 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -416,8 +416,14 @@
             ? bufferData.acquireFence
             : Fence::NO_FENCE;
     mDrawingState.acquireFenceTime = std::make_unique<FenceTime>(mDrawingState.acquireFence);
-    // The acquire fences of BufferStateLayers have already signaled before they are set
-    mCallbackHandleAcquireTime = mDrawingState.acquireFenceTime->getSignalTime();
+    if (mDrawingState.acquireFenceTime->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
+        // We latched this buffer unsiganled, so we need to pass the acquire fence
+        // on the callback instead of just the acquire time, since it's unknown at
+        // this point.
+        mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFence;
+    } else {
+        mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFenceTime->getSignalTime();
+    }
 
     mDrawingState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -527,7 +533,7 @@
         // If this layer will be presented in this frame
         if (willPresent) {
             // If this transaction set an acquire fence on this layer, set its acquire time
-            handle->acquireTime = mCallbackHandleAcquireTime;
+            handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence;
             handle->frameNumber = mDrawingState.frameNumber;
 
             // Store so latched time and release fence can be set
@@ -540,7 +546,7 @@
     }
 
     mReleasePreviousBuffer = false;
-    mCallbackHandleAcquireTime = -1;
+    mCallbackHandleAcquireTimeOrFence = -1;
 
     return willPresent;
 }
@@ -918,4 +924,183 @@
     return mDrawingState.transform.transform(bufferBounds);
 }
 
+bool BufferStateLayer::simpleBufferUpdate(const layer_state_t& s) const {
+    const uint64_t requiredFlags = layer_state_t::eBufferChanged;
+
+    const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged |
+            layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged |
+            layer_state_t::eFlagsChanged | layer_state_t::eBlurRegionsChanged |
+            layer_state_t::eLayerStackChanged | layer_state_t::eAutoRefreshChanged |
+            layer_state_t::eReparent;
+
+    const uint64_t allowedFlags = layer_state_t::eHasListenerCallbacksChanged |
+            layer_state_t::eFrameRateSelectionPriority | layer_state_t::eFrameRateChanged |
+            layer_state_t::eSurfaceDamageRegionChanged | layer_state_t::eApiChanged |
+            layer_state_t::eMetadataChanged | layer_state_t::eDropInputModeChanged |
+            layer_state_t::eInputInfoChanged;
+
+    if ((s.what & requiredFlags) != requiredFlags) {
+        ALOGV("%s: false [missing required flags 0x%" PRIx64 "]", __func__,
+              (s.what | requiredFlags) & ~s.what);
+        return false;
+    }
+
+    if (s.what & deniedFlags) {
+        ALOGV("%s: false [has denied flags 0x%" PRIx64 "]", __func__, s.what & deniedFlags);
+        return false;
+    }
+
+    if (s.what & allowedFlags) {
+        ALOGV("%s: [has allowed flags 0x%" PRIx64 "]", __func__, s.what & allowedFlags);
+    }
+
+    if (s.what & layer_state_t::ePositionChanged) {
+        if (mRequestedTransform.tx() != s.x || mRequestedTransform.ty() != s.y) {
+            ALOGV("%s: false [ePositionChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eAlphaChanged) {
+        if (mDrawingState.color.a != s.alpha) {
+            ALOGV("%s: false [eAlphaChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eColorTransformChanged) {
+        if (mDrawingState.colorTransform != s.colorTransform) {
+            ALOGV("%s: false [eColorTransformChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eBackgroundColorChanged) {
+        if (mDrawingState.bgColorLayer || s.bgColorAlpha != 0) {
+            ALOGV("%s: false [eBackgroundColorChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eMatrixChanged) {
+        if (mRequestedTransform.dsdx() != s.matrix.dsdx ||
+            mRequestedTransform.dtdy() != s.matrix.dtdy ||
+            mRequestedTransform.dtdx() != s.matrix.dtdx ||
+            mRequestedTransform.dsdy() != s.matrix.dsdy) {
+            ALOGV("%s: false [eMatrixChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eCornerRadiusChanged) {
+        if (mDrawingState.cornerRadius != s.cornerRadius) {
+            ALOGV("%s: false [eCornerRadiusChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eBackgroundBlurRadiusChanged) {
+        if (mDrawingState.backgroundBlurRadius != static_cast<int>(s.backgroundBlurRadius)) {
+            ALOGV("%s: false [eBackgroundBlurRadiusChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eTransformChanged) {
+        if (mDrawingState.bufferTransform != s.transform) {
+            ALOGV("%s: false [eTransformChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eTransformToDisplayInverseChanged) {
+        if (mDrawingState.transformToDisplayInverse != s.transformToDisplayInverse) {
+            ALOGV("%s: false [eTransformToDisplayInverseChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eCropChanged) {
+        if (mDrawingState.crop != s.crop) {
+            ALOGV("%s: false [eCropChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eDataspaceChanged) {
+        if (mDrawingState.dataspace != s.dataspace) {
+            ALOGV("%s: false [eDataspaceChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eHdrMetadataChanged) {
+        if (mDrawingState.hdrMetadata != s.hdrMetadata) {
+            ALOGV("%s: false [eHdrMetadataChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eSidebandStreamChanged) {
+        if (mDrawingState.sidebandStream != s.sidebandStream) {
+            ALOGV("%s: false [eSidebandStreamChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eColorSpaceAgnosticChanged) {
+        if (mDrawingState.colorSpaceAgnostic != s.colorSpaceAgnostic) {
+            ALOGV("%s: false [eColorSpaceAgnosticChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eShadowRadiusChanged) {
+        if (mDrawingState.shadowRadius != s.shadowRadius) {
+            ALOGV("%s: false [eShadowRadiusChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eFixedTransformHintChanged) {
+        if (mDrawingState.fixedTransformHint != s.fixedTransformHint) {
+            ALOGV("%s: false [eFixedTransformHintChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eTrustedOverlayChanged) {
+        if (mDrawingState.isTrustedOverlay != s.isTrustedOverlay) {
+            ALOGV("%s: false [eTrustedOverlayChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eStretchChanged) {
+        StretchEffect temp = s.stretchEffect;
+        temp.sanitize();
+        if (mDrawingState.stretchEffect != temp) {
+            ALOGV("%s: false [eStretchChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eBufferCropChanged) {
+        if (mDrawingState.bufferCrop != s.bufferCrop) {
+            ALOGV("%s: false [eBufferCropChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    if (s.what & layer_state_t::eDestinationFrameChanged) {
+        if (mDrawingState.destinationFrame != s.destinationFrame) {
+            ALOGV("%s: false [eDestinationFrameChanged changed]", __func__);
+            return false;
+        }
+    }
+
+    ALOGV("%s: true", __func__);
+    return true;
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 248e013..669eaad 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -136,6 +136,8 @@
 
     bool bufferNeedsFiltering() const override;
 
+    bool simpleBufferUpdate(const layer_state_t& s) const override;
+
     ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID;
     uint64_t mPreviousReleasedFrameNumber = 0;
 
@@ -143,7 +145,7 @@
 
     // Stores the last set acquire fence signal time used to populate the callback handle's acquire
     // time.
-    nsecs_t mCallbackHandleAcquireTime = -1;
+    std::variant<nsecs_t, sp<Fence>> mCallbackHandleAcquireTimeOrFence = -1;
 
     std::deque<std::shared_ptr<android::frametimeline::SurfaceFrame>> mPendingJankClassifications;
     // An upper bound on the number of SurfaceFrames in the pending classifications deque.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 08cfaa6..2b383c1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -153,9 +153,11 @@
     // Timestamp for when the layer is queued for client composition
     nsecs_t clientCompositionTimestamp{0};
 
-    // White point of the layer, in nits.
     static constexpr float kDefaultWhitePointNits = 200.f;
     float whitePointNits = kDefaultWhitePointNits;
+    // Dimming ratio of the layer from [0, 1]
+    static constexpr float kDefaultDimmingRatio = 1.f;
+    float dimmingRatio = kDefaultDimmingRatio;
 };
 
 } // namespace compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 29c146b..a3188f3 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -39,6 +39,7 @@
 
 #include "DisplayHardware/PowerAdvisor.h"
 
+using aidl::android::hardware::graphics::composer3::Capability;
 using aidl::android::hardware::graphics::composer3::DisplayCapability;
 
 namespace android::compositionengine::impl {
@@ -284,7 +285,7 @@
                                         DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM);
     }
 
-    return hwc.hasCapability(hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM);
+    return hwc.hasCapability(Capability::SKIP_CLIENT_COLOR_TRANSFORM);
 }
 
 bool Display::anyLayersRequireClientComposition() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 4ccf11f..3e983f3 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -324,9 +324,14 @@
 
     // For hdr content, treat the white point as the display brightness - HDR content should not be
     // boosted or dimmed.
-    if (isHdrDataspace(state.dataspace)) {
+    if (isHdrDataspace(state.dataspace) ||
+        getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits) {
+        state.dimmingRatio = 1.f;
         state.whitePointNits = getOutput().getState().displayBrightnessNits;
     } else {
+        state.dimmingRatio = std::clamp(getOutput().getState().sdrWhitePointNits /
+                                                getOutput().getState().displayBrightnessNits,
+                                        0.f, 1.f);
         state.whitePointNits = getOutput().getState().sdrWhitePointNits;
     }
 
@@ -502,13 +507,12 @@
     }
 
     // Don't dim cached layers
-    const auto whitePointNits = outputDependentState.overrideInfo.buffer
-            ? getOutput().getState().displayBrightnessNits
-            : outputDependentState.whitePointNits;
+    const auto dimmingRatio =
+            outputDependentState.overrideInfo.buffer ? 1.f : outputDependentState.dimmingRatio;
 
-    if (auto error = hwcLayer->setWhitePointNits(whitePointNits); error != hal::Error::NONE) {
-        ALOGE("[%s] Failed to set white point %f: %s (%d)", getLayerFE().getDebugName(),
-              whitePointNits, to_string(error).c_str(), static_cast<int32_t>(error));
+    if (auto error = hwcLayer->setBrightness(dimmingRatio); error != hal::Error::NONE) {
+        ALOGE("[%s] Failed to set brightness %f: %s (%d)", getLayerFE().getDebugName(),
+              dimmingRatio, to_string(error).c_str(), static_cast<int32_t>(error));
     }
 }
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 125ce74..44d34a3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -41,6 +41,7 @@
 
 #include <aidl/android/hardware/graphics/composer3/Composition.h>
 
+using aidl::android::hardware::graphics::composer3::Capability;
 using aidl::android::hardware::graphics::composer3::Composition;
 
 namespace android::compositionengine {
@@ -672,7 +673,7 @@
 using aidl::android::hardware::graphics::composer3::DisplayCapability;
 
 TEST_F(DisplayGetSkipColorTransformTest, checksCapabilityIfGpuDisplay) {
-    EXPECT_CALL(mHwComposer, hasCapability(hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM))
+    EXPECT_CALL(mHwComposer, hasCapability(Capability::SKIP_CLIENT_COLOR_TRANSFORM))
             .WillOnce(Return(true));
     auto args = getDisplayCreationArgsForGpuVirtualDisplay();
     auto gpuDisplay{impl::createDisplay(mCompositionEngine, args)};
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index 5185ea9..d933b94 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -74,7 +74,7 @@
     MOCK_METHOD1(setColorTransform, Error(const android::mat4&));
     MOCK_METHOD3(setLayerGenericMetadata,
                  Error(const std::string&, bool, const std::vector<uint8_t>&));
-    MOCK_METHOD1(setWhitePointNits, Error(float));
+    MOCK_METHOD1(setBrightness, Error(float));
     MOCK_METHOD1(setBlockingRegion, Error(const android::Region&));
 };
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 660f664..719f15c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -42,7 +42,8 @@
     MOCK_METHOD1(setCallback, void(HWC2::ComposerCallback&));
     MOCK_CONST_METHOD3(getDisplayIdentificationData,
                        bool(hal::HWDisplayId, uint8_t*, DisplayIdentificationData*));
-    MOCK_CONST_METHOD1(hasCapability, bool(hal::Capability));
+    MOCK_CONST_METHOD1(hasCapability,
+                       bool(aidl::android::hardware::graphics::composer3::Capability));
     MOCK_CONST_METHOD2(hasDisplayCapability,
                        bool(HalDisplayId,
                             aidl::android::hardware::graphics::composer3::DisplayCapability));
@@ -128,6 +129,10 @@
                 (const, override));
     MOCK_METHOD(std::optional<hal::HWDisplayId>, fromPhysicalDisplayId, (PhysicalDisplayId),
                 (const, override));
+    MOCK_METHOD2(getDisplayDecorationSupport,
+                 status_t(PhysicalDisplayId,
+                          std::optional<aidl::android::hardware::graphics::common::
+                                                DisplayDecorationSupport>* support));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 82dcc66..dda0822 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -751,6 +751,8 @@
     static constexpr bool kLayerGenericMetadata2Mandatory = true;
     static constexpr float kWhitePointNits = 200.f;
     static constexpr float kDisplayBrightnessNits = 400.f;
+    static constexpr float kLayerBrightness = kWhitePointNits / kDisplayBrightnessNits;
+    static constexpr float kFullLayerBrightness = 1.f;
 
     static const half4 kColor;
     static const Rect kDisplayFrame;
@@ -782,6 +784,7 @@
         outputLayerState.outputSpaceVisibleRegion = kOutputSpaceVisibleRegion;
         outputLayerState.dataspace = kDataspace;
         outputLayerState.whitePointNits = kWhitePointNits;
+        outputLayerState.dimmingRatio = kLayerBrightness;
 
         mLayerFEState.blendMode = kBlendMode;
         mLayerFEState.alpha = kAlpha;
@@ -846,11 +849,11 @@
                                    ui::Dataspace dataspace = kDataspace,
                                    const Region& visibleRegion = kOutputSpaceVisibleRegion,
                                    const Region& surfaceDamage = kSurfaceDamage,
-                                   float whitePointNits = kWhitePointNits,
+                                   float brightness = kLayerBrightness,
                                    const Region& blockingRegion = Region()) {
         EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(visibleRegion))).WillOnce(Return(kError));
         EXPECT_CALL(*mHwcLayer, setDataspace(dataspace)).WillOnce(Return(kError));
-        EXPECT_CALL(*mHwcLayer, setWhitePointNits(whitePointNits)).WillOnce(Return(kError));
+        EXPECT_CALL(*mHwcLayer, setBrightness(brightness)).WillOnce(Return(kError));
         EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform))
                 .WillOnce(Return(unsupported == SimulateUnsupported::ColorTransform
                                          ? hal::Error::UNSUPPORTED
@@ -1114,7 +1117,7 @@
     expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
                               kOverrideBlendMode, kSkipAlpha);
     expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
-                              kOverrideSurfaceDamage, kDisplayBrightnessNits);
+                              kOverrideSurfaceDamage, kFullLayerBrightness);
     expectSetHdrMetadataAndBufferCalls();
     expectSetCompositionTypeCall(Composition::DEVICE);
     EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1130,7 +1133,7 @@
     expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
                               kOverrideBlendMode, kSkipAlpha);
     expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
-                              kOverrideSurfaceDamage, kDisplayBrightnessNits);
+                              kOverrideSurfaceDamage, kFullLayerBrightness);
     expectSetHdrMetadataAndBufferCalls();
     expectSetCompositionTypeCall(Composition::DEVICE);
     EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1146,7 +1149,7 @@
     expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
                               kOverrideBlendMode, kOverrideAlpha);
     expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
-                              kOverrideSurfaceDamage, kDisplayBrightnessNits);
+                              kOverrideSurfaceDamage, kFullLayerBrightness);
     expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
     expectSetCompositionTypeCall(Composition::DEVICE);
     EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1162,7 +1165,7 @@
     expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
                               kOverrideBlendMode, kOverrideAlpha);
     expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
-                              kOverrideSurfaceDamage, kDisplayBrightnessNits);
+                              kOverrideSurfaceDamage, kFullLayerBrightness);
     expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
     expectSetCompositionTypeCall(Composition::DEVICE);
     EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1288,7 +1291,7 @@
 
     expectGeometryCommonCalls();
     expectPerFrameCommonCalls(SimulateUnsupported::None, kDataspace, kOutputSpaceVisibleRegion,
-                              kSurfaceDamage, kWhitePointNits, blockingRegion);
+                              kSurfaceDamage, kLayerBrightness, blockingRegion);
     expectSetHdrMetadataAndBufferCalls();
     EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
     expectSetCompositionTypeCall(Composition::DISPLAY_DECORATION);
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index b1057c3..8d67954 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -251,14 +251,14 @@
     }
 }
 
-std::vector<IComposer::Capability> AidlComposer::getCapabilities() {
+std::vector<Capability> AidlComposer::getCapabilities() {
     std::vector<Capability> capabilities;
     const auto status = mAidlComposer->getCapabilities(&capabilities);
     if (!status.isOk()) {
         ALOGE("getCapabilities failed %s", status.getDescription().c_str());
         return {};
     }
-    return translate<IComposer::Capability>(capabilities);
+    return capabilities;
 }
 
 std::string AidlComposer::dumpDebugInfo() {
@@ -1062,9 +1062,8 @@
     return Error::NONE;
 }
 
-Error AidlComposer::setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) {
-    mWriter.setLayerWhitePointNits(translate<int64_t>(display), translate<int64_t>(layer),
-                                   whitePointNits);
+Error AidlComposer::setLayerBrightness(Display display, Layer layer, float brightness) {
+    mWriter.setLayerBrightness(translate<int64_t>(display), translate<int64_t>(layer), brightness);
     return Error::NONE;
 }
 
@@ -1074,5 +1073,17 @@
                                    translate<AidlRect>(blocking));
     return Error::NONE;
 }
+
+Error AidlComposer::getDisplayDecorationSupport(Display display,
+                                                std::optional<DisplayDecorationSupport>* support) {
+    const auto status =
+            mAidlComposerClient->getDisplayDecorationSupport(translate<int64_t>(display), support);
+    if (!status.isOk()) {
+        ALOGE("getDisplayDecorationSupport failed %s", status.getDescription().c_str());
+        support->reset();
+        return static_cast<Error>(status.getServiceSpecificError());
+    }
+    return Error::NONE;
+}
 } // namespace Hwc2
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 374a436..724c6c9 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -45,6 +45,7 @@
 
 namespace android::Hwc2 {
 
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
 using aidl::android::hardware::graphics::composer3::ComposerClientReader;
 using aidl::android::hardware::graphics::composer3::ComposerClientWriter;
 
@@ -60,7 +61,8 @@
 
     bool isSupported(OptionalFeature) const;
 
-    std::vector<IComposer::Capability> getCapabilities() override;
+    std::vector<aidl::android::hardware::graphics::composer3::Capability> getCapabilities()
+            override;
     std::string dumpDebugInfo() override;
 
     void registerCallback(HWC2::ComposerCallback& callback) override;
@@ -210,12 +212,14 @@
                                   float* outClientTargetWhitePointNits) override;
 
     // AIDL Composer HAL
-    Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override;
+    Error setLayerBrightness(Display display, Layer layer, float brightness) override;
     Error setLayerBlockingRegion(Display display, Layer layer,
                                  const std::vector<IComposerClient::Rect>& blocking) override;
     Error setBootDisplayConfig(Display displayId, Config) override;
     Error clearBootDisplayConfig(Display displayId) override;
     Error getPreferredBootDisplayConfig(Display displayId, Config*) override;
+    Error getDisplayDecorationSupport(Display display,
+                                      std::optional<DisplayDecorationSupport>* support) override;
 
 private:
     // Many public functions above simply write a command into the command
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index fe55e6b..06aaa11 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -31,11 +31,15 @@
 #include <ui/GraphicBuffer.h>
 #include <utils/StrongPointer.h>
 
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+#include <aidl/android/hardware/graphics/composer3/Capability.h>
 #include <aidl/android/hardware/graphics/composer3/Color.h>
 #include <aidl/android/hardware/graphics/composer3/Composition.h>
 #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
 #include <aidl/android/hardware/graphics/composer3/IComposerCallback.h>
 
+#include <optional>
+
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
 
@@ -93,7 +97,8 @@
 
     virtual bool isSupported(OptionalFeature) const = 0;
 
-    virtual std::vector<IComposer::Capability> getCapabilities() = 0;
+    virtual std::vector<aidl::android::hardware::graphics::composer3::Capability>
+    getCapabilities() = 0;
     virtual std::string dumpDebugInfo() = 0;
 
     virtual void registerCallback(HWC2::ComposerCallback& callback) = 0;
@@ -259,12 +264,16 @@
             float* outWhitePointNits) = 0;
 
     // AIDL Composer
-    virtual Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) = 0;
+    virtual Error setLayerBrightness(Display display, Layer layer, float brightness) = 0;
     virtual Error setLayerBlockingRegion(Display display, Layer layer,
                                          const std::vector<IComposerClient::Rect>& blocking) = 0;
     virtual Error setBootDisplayConfig(Display displayId, Config) = 0;
     virtual Error clearBootDisplayConfig(Display displayId) = 0;
     virtual Error getPreferredBootDisplayConfig(Display displayId, Config*) = 0;
+    virtual Error getDisplayDecorationSupport(
+            Display display,
+            std::optional<::aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+                    support) = 0;
 };
 
 } // namespace Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 05e3aef..a1b663c 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -39,6 +39,7 @@
 
 using aidl::android::hardware::graphics::composer3::Color;
 using aidl::android::hardware::graphics::composer3::Composition;
+using AidlCapability = aidl::android::hardware::graphics::composer3::Capability;
 using aidl::android::hardware::graphics::composer3::DisplayCapability;
 
 namespace android {
@@ -73,7 +74,7 @@
 namespace impl {
 
 Display::Display(android::Hwc2::Composer& composer,
-                 const std::unordered_set<Capability>& capabilities, HWDisplayId id,
+                 const std::unordered_set<AidlCapability>& capabilities, HWDisplayId id,
                  DisplayType type)
       : mComposer(composer), mCapabilities(capabilities), mId(id), mType(type) {
     ALOGV("Created display %" PRIu64, id);
@@ -470,7 +471,7 @@
             } else if (error == Error::UNSUPPORTED) {
                 std::scoped_lock lock(mDisplayCapabilitiesMutex);
                 mDisplayCapabilities.emplace();
-                if (mCapabilities.count(Capability::SKIP_CLIENT_COLOR_TRANSFORM)) {
+                if (mCapabilities.count(AidlCapability::SKIP_CLIENT_COLOR_TRANSFORM)) {
                     mDisplayCapabilities->emplace(DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM);
                 }
                 bool dozeSupport = false;
@@ -580,6 +581,13 @@
     return static_cast<Error>(error);
 }
 
+Error Display::getDisplayDecorationSupport(
+        std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+                support) {
+    const auto error = mComposer.getDisplayDecorationSupport(mId, support);
+    return static_cast<Error>(error);
+}
+
 // For use by Device
 
 void Display::setConnected(bool connected) {
@@ -618,8 +626,9 @@
 
 namespace impl {
 
-Layer::Layer(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
-             HWC2::Display& display, HWLayerId layerId)
+Layer::Layer(android::Hwc2::Composer& composer,
+             const std::unordered_set<AidlCapability>& capabilities, HWC2::Display& display,
+             HWLayerId layerId)
       : mComposer(composer),
         mCapabilities(capabilities),
         mDisplay(&display),
@@ -849,7 +858,7 @@
         return Error::BAD_DISPLAY;
     }
 
-    if (mCapabilities.count(Capability::SIDEBAND_STREAM) == 0) {
+    if (mCapabilities.count(AidlCapability::SIDEBAND_STREAM) == 0) {
         ALOGE("Attempted to call setSidebandStream without checking that the "
                 "device supports sideband streams");
         return Error::UNSUPPORTED;
@@ -938,12 +947,12 @@
 }
 
 // AIDL HAL
-Error Layer::setWhitePointNits(float whitePointNits) {
+Error Layer::setBrightness(float brightness) {
     if (CC_UNLIKELY(!mDisplay)) {
         return Error::BAD_DISPLAY;
     }
 
-    auto intError = mComposer.setLayerWhitePointNits(mDisplay->getId(), mId, whitePointNits);
+    auto intError = mComposer.setLayerBrightness(mDisplay->getId(), mId, brightness);
     return static_cast<Error>(intError);
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 0a605a8..334d6ec 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -37,6 +37,8 @@
 #include "ComposerHal.h"
 #include "Hal.h"
 
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+#include <aidl/android/hardware/graphics/composer3/Capability.h>
 #include <aidl/android/hardware/graphics/composer3/Color.h>
 #include <aidl/android/hardware/graphics/composer3/Composition.h>
 #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
@@ -161,6 +163,9 @@
     [[clang::warn_unused_result]] virtual hal::Error setContentType(hal::ContentType) = 0;
     [[clang::warn_unused_result]] virtual hal::Error getClientTargetProperty(
             hal::ClientTargetProperty* outClientTargetProperty, float* outWhitePointNits) = 0;
+    [[clang::warn_unused_result]] virtual hal::Error getDisplayDecorationSupport(
+            std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+                    support) = 0;
 };
 
 namespace impl {
@@ -169,8 +174,9 @@
 
 class Display : public HWC2::Display {
 public:
-    Display(android::Hwc2::Composer&, const std::unordered_set<hal::Capability>&, hal::HWDisplayId,
-            hal::DisplayType);
+    Display(android::Hwc2::Composer&,
+            const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>&,
+            hal::HWDisplayId, hal::DisplayType);
     ~Display() override;
 
     // Required by HWC2
@@ -233,6 +239,9 @@
     hal::Error setContentType(hal::ContentType) override;
     hal::Error getClientTargetProperty(hal::ClientTargetProperty* outClientTargetProperty,
                                        float* outWhitePointNits) override;
+    hal::Error getDisplayDecorationSupport(
+            std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+                    support) override;
 
     // Other Display methods
     hal::HWDisplayId getId() const override { return mId; }
@@ -257,7 +266,8 @@
     // this HWC2::Display, so these references are guaranteed to be valid for
     // the lifetime of this object.
     android::Hwc2::Composer& mComposer;
-    const std::unordered_set<hal::Capability>& mCapabilities;
+    const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>&
+            mCapabilities;
 
     const hal::HWDisplayId mId;
     hal::DisplayType mType;
@@ -317,7 +327,7 @@
             const std::string& name, bool mandatory, const std::vector<uint8_t>& value) = 0;
 
     // AIDL HAL
-    [[clang::warn_unused_result]] virtual hal::Error setWhitePointNits(float whitePointNits) = 0;
+    [[clang::warn_unused_result]] virtual hal::Error setBrightness(float brightness) = 0;
     [[clang::warn_unused_result]] virtual hal::Error setBlockingRegion(
             const android::Region& region) = 0;
 };
@@ -329,8 +339,9 @@
 class Layer : public HWC2::Layer {
 public:
     Layer(android::Hwc2::Composer& composer,
-          const std::unordered_set<hal::Capability>& capabilities, HWC2::Display& display,
-          hal::HWLayerId layerId);
+          const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>&
+                  capabilities,
+          HWC2::Display& display, hal::HWLayerId layerId);
     ~Layer() override;
 
     void onOwningDisplayDestroyed();
@@ -365,7 +376,7 @@
                                        const std::vector<uint8_t>& value) override;
 
     // AIDL HAL
-    hal::Error setWhitePointNits(float whitePointNits) override;
+    hal::Error setBrightness(float brightness) override;
     hal::Error setBlockingRegion(const android::Region& region) override;
 
 private:
@@ -373,7 +384,8 @@
     // this HWC2::Layer, so these references are guaranteed to be valid for
     // the lifetime of this object.
     android::Hwc2::Composer& mComposer;
-    const std::unordered_set<hal::Capability>& mCapabilities;
+    const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>&
+            mCapabilities;
 
     HWC2::Display* mDisplay;
     hal::HWLayerId mId;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 2696bd8..6a3162e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -71,6 +71,8 @@
 #define RETURN_IF_HWC_ERROR(error, displayId, ...) \
     RETURN_IF_HWC_ERROR_FOR(__FUNCTION__, error, displayId, __VA_ARGS__)
 
+using aidl::android::hardware::graphics::composer3::Capability;
+using aidl::android::hardware::graphics::composer3::DisplayCapability;
 namespace hal = android::hardware::graphics::composer::hal;
 
 namespace android {
@@ -118,13 +120,11 @@
     return true;
 }
 
-bool HWComposer::hasCapability(hal::Capability capability) const {
+bool HWComposer::hasCapability(Capability capability) const {
     return mCapabilities.count(capability) > 0;
 }
 
-bool HWComposer::hasDisplayCapability(
-        HalDisplayId displayId,
-        aidl::android::hardware::graphics::composer3::DisplayCapability capability) const {
+bool HWComposer::hasDisplayCapability(HalDisplayId displayId, DisplayCapability capability) const {
     RETURN_IF_INVALID_DISPLAY(displayId, false);
     return mDisplayData.at(displayId).hwcDisplay->hasCapability(capability);
 }
@@ -785,6 +785,22 @@
     return displayModeId;
 }
 
+status_t HWComposer::getDisplayDecorationSupport(
+        PhysicalDisplayId displayId,
+        std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+                support) {
+    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+    const auto error = mDisplayData[displayId].hwcDisplay->getDisplayDecorationSupport(support);
+    if (error == hal::Error::UNSUPPORTED) {
+        RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+    }
+    if (error == hal::Error::BAD_PARAMETER) {
+        RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
+    }
+    RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+    return NO_ERROR;
+}
+
 status_t HWComposer::setAutoLowLatencyMode(PhysicalDisplayId displayId, bool on) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
     const auto error = mDisplayData[displayId].hwcDisplay->setAutoLowLatencyMode(on);
@@ -952,7 +968,7 @@
     static_assert(sizeof(hal::Capability) == sizeof(int32_t), "Capability size has changed");
     auto capabilities = mComposer->getCapabilities();
     for (auto capability : capabilities) {
-        mCapabilities.emplace(static_cast<hal::Capability>(capability));
+        mCapabilities.emplace(capability);
     }
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 29335d5..916c4b7 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -43,6 +43,8 @@
 #include "HWC2.h"
 #include "Hal.h"
 
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+#include <aidl/android/hardware/graphics/composer3/Capability.h>
 #include <aidl/android/hardware/graphics/composer3/Composition.h>
 #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
 
@@ -110,7 +112,7 @@
     virtual bool getDisplayIdentificationData(hal::HWDisplayId, uint8_t* outPort,
                                               DisplayIdentificationData* outData) const = 0;
 
-    virtual bool hasCapability(hal::Capability) const = 0;
+    virtual bool hasCapability(aidl::android::hardware::graphics::composer3::Capability) const = 0;
     virtual bool hasDisplayCapability(
             HalDisplayId,
             aidl::android::hardware::graphics::composer3::DisplayCapability) const = 0;
@@ -261,6 +263,10 @@
     virtual status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) = 0;
     virtual status_t clearBootDisplayMode(PhysicalDisplayId) = 0;
     virtual std::optional<hal::HWConfigId> getPreferredBootDisplayMode(PhysicalDisplayId) = 0;
+    virtual status_t getDisplayDecorationSupport(
+            PhysicalDisplayId,
+            std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+                    support) = 0;
 };
 
 namespace impl {
@@ -277,7 +283,7 @@
     bool getDisplayIdentificationData(hal::HWDisplayId, uint8_t* outPort,
                                       DisplayIdentificationData* outData) const override;
 
-    bool hasCapability(hal::Capability) const override;
+    bool hasCapability(aidl::android::hardware::graphics::composer3::Capability) const override;
     bool hasDisplayCapability(
             HalDisplayId,
             aidl::android::hardware::graphics::composer3::DisplayCapability) const override;
@@ -392,6 +398,10 @@
     status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) override;
     status_t clearBootDisplayMode(PhysicalDisplayId) override;
     std::optional<hal::HWConfigId> getPreferredBootDisplayMode(PhysicalDisplayId) override;
+    status_t getDisplayDecorationSupport(
+            PhysicalDisplayId,
+            std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+                    support) override;
 
     // for debugging ----------------------------------------------------------
     void dump(std::string& out) const override;
@@ -447,7 +457,7 @@
     std::unordered_map<HalDisplayId, DisplayData> mDisplayData;
 
     std::unique_ptr<android::Hwc2::Composer> mComposer;
-    std::unordered_set<hal::Capability> mCapabilities;
+    std::unordered_set<aidl::android::hardware::graphics::composer3::Capability> mCapabilities;
     std::unordered_map<std::string, bool> mSupportedLayerGenericMetadata;
     bool mRegisteredCallback = false;
 
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index 40c9761..4737034 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -135,8 +135,8 @@
             return "AutoLowLatencyMode";
         case aidl::android::hardware::graphics::composer3::DisplayCapability::SUSPEND:
             return "Suspend";
-        case aidl::android::hardware::graphics::composer3::DisplayCapability::DISPLAY_DECORATION:
-            return "DisplayDecoration";
+        case aidl::android::hardware::graphics::composer3::DisplayCapability::DISPLAY_IDLE_TIMER:
+            return "DisplayIdleTimer";
         default:
             return "Unknown";
     }
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 746ac64..95d7b58 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -36,6 +36,7 @@
 #include <algorithm>
 #include <cinttypes>
 
+using aidl::android::hardware::graphics::composer3::Capability;
 using aidl::android::hardware::graphics::composer3::DisplayCapability;
 
 namespace android {
@@ -168,6 +169,20 @@
     return unwrapRet(ret, kDefaultError);
 }
 
+template <typename To, typename From>
+To translate(From x) {
+    return static_cast<To>(x);
+}
+
+template <typename To, typename From>
+std::vector<To> translate(const hidl_vec<From>& in) {
+    std::vector<To> out;
+    out.reserve(in.size());
+    std::transform(in.begin(), in.end(), std::back_inserter(out),
+                   [](From x) { return translate<To>(x); });
+    return out;
+}
+
 } // anonymous namespace
 
 HidlComposer::HidlComposer(const std::string& serviceName) : mWriter(kWriterInitialSize) {
@@ -225,10 +240,11 @@
     }
 }
 
-std::vector<IComposer::Capability> HidlComposer::getCapabilities() {
-    std::vector<IComposer::Capability> capabilities;
-    mComposer->getCapabilities(
-            [&](const auto& tmpCapabilities) { capabilities = tmpCapabilities; });
+std::vector<Capability> HidlComposer::getCapabilities() {
+    std::vector<Capability> capabilities;
+    mComposer->getCapabilities([&](const auto& tmpCapabilities) {
+        capabilities = translate<Capability>(tmpCapabilities);
+    });
     return capabilities;
 }
 
@@ -1101,15 +1117,6 @@
 
 // Composer HAL 2.4
 
-namespace {
-template <typename T>
-void copyCapabilities(const T& tmpCaps, std::vector<DisplayCapability>* outCapabilities) {
-    outCapabilities->resize(tmpCaps.size());
-    std::transform(tmpCaps.begin(), tmpCaps.end(), outCapabilities->begin(),
-                   [](auto cap) { return static_cast<DisplayCapability>(cap); });
-}
-} // anonymous namespace
-
 Error HidlComposer::getDisplayCapabilities(Display display,
                                            std::vector<DisplayCapability>* outCapabilities) {
     if (!mClient_2_3) {
@@ -1124,7 +1131,8 @@
                                                     if (error != V2_4::Error::NONE) {
                                                         return;
                                                     }
-                                                    copyCapabilities(tmpCaps, outCapabilities);
+                                                    *outCapabilities =
+                                                            translate<DisplayCapability>(tmpCaps);
                                                 });
     } else {
         mClient_2_3
@@ -1134,7 +1142,7 @@
                         return;
                     }
 
-                    copyCapabilities(tmpCaps, outCapabilities);
+                    *outCapabilities = translate<DisplayCapability>(tmpCaps);
                 });
     }
 
@@ -1295,7 +1303,7 @@
     return Error::NONE;
 }
 
-Error HidlComposer::setLayerWhitePointNits(Display, Layer, float) {
+Error HidlComposer::setLayerBrightness(Display, Layer, float) {
     return Error::NONE;
 }
 
@@ -1304,6 +1312,14 @@
     return Error::NONE;
 }
 
+Error HidlComposer::getDisplayDecorationSupport(
+        Display,
+        std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+                support) {
+    support->reset();
+    return Error::UNSUPPORTED;
+}
+
 void HidlComposer::registerCallback(ComposerCallback& callback) {
     const bool vsyncSwitchingSupported =
             isSupported(Hwc2::Composer::OptionalFeature::RefreshRateSwitching);
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 1ffca6e..71ae8b4 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -169,7 +169,8 @@
 
     bool isSupported(OptionalFeature) const;
 
-    std::vector<IComposer::Capability> getCapabilities() override;
+    std::vector<aidl::android::hardware::graphics::composer3::Capability> getCapabilities()
+            override;
     std::string dumpDebugInfo() override;
 
     void registerCallback(HWC2::ComposerCallback& callback) override;
@@ -320,12 +321,16 @@
                                   float* outWhitePointNits) override;
 
     // AIDL Composer HAL
-    Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override;
+    Error setLayerBrightness(Display display, Layer layer, float brightness) override;
     Error setLayerBlockingRegion(Display display, Layer layer,
                                  const std::vector<IComposerClient::Rect>& blocking) override;
     Error setBootDisplayConfig(Display displayId, Config) override;
     Error clearBootDisplayConfig(Display displayId) override;
     Error getPreferredBootDisplayConfig(Display displayId, Config*) override;
+    Error getDisplayDecorationSupport(
+            Display display,
+            std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+                    support) override;
 
 private:
     class CommandWriter : public CommandWriterBase {
diff --git a/services/surfaceflinger/FlagManager.cpp b/services/surfaceflinger/FlagManager.cpp
index 7602e6d..e09a192 100644
--- a/services/surfaceflinger/FlagManager.cpp
+++ b/services/surfaceflinger/FlagManager.cpp
@@ -19,8 +19,10 @@
 #include <SurfaceFlingerProperties.sysprop.h>
 #include <android-base/parsebool.h>
 #include <android-base/parseint.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <log/log.h>
+#include <renderengine/RenderEngine.h>
 #include <server_configurable_flags/get_flags.h>
 #include <cinttypes>
 
@@ -34,6 +36,7 @@
     base::StringAppendF(&result, "FlagManager values: \n");
     base::StringAppendF(&result, "demo_flag: %" PRId64 "\n", demo_flag());
     base::StringAppendF(&result, "use_adpf_cpu_hint: %s\n", use_adpf_cpu_hint() ? "true" : "false");
+    base::StringAppendF(&result, "use_skia_tracing: %s\n", use_skia_tracing() ? "true" : "false");
 }
 
 namespace {
@@ -97,4 +100,11 @@
     return getValue("AdpfFeature__adpf_cpu_hint", sysPropVal, false);
 }
 
+bool FlagManager::use_skia_tracing() const {
+    ALOGD("use_skia_tracing ?");
+    std::optional<bool> sysPropVal =
+            doParse<bool>(base::GetProperty(PROPERTY_SKIA_ATRACE_ENABLED, "").c_str());
+    return getValue("SkiaTracingFeature__use_skia_tracing", sysPropVal, false);
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/FlagManager.h b/services/surfaceflinger/FlagManager.h
index 24d83a2..e834142 100644
--- a/services/surfaceflinger/FlagManager.h
+++ b/services/surfaceflinger/FlagManager.h
@@ -33,6 +33,8 @@
 
     bool use_adpf_cpu_hint() const;
 
+    bool use_skia_tracing() const;
+
 private:
     friend class FlagManagerTest;
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a039250..973029c 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1993,29 +1993,31 @@
     setTransactionFlags(eTransactionNeeded);
 }
 
-LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags,
-                                const DisplayDevice* display) {
+LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags) {
     LayerProto* layerProto = layersProto.add_layers();
-    writeToProtoDrawingState(layerProto, traceFlags, display);
+    writeToProtoDrawingState(layerProto);
     writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
 
     if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
         // Only populate for the primary display.
+        UnnecessaryLock assumeLocked(mFlinger->mStateLock); // called from the main thread.
+        const auto display = mFlinger->getDefaultDisplayDeviceLocked();
         if (display) {
             const auto compositionType = getCompositionType(*display);
             layerProto->set_hwc_composition_type(static_cast<HwcCompositionType>(compositionType));
+            LayerProtoHelper::writeToProto(getVisibleRegion(display.get()),
+                                           [&]() { return layerProto->mutable_visible_region(); });
         }
     }
 
     for (const sp<Layer>& layer : mDrawingChildren) {
-        layer->writeToProto(layersProto, traceFlags, display);
+        layer->writeToProto(layersProto, traceFlags);
     }
 
     return layerProto;
 }
 
-void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags,
-                                     const DisplayDevice* display) {
+void Layer::writeToProtoDrawingState(LayerProto* layerInfo) {
     const ui::Transform transform = getTransform();
     auto buffer = getExternalTexture();
     if (buffer != nullptr) {
@@ -2039,10 +2041,6 @@
     LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
                                            [&]() { return layerInfo->mutable_position(); });
     LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
-    if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
-        LayerProtoHelper::writeToProto(getVisibleRegion(display),
-                                       [&]() { return layerInfo->mutable_visible_region(); });
-    }
     LayerProtoHelper::writeToProto(surfaceDamageRegion,
                                    [&]() { return layerInfo->mutable_damage_region(); });
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ddcd641..21dd5f4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -686,12 +686,12 @@
 
     bool isRemovedFromCurrentState() const;
 
-    LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags, const DisplayDevice*);
+    LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags);
 
     // Write states that are modified by the main thread. This includes drawing
     // state as well as buffer data. This should be called in the main or tracing
     // thread.
-    void writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, const DisplayDevice*);
+    void writeToProtoDrawingState(LayerProto* layerInfo);
     // Write drawing or current state. If writing current state, the caller should hold the
     // external mStateLock. If writing drawing state, this function should be called on the
     // main or tracing thread.
@@ -897,6 +897,8 @@
     virtual std::string getPendingBufferCounterName() { return ""; }
     virtual bool updateGeometry() { return false; }
 
+    virtual bool simpleBufferUpdate(const layer_state_t&) const { return false; }
+
 protected:
     friend class impl::SurfaceInterceptor;
 
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 015caa6..3bd0643 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -156,14 +156,14 @@
 
 void LayerProtoHelper::writeToProto(const renderengine::ExternalTexture& buffer,
                                     std::function<ActiveBufferProto*()> getActiveBufferProto) {
-    if (buffer.getBuffer()->getWidth() != 0 || buffer.getBuffer()->getHeight() != 0 ||
-        buffer.getBuffer()->getUsage() != 0 || buffer.getBuffer()->getPixelFormat() != 0) {
+    if (buffer.getWidth() != 0 || buffer.getHeight() != 0 || buffer.getUsage() != 0 ||
+        buffer.getPixelFormat() != 0) {
         // Use a lambda do avoid writing the object header when the object is empty
         ActiveBufferProto* activeBufferProto = getActiveBufferProto();
-        activeBufferProto->set_width(buffer.getBuffer()->getWidth());
-        activeBufferProto->set_height(buffer.getBuffer()->getHeight());
-        activeBufferProto->set_format(buffer.getBuffer()->getPixelFormat());
-        activeBufferProto->set_usage(buffer.getBuffer()->getUsage());
+        activeBufferProto->set_width(buffer.getWidth());
+        activeBufferProto->set_height(buffer.getHeight());
+        activeBufferProto->set_stride(buffer.getUsage());
+        activeBufferProto->set_format(buffer.getPixelFormat());
     }
 }
 
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index ff30348..e29e6ab 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -30,6 +30,7 @@
 #include <compositionengine/impl/OutputCompositionState.h>
 #include <cutils/properties.h>
 #include <ftl/future.h>
+#include <gui/SpHash.h>
 #include <gui/SyncScreenCaptureListener.h>
 #include <renderengine/impl/ExternalTexture.h>
 #include <ui/DisplayStatInfo.h>
@@ -46,10 +47,7 @@
 namespace android {
 using namespace std::chrono_literals;
 
-template <typename T>
-struct SpHash {
-    size_t operator()(const sp<T>& p) const { return std::hash<T*>()(p.get()); }
-};
+using gui::SpHash;
 
 constexpr auto lumaSamplingStepTag = "LumaSamplingStep";
 enum class samplingStep {
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 50b38c9..747032b 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -23,6 +23,7 @@
 #include <mutex>
 
 #include "EventThread.h"
+#include "VSyncTracker.h"
 #include "VsyncController.h"
 
 namespace android::scheduler {
@@ -114,7 +115,7 @@
     std::chrono::nanoseconds mLastCallTime GUARDED_BY(mMutex) = 0ns;
 };
 
-DispSyncSource::DispSyncSource(scheduler::VSyncDispatch& vSyncDispatch,
+DispSyncSource::DispSyncSource(VSyncDispatch& vSyncDispatch, VSyncTracker& vSyncTracker,
                                std::chrono::nanoseconds workDuration,
                                std::chrono::nanoseconds readyDuration, bool traceVsync,
                                const char* name)
@@ -122,6 +123,7 @@
         mValue(base::StringPrintf("VSYNC-%s", name), 0),
         mTraceVsync(traceVsync),
         mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
+        mVSyncTracker(vSyncTracker),
         mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
         mReadyDuration(readyDuration) {
     mCallbackRepeater =
@@ -180,10 +182,18 @@
     }
 
     if (callback != nullptr) {
-        callback->onVSyncEvent(targetWakeupTime, vsyncTime, readyTime);
+        callback->onVSyncEvent(targetWakeupTime, {vsyncTime, readyTime});
     }
 }
 
+VSyncSource::VSyncData DispSyncSource::getLatestVSyncData() const {
+    std::lock_guard lock(mVsyncMutex);
+    nsecs_t expectedPresentTime = mVSyncTracker.nextAnticipatedVSyncTimeFrom(
+            systemTime() + mWorkDuration.get().count() + mReadyDuration.count());
+    nsecs_t deadline = expectedPresentTime - mWorkDuration.get().count() - mReadyDuration.count();
+    return {expectedPresentTime, deadline};
+}
+
 void DispSyncSource::dump(std::string& result) const {
     std::lock_guard lock(mVsyncMutex);
     StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled");
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 2fce235..edcd3ac 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -24,11 +24,13 @@
 
 namespace android::scheduler {
 class CallbackRepeater;
+class VSyncTracker;
 
 class DispSyncSource final : public VSyncSource {
 public:
-    DispSyncSource(VSyncDispatch& vSyncDispatch, std::chrono::nanoseconds workDuration,
-                   std::chrono::nanoseconds readyDuration, bool traceVsync, const char* name);
+    DispSyncSource(VSyncDispatch& vSyncDispatch, VSyncTracker& vSyncTracker,
+                   std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
+                   bool traceVsync, const char* name);
 
     ~DispSyncSource() override;
 
@@ -38,6 +40,7 @@
     void setCallback(VSyncSource::Callback* callback) override;
     void setDuration(std::chrono::nanoseconds workDuration,
                      std::chrono::nanoseconds readyDuration) override;
+    VSyncData getLatestVSyncData() const override;
 
     void dump(std::string&) const override;
 
@@ -50,6 +53,8 @@
     const bool mTraceVsync;
     const std::string mVsyncOnLabel;
 
+    const VSyncTracker& mVSyncTracker;
+
     std::unique_ptr<CallbackRepeater> mCallbackRepeater;
 
     std::mutex mCallbackMutex;
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 627c49a..2d0da46 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -108,13 +108,12 @@
 
 DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp,
                                       uint32_t count, nsecs_t expectedVSyncTimestamp,
-                                      nsecs_t deadlineTimestamp, int64_t vsyncId) {
+                                      nsecs_t deadlineTimestamp) {
     DisplayEventReceiver::Event event;
     event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
     event.vsync.count = count;
     event.vsync.expectedVSyncTimestamp = expectedVSyncTimestamp;
     event.vsync.deadlineTimestamp = deadlineTimestamp;
-    event.vsync.vsyncId = vsyncId;
     return event;
 }
 
@@ -182,11 +181,17 @@
 }
 
 binder::Status EventThreadConnection::requestNextVsync() {
-    ATRACE_NAME("requestNextVsync");
+    ATRACE_CALL();
     mEventThread->requestNextVsync(this);
     return binder::Status::ok();
 }
 
+binder::Status EventThreadConnection::getLatestVsyncEventData(VsyncEventData* outVsyncEventData) {
+    ATRACE_CALL();
+    *outVsyncEventData = mEventThread->getLatestVsyncEventData(this);
+    return binder::Status::ok();
+}
+
 status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
     constexpr auto toStatus = [](ssize_t size) {
         return size < 0 ? status_t(size) : status_t(NO_ERROR);
@@ -331,6 +336,15 @@
     }
 }
 
+VsyncEventData EventThread::getLatestVsyncEventData(
+        const sp<EventThreadConnection>& connection) const {
+    nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid);
+    VsyncEventData vsyncEventData;
+    vsyncEventData.frameInterval = frameInterval;
+    generateFrameTimeline(vsyncEventData, frameInterval, systemTime(SYSTEM_TIME_MONOTONIC));
+    return vsyncEventData;
+}
+
 void EventThread::onScreenReleased() {
     std::lock_guard<std::mutex> lock(mMutex);
     if (!mVSyncState || mVSyncState->synthetic) {
@@ -351,14 +365,13 @@
     mCondition.notify_all();
 }
 
-void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp,
-                               nsecs_t deadlineTimestamp) {
+void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) {
     std::lock_guard<std::mutex> lock(mMutex);
 
     LOG_FATAL_IF(!mVSyncState);
-    const int64_t vsyncId = generateToken(timestamp, deadlineTimestamp, expectedVSyncTimestamp);
     mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
-                                       expectedVSyncTimestamp, deadlineTimestamp, vsyncId));
+                                       vsyncData.expectedVSyncTimestamp,
+                                       vsyncData.deadlineTimestamp));
     mCondition.notify_all();
 }
 
@@ -493,16 +506,9 @@
                 const auto now = systemTime(SYSTEM_TIME_MONOTONIC);
                 const auto deadlineTimestamp = now + timeout.count();
                 const auto expectedVSyncTime = deadlineTimestamp + timeout.count();
-                const int64_t vsyncId = [&] {
-                    if (mTokenManager != nullptr) {
-                        return mTokenManager->generateTokenForPredictions(
-                                {now, deadlineTimestamp, expectedVSyncTime});
-                    }
-                    return FrameTimelineInfo::INVALID_VSYNC_ID;
-                }();
                 mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now,
                                                    ++mVSyncState->count, expectedVSyncTime,
-                                                   deadlineTimestamp, vsyncId));
+                                                   deadlineTimestamp));
             }
         }
     }
@@ -570,32 +576,64 @@
     return FrameTimelineInfo::INVALID_VSYNC_ID;
 }
 
-void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const {
+void EventThread::generateFrameTimeline(
+        nsecs_t frameInterval, nsecs_t timestamp, nsecs_t preferredExpectedVSyncTimestamp,
+        nsecs_t preferredDeadlineTimestamp,
+        std::function<void(int64_t index)> setPreferredFrameTimelineIndex,
+        std::function<void(int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp,
+                           nsecs_t deadlineTimestamp)>
+                setFrameTimeline) const {
     // Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included.
-    for (int multiplier = -DisplayEventReceiver::kFrameTimelinesLength + 1, currentIndex = 0;
-         currentIndex < DisplayEventReceiver::kFrameTimelinesLength; multiplier++) {
-        nsecs_t deadline = event.vsync.deadlineTimestamp + multiplier * event.vsync.frameInterval;
+    for (int64_t multiplier = -VsyncEventData::kFrameTimelinesLength + 1, currentIndex = 0;
+         currentIndex < VsyncEventData::kFrameTimelinesLength; multiplier++) {
+        nsecs_t deadline = preferredDeadlineTimestamp + multiplier * frameInterval;
         // Valid possible frame timelines must have future values.
-        if (deadline > event.header.timestamp) {
+        if (deadline > timestamp) {
             if (multiplier == 0) {
-                event.vsync.preferredFrameTimelineIndex = currentIndex;
-                event.vsync.frameTimelines[currentIndex] =
-                        {.vsyncId = event.vsync.vsyncId,
-                         .deadlineTimestamp = event.vsync.deadlineTimestamp,
-                         .expectedVSyncTimestamp = event.vsync.expectedVSyncTimestamp};
-            } else {
-                nsecs_t expectedVSync =
-                        event.vsync.expectedVSyncTimestamp + multiplier * event.vsync.frameInterval;
-                event.vsync.frameTimelines[currentIndex] =
-                        {.vsyncId = generateToken(event.header.timestamp, deadline, expectedVSync),
-                         .deadlineTimestamp = deadline,
-                         .expectedVSyncTimestamp = expectedVSync};
+                setPreferredFrameTimelineIndex(currentIndex);
             }
+            nsecs_t expectedVSyncTimestamp =
+                    preferredExpectedVSyncTimestamp + multiplier * frameInterval;
+            setFrameTimeline(currentIndex,
+                             generateToken(timestamp, deadline, expectedVSyncTimestamp),
+                             expectedVSyncTimestamp, deadline);
             currentIndex++;
         }
     }
 }
 
+void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const {
+    generateFrameTimeline(
+            event.vsync.frameInterval, event.header.timestamp, event.vsync.expectedVSyncTimestamp,
+            event.vsync.deadlineTimestamp,
+            [&](int index) { event.vsync.preferredFrameTimelineIndex = index; },
+            [&](int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp,
+                nsecs_t deadlineTimestamp) {
+                event.vsync.frameTimelines[index] = {.vsyncId = vsyncId,
+                                                     .deadlineTimestamp = deadlineTimestamp,
+                                                     .expectedVSyncTimestamp =
+                                                             expectedVSyncTimestamp};
+            });
+}
+
+void EventThread::generateFrameTimeline(VsyncEventData& out, const nsecs_t frameInterval,
+                                        const nsecs_t timestamp) const {
+    VSyncSource::VSyncData vsyncData;
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        vsyncData = mVSyncSource->getLatestVSyncData();
+    }
+    generateFrameTimeline(
+            frameInterval, timestamp, vsyncData.expectedVSyncTimestamp, vsyncData.deadlineTimestamp,
+            [&](int index) { out.preferredFrameTimelineIndex = index; },
+            [&](int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp,
+                nsecs_t deadlineTimestamp) {
+                out.frameTimelines[index] =
+                        VsyncEventData::FrameTimeline(vsyncId, deadlineTimestamp,
+                                                      expectedVSyncTimestamp);
+            });
+}
+
 void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
                                 const DisplayEventConsumers& consumers) {
     for (const auto& consumer : consumers) {
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index fa9af09..a858169 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -45,6 +45,8 @@
 class TokenManager;
 } // namespace frametimeline
 
+using gui::VsyncEventData;
+
 // ---------------------------------------------------------------------------
 
 using ResyncCallback = std::function<void()>;
@@ -62,11 +64,16 @@
 
 class VSyncSource {
 public:
+    class VSyncData {
+    public:
+        nsecs_t expectedVSyncTimestamp;
+        nsecs_t deadlineTimestamp;
+    };
+
     class Callback {
     public:
         virtual ~Callback() {}
-        virtual void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
-                                  nsecs_t deadlineTimestamp) = 0;
+        virtual void onVSyncEvent(nsecs_t when, VSyncData vsyncData) = 0;
     };
 
     virtual ~VSyncSource() {}
@@ -76,6 +83,7 @@
     virtual void setCallback(Callback* callback) = 0;
     virtual void setDuration(std::chrono::nanoseconds workDuration,
                              std::chrono::nanoseconds readyDuration) = 0;
+    virtual VSyncData getLatestVSyncData() const = 0;
 
     virtual void dump(std::string& result) const = 0;
 };
@@ -91,6 +99,7 @@
     binder::Status stealReceiveChannel(gui::BitTube* outChannel) override;
     binder::Status setVsyncRate(int rate) override;
     binder::Status requestNextVsync() override; // asynchronous
+    binder::Status getLatestVsyncEventData(VsyncEventData* outVsyncEventData) override;
 
     // Called in response to requestNextVsync.
     const ResyncCallback resyncCallback;
@@ -140,6 +149,8 @@
     virtual void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) = 0;
     // Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
     virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
+    virtual VsyncEventData getLatestVsyncEventData(
+            const sp<EventThreadConnection>& connection) const = 0;
 
     // Retrieves the number of event connections tracked by this EventThread.
     virtual size_t getEventThreadConnectionCount() = 0;
@@ -164,6 +175,8 @@
     status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
     void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
     void requestNextVsync(const sp<EventThreadConnection>& connection) override;
+    VsyncEventData getLatestVsyncEventData(
+            const sp<EventThreadConnection>& connection) const override;
 
     // called before the screen is turned off from main thread
     void onScreenReleased() override;
@@ -201,12 +214,20 @@
             REQUIRES(mMutex);
 
     // Implements VSyncSource::Callback
-    void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp,
-                      nsecs_t deadlineTimestamp) override;
+    void onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) override;
 
     int64_t generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp,
                           nsecs_t expectedVSyncTimestamp) const;
     void generateFrameTimeline(DisplayEventReceiver::Event& event) const;
+    void generateFrameTimeline(VsyncEventData& out, const nsecs_t frameInterval,
+                               const nsecs_t timestamp) const;
+    void generateFrameTimeline(
+            nsecs_t frameInterval, nsecs_t timestamp, nsecs_t preferredExpectedVSyncTimestamp,
+            nsecs_t preferredDeadlineTimestamp,
+            std::function<void(int64_t index)> setPreferredFrameTimelineIndex,
+            std::function<void(int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp,
+                               nsecs_t deadlineTimestamp)>
+                    setFrameTimeline) const;
 
     const std::unique_ptr<VSyncSource> mVSyncSource GUARDED_BY(mMutex);
     frametimeline::TokenManager* const mTokenManager;
diff --git a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
index d9d64ae..c233455 100644
--- a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
+++ b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
@@ -51,7 +51,8 @@
     return std::nullopt;
 }
 
-std::vector<FrameRateOverride> FrameRateOverrideMappings::getAllFrameRateOverrides() {
+std::vector<FrameRateOverride> FrameRateOverrideMappings::getAllFrameRateOverrides(
+        bool supportsFrameRateOverrideByContent) {
     std::lock_guard lock(mFrameRateOverridesLock);
     std::vector<FrameRateOverride> overrides;
     overrides.reserve(std::max({mFrameRateOverridesFromGameManager.size(),
@@ -67,6 +68,11 @@
             overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
         }
     }
+
+    if (!supportsFrameRateOverrideByContent) {
+        return overrides;
+    }
+
     for (const auto& [uid, frameRate] : mFrameRateOverridesByContent) {
         if (std::find_if(overrides.begin(), overrides.end(),
                          [uid = uid](auto i) { return i.uid == uid; }) == overrides.end()) {
diff --git a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h
index 278f87c..4185a4c 100644
--- a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h
+++ b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h
@@ -32,7 +32,8 @@
     std::optional<Fps> getFrameRateOverrideForUid(uid_t uid,
                                                   bool supportsFrameRateOverrideByContent) const
             EXCLUDES(mFrameRateOverridesLock);
-    std::vector<FrameRateOverride> getAllFrameRateOverrides() EXCLUDES(mFrameRateOverridesLock);
+    std::vector<FrameRateOverride> getAllFrameRateOverrides(bool supportsFrameRateOverrideByContent)
+            EXCLUDES(mFrameRateOverridesLock);
     void dump(std::string& result) const;
     bool updateFrameRateOverridesByContent(const UidToFrameRateOverride& frameRateOverrides)
             EXCLUDES(mFrameRateOverridesLock);
diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
index 016b076..760a4ee 100644
--- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h
+++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
@@ -39,13 +39,14 @@
                            nsecs_t deadlineTimestamp) {
         std::lock_guard<std::mutex> lock(mCallbackMutex);
         if (mCallback) {
-            mCallback->onVSyncEvent(when, expectedVSyncTimestamp, deadlineTimestamp);
+            mCallback->onVSyncEvent(when, {expectedVSyncTimestamp, deadlineTimestamp});
         }
     }
 
     const char* getName() const override { return "inject"; }
     void setVSyncEnabled(bool) override {}
     void setDuration(std::chrono::nanoseconds, std::chrono::nanoseconds) override {}
+    VSyncData getLatestVSyncData() const override { return {}; }
     void dump(std::string&) const override {}
 
 private:
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 665d36982..286e7f4 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -134,7 +134,8 @@
 std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
         const char* name, std::chrono::nanoseconds workDuration,
         std::chrono::nanoseconds readyDuration, bool traceVsync) {
-    return std::make_unique<scheduler::DispSyncSource>(getVsyncDispatch(), workDuration,
+    return std::make_unique<scheduler::DispSyncSource>(mVsyncSchedule->getDispatch(),
+                                                       mVsyncSchedule->getTracker(), workDuration,
                                                        readyDuration, traceVsync, name);
 }
 
@@ -262,8 +263,12 @@
 }
 
 void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) {
+    const auto refreshRateConfigs = holdRefreshRateConfigs();
+    const bool supportsFrameRateOverrideByContent =
+            refreshRateConfigs->supportsFrameRateOverrideByContent();
+
     std::vector<FrameRateOverride> overrides =
-            mFrameRateOverrideMappings.getAllFrameRateOverrides();
+            mFrameRateOverrideMappings.getAllFrameRateOverrides(supportsFrameRateOverrideByContent);
 
     android::EventThread* thread;
     {
@@ -681,10 +686,10 @@
 
 bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) {
     const auto refreshRateConfigs = holdRefreshRateConfigs();
-    if (!refreshRateConfigs->supportsFrameRateOverrideByContent()) {
-        return false;
-    }
 
+    // we always update mFrameRateOverridesByContent here
+    // supportsFrameRateOverridesByContent will be checked
+    // when getting FrameRateOverrides from mFrameRateOverrideMappings
     if (!consideredSignals.idle) {
         const auto frameRateOverrides =
                 refreshRateConfigs->getFrameRateOverrides(mPolicy.contentRequirements,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b3c3a41..ee1ea40 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -141,6 +141,7 @@
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
 #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
 
 #define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock)
@@ -163,6 +164,8 @@
 #define NO_THREAD_SAFETY_ANALYSIS \
     _Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"")
 
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
+using aidl::android::hardware::graphics::composer3::Capability;
 using aidl::android::hardware::graphics::composer3::DisplayCapability;
 
 namespace android {
@@ -247,11 +250,6 @@
     const status_t status;
 };
 
-struct SCOPED_CAPABILITY UnnecessaryLock {
-    explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {}
-    ~UnnecessaryLock() RELEASE() {}
-};
-
 // TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity.
 constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV;
 
@@ -497,8 +495,6 @@
 
     mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0);
 
-    enableLatchUnsignaledConfig = getLatchUnsignaledConfig();
-
     if (!mIsUserBuild && base::GetBoolProperty("debug.sf.enable_transaction_tracing"s, true)) {
         mTransactionTracing.emplace();
     }
@@ -507,11 +503,13 @@
 LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
     if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) {
         return LatchUnsignaledConfig::Always;
-    } else if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, false)) {
-        return LatchUnsignaledConfig::Auto;
-    } else {
-        return LatchUnsignaledConfig::Disabled;
     }
+
+    if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, false)) {
+        return LatchUnsignaledConfig::AutoSingleLayer;
+    }
+
+    return LatchUnsignaledConfig::Disabled;
 }
 
 SurfaceFlinger::~SurfaceFlinger() = default;
@@ -712,6 +710,7 @@
     mFlagManager = std::make_unique<android::FlagManager>();
     mFrameTracer->initialize();
     mFrameTimeline->onBootFinished();
+    getRenderEngine().setEnableTracing(mFlagManager->use_skia_tracing());
 
     // wait patiently for the window manager death
     const String16 name("window");
@@ -852,6 +851,8 @@
     mCompositionEngine->getHwComposer().setCallback(*this);
     ClientCache::getInstance().setRenderEngine(&getRenderEngine());
 
+    enableLatchUnsignaledConfig = getLatchUnsignaledConfig();
+
     if (base::GetBoolProperty("debug.sf.enable_hwc_vds"s, false)) {
         enableHalVirtualDisplays(true);
     }
@@ -891,7 +892,7 @@
     // Inform native graphics APIs whether the present timestamp is supported:
 
     const bool presentFenceReliable =
-            !getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE);
+            !getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE);
     mStartPropertySetThread = getFactory().createStartPropertySetThread(presentFenceReliable);
 
     if (mStartPropertySetThread->Start() != NO_ERROR) {
@@ -955,7 +956,7 @@
     };
     ConditionalLock _l(mStateLock,
             std::this_thread::get_id() != mMainThreadId);
-    if (!getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
+    if (!getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
         outSupported->push_back(FrameEvent::DISPLAY_PRESENT);
     }
     return NO_ERROR;
@@ -1731,11 +1732,15 @@
                    // If we support applying display brightness as a command, then we also support
                    // dimming SDR layers.
                    if (supportsDisplayBrightnessCommand) {
-                       display->getCompositionDisplay()
-                               ->setDisplayBrightness(brightness.sdrWhitePointNits,
-                                                      brightness.displayBrightnessNits);
+                       auto compositionDisplay = display->getCompositionDisplay();
+                       float currentDimmingRatio =
+                               compositionDisplay->editState().sdrWhitePointNits /
+                               compositionDisplay->editState().displayBrightnessNits;
+                       compositionDisplay->setDisplayBrightness(brightness.sdrWhitePointNits,
+                                                                brightness.displayBrightnessNits);
                        MAIN_THREAD_GUARD(display->stageBrightness(brightness.displayBrightness));
-                       if (hasVisibleHdrLayer(display)) {
+                       if (brightness.sdrWhitePointNits / brightness.displayBrightnessNits !=
+                           currentDimmingRatio) {
                            scheduleComposite(FrameHint::kNone);
                        } else {
                            scheduleCommit(FrameHint::kNone);
@@ -1812,8 +1817,9 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getDisplayDecorationSupport(const sp<IBinder>& displayToken,
-                                                     bool* outSupport) const {
+status_t SurfaceFlinger::getDisplayDecorationSupport(
+        const sp<IBinder>& displayToken,
+        std::optional<DisplayDecorationSupport>* outSupport) const {
     if (!displayToken || !outSupport) {
         return BAD_VALUE;
     }
@@ -1824,8 +1830,7 @@
     if (!displayId) {
         return NAME_NOT_FOUND;
     }
-    *outSupport =
-            getHwComposer().hasDisplayCapability(*displayId, DisplayCapability::DISPLAY_DECORATION);
+    getHwComposer().getDisplayDecorationSupport(*displayId, outSupport);
     return NO_ERROR;
 }
 
@@ -2356,9 +2361,11 @@
     // something (such as user input) to an accurate diasplay time.
     // Snapping also allows an app to precisely calculate
     // mVsyncConfiguration->getCurrentConfigs().late.sf with (presentLatency % interval).
-    nsecs_t bias = stats.vsyncPeriod / 2;
-    int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod;
-    nsecs_t snappedCompositeToPresentLatency =
+    const nsecs_t bias = stats.vsyncPeriod / 2;
+    const int64_t extraVsyncs = (stats.vsyncPeriod) > 0 ?
+        ((compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod) :
+        0;
+    const nsecs_t snappedCompositeToPresentLatency =
             (extraVsyncs > 0) ? idealLatency + (extraVsyncs * stats.vsyncPeriod) : idealLatency;
 
     std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
@@ -3377,7 +3384,7 @@
         features |= Feature::kTracePredictedVsync;
     }
     if (!base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false) &&
-        !getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
+        !getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
         features |= Feature::kPresentFences;
     }
 
@@ -3639,51 +3646,62 @@
     return old;
 }
 
+bool SurfaceFlinger::stopTransactionProcessing(
+        const std::unordered_set<sp<IBinder>, SpHash<IBinder>>&
+                applyTokensWithUnsignaledTransactions) const {
+    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) {
+        // if we are in LatchUnsignaledConfig::AutoSingleLayer
+        // then we should have only one applyToken for processing.
+        // so we can stop further transactions on this applyToken.
+        return !applyTokensWithUnsignaledTransactions.empty();
+    }
+
+    return false;
+}
+
 bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) {
     // to prevent onHandleDestroyed from being called while the lock is held,
     // we must keep a copy of the transactions (specifically the composer
     // states) around outside the scope of the lock
     std::vector<TransactionState> transactions;
     // Layer handles that have transactions with buffers that are ready to be applied.
-    std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> bufferLayersReadyToPresent;
+    std::unordered_set<sp<IBinder>, SpHash<IBinder>> bufferLayersReadyToPresent;
+    std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions;
     {
         Mutex::Autolock _l(mStateLock);
         {
             Mutex::Autolock _l(mQueueLock);
-            // allowLatchUnsignaled acts as a filter condition when latch unsignaled is either auto
-            // or always. auto: in this case we let buffer latch unsignaled if we have only one
-            // applyToken and if only first transaction is latch unsignaled. If more than one
-            // applyToken we don't latch unsignaled.
-            bool allowLatchUnsignaled = allowedLatchUnsignaled();
-            bool isFirstUnsignaledTransactionApplied = false;
             // Collect transactions from pending transaction queue.
             auto it = mPendingTransactionQueues.begin();
             while (it != mPendingTransactionQueues.end()) {
                 auto& [applyToken, transactionQueue] = *it;
                 while (!transactionQueue.empty()) {
+                    if (stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) {
+                        break;
+                    }
+
                     auto& transaction = transactionQueue.front();
-                    if (!transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
-                                                       transaction.isAutoTimestamp,
-                                                       transaction.desiredPresentTime,
-                                                       transaction.originUid, transaction.states,
-                                                       bufferLayersReadyToPresent,
-                                                       allowLatchUnsignaled)) {
+                    const auto ready =
+                            transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
+                                                          transaction.isAutoTimestamp,
+                                                          transaction.desiredPresentTime,
+                                                          transaction.originUid, transaction.states,
+                                                          bufferLayersReadyToPresent,
+                                                          transactions.size());
+                    if (ready == TransactionReadiness::NotReady) {
                         setTransactionFlags(eTransactionFlushNeeded);
                         break;
                     }
                     transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
                         bufferLayersReadyToPresent.insert(state.surface);
                     });
+                    const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled);
+                    if (appliedUnsignaled) {
+                        applyTokensWithUnsignaledTransactions.insert(transaction.applyToken);
+                    }
+
                     transactions.emplace_back(std::move(transaction));
                     transactionQueue.pop();
-                    if (allowLatchUnsignaled &&
-                        enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto) {
-                        // if allowLatchUnsignaled && we are in LatchUnsignaledConfig::Auto
-                        // then we should have only one applyToken for processing.
-                        // so we can stop further transactions on this applyToken.
-                        isFirstUnsignaledTransactionApplied = true;
-                        break;
-                    }
                 }
 
                 if (transactionQueue.empty()) {
@@ -3701,25 +3719,34 @@
             // Case 3: others are the transactions that are ready to apply.
             while (!mTransactionQueue.empty()) {
                 auto& transaction = mTransactionQueue.front();
-                bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) !=
+                const bool pendingTransactions =
+                        mPendingTransactionQueues.find(transaction.applyToken) !=
                         mPendingTransactionQueues.end();
-                if (isFirstUnsignaledTransactionApplied || pendingTransactions ||
-                    !transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
-                                                   transaction.isAutoTimestamp,
-                                                   transaction.desiredPresentTime,
-                                                   transaction.originUid, transaction.states,
-                                                   bufferLayersReadyToPresent,
-                                                   allowLatchUnsignaled)) {
+                const auto ready = [&]() REQUIRES(mStateLock) {
+                    if (pendingTransactions ||
+                        stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) {
+                        return TransactionReadiness::NotReady;
+                    }
+
+                    return transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
+                                                         transaction.isAutoTimestamp,
+                                                         transaction.desiredPresentTime,
+                                                         transaction.originUid, transaction.states,
+                                                         bufferLayersReadyToPresent,
+                                                         transactions.size());
+                }();
+
+                if (ready == TransactionReadiness::NotReady) {
                     mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction));
                 } else {
                     transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
                         bufferLayersReadyToPresent.insert(state.surface);
                     });
-                    transactions.emplace_back(std::move(transaction));
-                    if (allowLatchUnsignaled &&
-                        enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto) {
-                        isFirstUnsignaledTransactionApplied = true;
+                    const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled);
+                    if (appliedUnsignaled) {
+                        applyTokensWithUnsignaledTransactions.insert(transaction.applyToken);
                     }
+                    transactions.emplace_back(std::move(transaction));
                 }
                 mTransactionQueue.pop_front();
                 ATRACE_INT("TransactionQueue", mTransactionQueue.size());
@@ -3734,7 +3761,7 @@
                                        int64_t vsyncId) {
     bool needsTraversal = false;
     // Now apply all transactions.
-    for (const auto& transaction : transactions) {
+    for (auto& transaction : transactions) {
         needsTraversal |=
                 applyTransactionState(transaction.frameTimelineInfo, transaction.states,
                                       transaction.displays, transaction.flags,
@@ -3756,62 +3783,6 @@
     return needsTraversal;
 }
 
-bool SurfaceFlinger::allowedLatchUnsignaled() {
-    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
-        return false;
-    }
-    // Always mode matches the current latch unsignaled behavior.
-    // This behavior is currently used by the partners and we would like
-    // to keep it until we are completely migrated to Auto mode successfully
-    // and we we have our fallback based implementation in place.
-    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Always) {
-        return true;
-    }
-
-    //  if enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto
-    //  we don't latch unsignaled if more than one applyToken, as it can backpressure
-    //  the other transactions.
-    if (mPendingTransactionQueues.size() > 1) {
-        return false;
-    }
-    std::optional<sp<IBinder>> applyToken = std::nullopt;
-    bool isPendingTransactionQueuesItem = false;
-    if (!mPendingTransactionQueues.empty()) {
-        applyToken = mPendingTransactionQueues.begin()->first;
-        isPendingTransactionQueuesItem = true;
-    }
-
-    for (const auto& item : mTransactionQueue) {
-        if (!applyToken.has_value()) {
-            applyToken = item.applyToken;
-        } else if (applyToken.has_value() && applyToken != item.applyToken) {
-            return false;
-        }
-    }
-
-    if (isPendingTransactionQueuesItem) {
-        return checkTransactionCanLatchUnsignaled(
-                mPendingTransactionQueues.begin()->second.front());
-    } else if (applyToken.has_value()) {
-        return checkTransactionCanLatchUnsignaled((mTransactionQueue.front()));
-    }
-    return false;
-}
-
-bool SurfaceFlinger::checkTransactionCanLatchUnsignaled(const TransactionState& transaction) {
-    if (transaction.states.size() == 1) {
-        const auto& state = transaction.states.begin()->state;
-        if ((state.flags & ~layer_state_t::eBufferChanged) == 0 &&
-            state.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) &&
-            state.bufferData->acquireFence &&
-            state.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled) {
-            ATRACE_NAME("transactionCanLatchUnsignaled");
-            return true;
-        }
-    }
-    return false;
-}
-
 bool SurfaceFlinger::transactionFlushNeeded() {
     Mutex::Autolock _l(mQueueLock);
     return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty();
@@ -3838,13 +3809,46 @@
     return prediction->presentTime >= expectedPresentTime &&
             prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold;
 }
+bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state,
+                                           size_t numStates, size_t totalTXapplied) {
+    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
+        ALOGV("%s: false (LatchUnsignaledConfig::Disabled)", __func__);
+        return false;
+    }
 
-bool SurfaceFlinger::transactionIsReadyToBeApplied(
+    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Always) {
+        ALOGV("%s: true (LatchUnsignaledConfig::Always)", __func__);
+        return true;
+    }
+
+    // We only want to latch unsignaled when a single layer is updated in this
+    // transaction (i.e. not a blast sync transaction).
+    if (numStates != 1) {
+        ALOGV("%s: false (numStates=%zu)", __func__, numStates);
+        return false;
+    }
+
+    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer &&
+        totalTXapplied > 0) {
+        ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)", __func__,
+              totalTXapplied);
+        return false;
+    }
+
+    if (!layer->simpleBufferUpdate(state)) {
+        ALOGV("%s: false (!simpleBufferUpdate)", __func__);
+        return false;
+    }
+
+    ALOGV("%s: true", __func__);
+    return true;
+}
+
+auto SurfaceFlinger::transactionIsReadyToBeApplied(
         const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
         uid_t originUid, const Vector<ComposerState>& states,
-        const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>&
-                bufferLayersReadyToPresent,
-        bool allowLatchUnsignaled) const {
+        const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent,
+        size_t totalTXapplied) const -> TransactionReadiness {
     ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId);
     const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
     // Do not present if the desiredPresentTime has not passed unless it is more than one second
@@ -3852,31 +3856,24 @@
     if (!isAutoTimestamp && desiredPresentTime >= expectedPresentTime &&
         desiredPresentTime < expectedPresentTime + s2ns(1)) {
         ATRACE_NAME("not current");
-        return false;
+        return TransactionReadiness::NotReady;
     }
 
     if (!mScheduler->isVsyncValid(expectedPresentTime, originUid)) {
         ATRACE_NAME("!isVsyncValid");
-        return false;
+        return TransactionReadiness::NotReady;
     }
 
     // If the client didn't specify desiredPresentTime, use the vsyncId to determine the expected
     // present time of this transaction.
     if (isAutoTimestamp && frameIsEarly(expectedPresentTime, info.vsyncId)) {
         ATRACE_NAME("frameIsEarly");
-        return false;
+        return TransactionReadiness::NotReady;
     }
 
+    bool fenceUnsignaled = false;
     for (const ComposerState& state : states) {
         const layer_state_t& s = state.state;
-        const bool acquireFenceChanged = s.bufferData &&
-                s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged);
-        if (acquireFenceChanged && s.bufferData->acquireFence && !allowLatchUnsignaled &&
-            s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled) {
-            ATRACE_NAME("fence unsignaled");
-            return false;
-        }
-
         sp<Layer> layer = nullptr;
         if (s.surface) {
             layer = fromHandle(s.surface).promote();
@@ -3890,6 +3887,22 @@
 
         ATRACE_NAME(layer->getName().c_str());
 
+        const bool allowLatchUnsignaled =
+                shouldLatchUnsignaled(layer, s, states.size(), totalTXapplied);
+        ATRACE_INT("allowLatchUnsignaled", allowLatchUnsignaled);
+
+        const bool acquireFenceChanged = s.bufferData &&
+                s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) &&
+                s.bufferData->acquireFence;
+        fenceUnsignaled = fenceUnsignaled ||
+                (acquireFenceChanged &&
+                 s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled);
+
+        if (fenceUnsignaled && !allowLatchUnsignaled) {
+            ATRACE_NAME("fence unsignaled");
+            return TransactionReadiness::NotReady;
+        }
+
         if (s.hasBufferChanges()) {
             // If backpressure is enabled and we already have a buffer to commit, keep the
             // transaction in the queue.
@@ -3897,11 +3910,11 @@
                     bufferLayersReadyToPresent.find(s.surface) != bufferLayersReadyToPresent.end();
             if (layer->backpressureEnabled() && hasPendingBuffer && isAutoTimestamp) {
                 ATRACE_NAME("hasPendingBuffer");
-                return false;
+                return TransactionReadiness::NotReady;
             }
         }
     }
-    return true;
+    return fenceUnsignaled ? TransactionReadiness::ReadyUnsignaled : TransactionReadiness::Ready;
 }
 
 void SurfaceFlinger::queueTransaction(TransactionState& state) {
@@ -4028,7 +4041,7 @@
 }
 
 bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo,
-                                           const Vector<ComposerState>& states,
+                                           Vector<ComposerState>& states,
                                            const Vector<DisplayState>& displays, uint32_t flags,
                                            const InputWindowCommands& inputWindowCommands,
                                            const int64_t desiredPresentTime, bool isAutoTimestamp,
@@ -4050,9 +4063,9 @@
     }
 
     uint32_t clientStateFlags = 0;
-    for (const ComposerState& state : states) {
-        ComposerState stateCopy = state;
-        clientStateFlags |= setClientStateLocked(frameTimelineInfo, stateCopy, desiredPresentTime,
+    for (int i = 0; i < states.size(); i++) {
+        ComposerState& state = states.editItemAt(i);
+        clientStateFlags |= setClientStateLocked(frameTimelineInfo, state, desiredPresentTime,
                                                  isAutoTimestamp, postTime, permissions);
         if ((flags & eAnimation) && state.state.surface) {
             if (const auto layer = fromHandle(state.state.surface).promote()) {
@@ -5088,11 +5101,9 @@
 }
 
 LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
-    const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
-
     LayersProto layersProto;
     for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
-        layer->writeToProto(layersProto, traceFlags, display.get());
+        layer->writeToProto(layersProto, traceFlags);
     }
 
     return layersProto;
@@ -5133,8 +5144,7 @@
         rootProto->add_children(offscreenLayer->sequence);
 
         // Add layer
-        LayerProto* layerProto =
-                offscreenLayer->writeToProto(layersProto, traceFlags, nullptr /*device*/);
+        LayerProto* layerProto = offscreenLayer->writeToProto(layersProto, traceFlags);
         layerProto->set_parent(offscreenRootLayerId);
     }
 }
@@ -5508,7 +5518,13 @@
             }
             return PERMISSION_DENIED;
         }
-        case SET_OVERRIDE_FRAME_RATE:
+        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) {
@@ -5723,9 +5739,9 @@
             }
             case 1025: { // Set layer tracing
                 n = data.readInt32();
-                int64_t fixedStartingTime = data.readInt64();
                 bool tracingEnabledChanged;
-                if (n) {
+                if (n == 1) {
+                    int64_t fixedStartingTime = data.readInt64();
                     ALOGD("LayerTracing enabled");
                     tracingEnabledChanged = mLayerTracing.enable();
                     if (tracingEnabledChanged) {
@@ -5737,6 +5753,10 @@
                                 })
                                 .wait();
                     }
+                } else if (n == 2) {
+                    std::string filename = std::string(data.readCString());
+                    ALOGD("LayerTracing disabled. Trace wrote to %s", filename.c_str());
+                    tracingEnabledChanged = mLayerTracing.disable(filename.c_str());
                 } else {
                     ALOGD("LayerTracing disabled");
                     tracingEnabledChanged = mLayerTracing.disable();
@@ -5989,9 +6009,9 @@
                         mTransactionTracing->setBufferSize(
                                 TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE);
                     } else {
+                        mTransactionTracing->writeToFile();
                         mTransactionTracing->setBufferSize(
                                 TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE);
-                        mTransactionTracing->writeToFile();
                     }
                 }
                 reply->writeInt32(NO_ERROR);
@@ -6291,7 +6311,7 @@
     ui::Size reqSize;
     sp<Layer> parent;
     Rect crop(args.sourceCrop);
-    std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> excludeLayers;
+    std::unordered_set<sp<Layer>, SpHash<Layer>> excludeLayers;
     ui::Dataspace dataspace;
 
     // Call this before holding mStateLock to avoid any deadlocking.
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 77193a6..af6b415 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -85,6 +85,8 @@
 #include <unordered_set>
 #include <utility>
 
+#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+
 using namespace android::surfaceflinger;
 
 namespace android {
@@ -137,7 +139,20 @@
     eTransactionMask = 0x1f,
 };
 
-enum class LatchUnsignaledConfig { Always, Auto, Disabled };
+// Latch Unsignaled buffer behaviours
+enum class LatchUnsignaledConfig {
+    // All buffers are latched signaled.
+    Disabled,
+
+    // Latch unsignaled is permitted when a single layer is updated in a frame,
+    // and the update includes just a buffer update (i.e. no sync transactions
+    // or geometry changes).
+    AutoSingleLayer,
+
+    // All buffers are latched unsignaled. This behaviour is discouraged as it
+    // can break sync transactions, stall the display and cause undesired side effects.
+    Always,
+};
 
 using DisplayColorSetting = compositionengine::OutputColorSetting;
 
@@ -162,6 +177,11 @@
     std::atomic<nsecs_t> mLastSwapTime = 0;
 };
 
+struct SCOPED_CAPABILITY UnnecessaryLock {
+    explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {}
+    ~UnnecessaryLock() RELEASE() {}
+};
+
 class SurfaceFlinger : public BnSurfaceComposer,
                        public PriorityDumper,
                        private IBinder::DeathRecipient,
@@ -596,8 +616,10 @@
     status_t notifyPowerBoost(int32_t boostId) override;
     status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
                                      float lightPosY, float lightPosZ, float lightRadius) override;
-    status_t getDisplayDecorationSupport(const sp<IBinder>& displayToken,
-                                         bool* outSupport) const override;
+    status_t getDisplayDecorationSupport(
+            const sp<IBinder>& displayToken,
+            std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
+                    outSupport) const override;
     status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
                           int8_t compatibility, int8_t changeFrameRateStrategy) override;
 
@@ -714,7 +736,7 @@
     /*
      * Transactions
      */
-    bool applyTransactionState(const FrameTimelineInfo& info, const Vector<ComposerState>& state,
+    bool applyTransactionState(const FrameTimelineInfo& info, Vector<ComposerState>& state,
                                const Vector<DisplayState>& displays, uint32_t flags,
                                const InputWindowCommands& inputWindowCommands,
                                const int64_t desiredPresentTime, bool isAutoTimestamp,
@@ -749,17 +771,21 @@
     uint32_t setTransactionFlags(uint32_t mask, TransactionSchedule,
                                  const sp<IBinder>& applyToken = {});
     void commitOffscreenLayers();
-    bool transactionIsReadyToBeApplied(
+    enum class TransactionReadiness {
+        NotReady,
+        Ready,
+        ReadyUnsignaled,
+    };
+    TransactionReadiness transactionIsReadyToBeApplied(
             const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
             uid_t originUid, const Vector<ComposerState>& states,
-            const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>&
-                    bufferLayersReadyToPresent,
-            bool allowLatchUnsignaled) const REQUIRES(mStateLock);
+            const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent,
+            size_t totalTXapplied) const REQUIRES(mStateLock);
     static LatchUnsignaledConfig getLatchUnsignaledConfig();
-    bool latchUnsignaledIsAllowed(std::vector<TransactionState>& transactions) REQUIRES(mStateLock);
-    bool allowedLatchUnsignaled() REQUIRES(mQueueLock, mStateLock);
-    bool checkTransactionCanLatchUnsignaled(const TransactionState& transaction)
-            REQUIRES(mStateLock);
+    static bool shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t&,
+                                      size_t numStates, size_t totalTXapplied);
+    bool stopTransactionProcessing(const std::unordered_set<sp<IBinder>, SpHash<IBinder>>&
+                                           applyTokensWithUnsignaledTransactions) const;
     bool applyTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId)
             REQUIRES(mStateLock);
     uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
@@ -1155,7 +1181,7 @@
 
     // Tracks layers that have pending frames which are candidates for being
     // latched.
-    std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> mLayersWithQueuedFrames;
+    std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithQueuedFrames;
     // Tracks layers that need to update a display's dirty region.
     std::vector<sp<Layer>> mLayersPendingRefresh;
     std::array<FenceWithFenceTime, 2> mPreviousPresentFences;
@@ -1262,6 +1288,7 @@
     ui::Dataspace mDefaultCompositionDataspace;
     ui::Dataspace mWideColorGamutCompositionDataspace;
     ui::Dataspace mColorSpaceAgnosticDataspace;
+    float mDimmingRatio = -1.f;
 
     SurfaceFlingerBE mBE;
     std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index 006efdf..49554c7 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -45,14 +45,14 @@
     return true;
 }
 
-bool LayerTracing::disable() {
+bool LayerTracing::disable(std::string filename) {
     std::scoped_lock lock(mTraceLock);
     if (!mEnabled) {
         return false;
     }
     mEnabled = false;
     LayersTraceFileProto fileProto = createTraceFileProto();
-    mBuffer->writeToFile(fileProto, FILE_NAME);
+    mBuffer->writeToFile(fileProto, filename);
     mBuffer->reset();
     return true;
 }
diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h
index bd448c9..88a19ec 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.h
+++ b/services/surfaceflinger/Tracing/LayerTracing.h
@@ -43,7 +43,7 @@
     LayerTracing(SurfaceFlinger& flinger);
     ~LayerTracing();
     bool enable();
-    bool disable();
+    bool disable(std::string filename = FILE_NAME);
     bool isEnabled() const;
     status_t writeToFile();
     LayersTraceFileProto createTraceFileProto() const;
diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h
index 3b2626d..7e38c55 100644
--- a/services/surfaceflinger/Tracing/RingBuffer.h
+++ b/services/surfaceflinger/Tracing/RingBuffer.h
@@ -67,7 +67,7 @@
         // -rw-r--r--
         const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
         if (!android::base::WriteStringToFile(output, filename, mode, getuid(), getgid(), true)) {
-            ALOGE("Could not save the proto file.");
+            ALOGE("Could not save the proto file %s", filename.c_str());
             return PERMISSION_DENIED;
         }
         return NO_ERROR;
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index a91698f..fb5a6b3 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -22,9 +22,7 @@
 
 namespace android::surfaceflinger {
 
-proto::TransactionState TransactionProtoParser::toProto(const TransactionState& t,
-                                                        LayerHandleToIdFn getLayerId,
-                                                        DisplayHandleToIdFn getDisplayId) {
+proto::TransactionState TransactionProtoParser::toProto(const TransactionState& t) {
     proto::TransactionState proto;
     proto.set_pid(t.originPid);
     proto.set_uid(t.originUid);
@@ -33,12 +31,14 @@
     proto.set_post_time(t.postTime);
     proto.set_transaction_id(t.id);
 
+    proto.mutable_layer_changes()->Reserve(static_cast<int32_t>(t.states.size()));
     for (auto& layerState : t.states) {
-        proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state, getLayerId)));
+        proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state)));
     }
 
+    proto.mutable_display_changes()->Reserve(static_cast<int32_t>(t.displays.size()));
     for (auto& displayState : t.displays) {
-        proto.mutable_display_changes()->Add(std::move(toProto(displayState, getDisplayId)));
+        proto.mutable_display_changes()->Add(std::move(toProto(displayState)));
     }
     return proto;
 }
@@ -46,8 +46,9 @@
 proto::TransactionState TransactionProtoParser::toProto(
         const std::map<int32_t /* layerId */, TracingLayerState>& states) {
     proto::TransactionState proto;
+    proto.mutable_layer_changes()->Reserve(static_cast<int32_t>(states.size()));
     for (auto& [layerId, state] : states) {
-        proto::LayerState layerProto = toProto(state, nullptr);
+        proto::LayerState layerProto = toProto(state);
         if (layerProto.has_buffer_data()) {
             proto::LayerState_BufferData* bufferProto = layerProto.mutable_buffer_data();
             bufferProto->set_buffer_id(state.bufferId);
@@ -69,11 +70,10 @@
     return proto;
 }
 
-proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer,
-                                                  LayerHandleToIdFn getLayerId) {
+proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) {
     proto::LayerState proto;
-    if (getLayerId != nullptr) {
-        proto.set_layer_id(getLayerId(layer.surface));
+    if (layer.surface) {
+        proto.set_layer_id(mMapper->getLayerId(layer.surface));
     } else {
         proto.set_layer_id(layer.layerId);
     }
@@ -136,13 +136,27 @@
     }
     if (layer.what & layer_state_t::eBufferChanged) {
         proto::LayerState_BufferData* bufferProto = proto.mutable_buffer_data();
-        if (layer.bufferData->buffer) {
+        if (layer.bufferData->hasBuffer()) {
             bufferProto->set_buffer_id(layer.bufferData->getId());
             bufferProto->set_width(layer.bufferData->getWidth());
             bufferProto->set_height(layer.bufferData->getHeight());
             bufferProto->set_pixel_format(static_cast<proto::LayerState_BufferData_PixelFormat>(
                     layer.bufferData->getPixelFormat()));
             bufferProto->set_usage(layer.bufferData->getUsage());
+        } else {
+            uint64_t bufferId;
+            uint32_t width;
+            uint32_t height;
+            int32_t pixelFormat;
+            uint64_t usage;
+            mMapper->getGraphicBufferPropertiesFromCache(layer.bufferData->cachedBuffer, &bufferId,
+                                                         &width, &height, &pixelFormat, &usage);
+            bufferProto->set_buffer_id(bufferId);
+            bufferProto->set_width(width);
+            bufferProto->set_height(height);
+            bufferProto->set_pixel_format(
+                    static_cast<proto::LayerState_BufferData_PixelFormat>(pixelFormat));
+            bufferProto->set_usage(usage);
         }
         bufferProto->set_frame_number(layer.bufferData->frameNumber);
         bufferProto->set_flags(layer.bufferData->flags.get());
@@ -165,15 +179,15 @@
         }
     }
 
-    if ((layer.what & layer_state_t::eReparent) && getLayerId != nullptr) {
+    if (layer.what & layer_state_t::eReparent) {
         int32_t layerId = layer.parentSurfaceControlForChild
-                ? getLayerId(layer.parentSurfaceControlForChild->getHandle())
+                ? mMapper->getLayerId(layer.parentSurfaceControlForChild->getHandle())
                 : -1;
         proto.set_parent_id(layerId);
     }
-    if ((layer.what & layer_state_t::eRelativeLayerChanged) && getLayerId != nullptr) {
+    if (layer.what & layer_state_t::eRelativeLayerChanged) {
         int32_t layerId = layer.relativeLayerSurfaceControl
-                ? getLayerId(layer.relativeLayerSurfaceControl->getHandle())
+                ? mMapper->getLayerId(layer.relativeLayerSurfaceControl->getHandle())
                 : -1;
         proto.set_relative_parent_id(layerId);
         proto.set_z(layer.z);
@@ -200,12 +214,8 @@
             transformProto->set_ty(inputInfo->transform.ty());
             windowInfoProto->set_replace_touchable_region_with_crop(
                     inputInfo->replaceTouchableRegionWithCrop);
-            if (getLayerId != nullptr) {
-                windowInfoProto->set_crop_layer_id(
-                        getLayerId(inputInfo->touchableRegionCropHandle.promote()));
-            } else {
-                windowInfoProto->set_crop_layer_id(-1);
-            }
+            windowInfoProto->set_crop_layer_id(
+                    mMapper->getLayerId(inputInfo->touchableRegionCropHandle.promote()));
         }
     }
     if (layer.what & layer_state_t::eBackgroundColorChanged) {
@@ -252,13 +262,10 @@
     return proto;
 }
 
-proto::DisplayState TransactionProtoParser::toProto(const DisplayState& display,
-                                                    DisplayHandleToIdFn getDisplayId) {
+proto::DisplayState TransactionProtoParser::toProto(const DisplayState& display) {
     proto::DisplayState proto;
     proto.set_what(display.what);
-    if (getDisplayId != nullptr) {
-        proto.set_id(getDisplayId(display.token));
-    }
+    proto.set_id(mMapper->getDisplayId(display.token));
 
     if (display.what & DisplayState::eLayerStackChanged) {
         proto.set_layer_stack(display.layerStack.id);
@@ -290,9 +297,7 @@
     return proto;
 }
 
-TransactionState TransactionProtoParser::fromProto(const proto::TransactionState& proto,
-                                                   LayerIdToHandleFn getLayerHandle,
-                                                   DisplayIdToHandleFn getDisplayHandle) {
+TransactionState TransactionProtoParser::fromProto(const proto::TransactionState& proto) {
     TransactionState t;
     t.originPid = proto.pid();
     t.originUid = proto.uid();
@@ -306,14 +311,14 @@
     for (int i = 0; i < layerCount; i++) {
         ComposerState s;
         s.state.what = 0;
-        fromProto(proto.layer_changes(i), getLayerHandle, s.state);
+        fromProto(proto.layer_changes(i), s.state);
         t.states.add(s);
     }
 
     int32_t displayCount = proto.display_changes_size();
     t.displays.reserve(static_cast<size_t>(displayCount));
     for (int i = 0; i < displayCount; i++) {
-        t.displays.add(fromProto(proto.display_changes(i), getDisplayHandle));
+        t.displays.add(fromProto(proto.display_changes(i)));
     }
     return t;
 }
@@ -328,10 +333,9 @@
 }
 
 void TransactionProtoParser::mergeFromProto(const proto::LayerState& proto,
-                                            LayerIdToHandleFn getLayerHandle,
                                             TracingLayerState& outState) {
     layer_state_t state;
-    fromProto(proto, getLayerHandle, state);
+    fromProto(proto, state);
     outState.merge(state);
 
     if (state.what & layer_state_t::eReparent) {
@@ -356,14 +360,10 @@
     }
 }
 
-void TransactionProtoParser::fromProto(const proto::LayerState& proto,
-                                       LayerIdToHandleFn getLayerHandle, layer_state_t& layer) {
+void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_state_t& layer) {
     layer.layerId = proto.layer_id();
     layer.what |= proto.what();
-
-    if (getLayerHandle != nullptr) {
-        layer.surface = getLayerHandle(layer.layerId);
-    }
+    layer.surface = mMapper->getLayerHandle(layer.layerId);
 
     if (proto.what() & layer_state_t::ePositionChanged) {
         layer.x = proto.x();
@@ -420,10 +420,11 @@
         LayerProtoHelper::readFromProto(proto.crop(), layer.crop);
     }
     if (proto.what() & layer_state_t::eBufferChanged) {
-        if (!layer.bufferData) {
-            layer.bufferData = std::make_shared<BufferData>();
-        }
         const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
+        layer.bufferData =
+                std::move(mMapper->getGraphicData(bufferProto.buffer_id(), bufferProto.width(),
+                                                  bufferProto.height(), bufferProto.pixel_format(),
+                                                  bufferProto.usage()));
         layer.bufferData->frameNumber = bufferProto.frame_number();
         layer.bufferData->flags = Flags<BufferData::BufferDataChange>(bufferProto.flags());
         layer.bufferData->cachedBuffer.id = bufferProto.cached_buffer_id();
@@ -445,24 +446,24 @@
         }
     }
 
-    if ((proto.what() & layer_state_t::eReparent) && (getLayerHandle != nullptr)) {
+    if (proto.what() & layer_state_t::eReparent) {
         int32_t layerId = proto.parent_id();
         if (layerId == -1) {
             layer.parentSurfaceControlForChild = nullptr;
         } else {
             layer.parentSurfaceControlForChild =
-                    new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
-                                       nullptr, layerId);
+                    new SurfaceControl(SurfaceComposerClient::getDefault(),
+                                       mMapper->getLayerHandle(layerId), nullptr, layerId);
         }
     }
     if (proto.what() & layer_state_t::eRelativeLayerChanged) {
         int32_t layerId = proto.relative_parent_id();
         if (layerId == -1) {
             layer.relativeLayerSurfaceControl = nullptr;
-        } else if (getLayerHandle != nullptr) {
+        } else {
             layer.relativeLayerSurfaceControl =
-                    new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
-                                       nullptr, layerId);
+                    new SurfaceControl(SurfaceComposerClient::getDefault(),
+                                       mMapper->getLayerHandle(layerId), nullptr, layerId);
         }
         layer.z = proto.z();
     }
@@ -486,9 +487,7 @@
         inputInfo.replaceTouchableRegionWithCrop =
                 windowInfoProto.replace_touchable_region_with_crop();
         int32_t layerId = windowInfoProto.crop_layer_id();
-        if (getLayerHandle != nullptr) {
-            inputInfo.touchableRegionCropHandle = getLayerHandle(layerId);
-        }
+        inputInfo.touchableRegionCropHandle = mMapper->getLayerHandle(layerId);
         layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
     }
     if (proto.what() & layer_state_t::eBackgroundColorChanged) {
@@ -534,13 +533,10 @@
     }
 }
 
-DisplayState TransactionProtoParser::fromProto(const proto::DisplayState& proto,
-                                               DisplayIdToHandleFn getDisplayHandle) {
+DisplayState TransactionProtoParser::fromProto(const proto::DisplayState& proto) {
     DisplayState display;
     display.what = proto.what();
-    if (getDisplayHandle != nullptr) {
-        display.token = getDisplayHandle(proto.id());
-    }
+    display.token = mMapper->getDisplayHandle(proto.id());
 
     if (display.what & DisplayState::eLayerStackChanged) {
         display.layerStack.id = proto.layer_stack();
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index d589936..2f70b27 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -43,33 +43,77 @@
     TracingLayerCreationArgs args;
 };
 
-class TransactionProtoParser {
+// Class which exposes buffer properties from BufferData without holding on to the actual buffer
+// handle.
+class BufferDataStub : public BufferData {
 public:
-    typedef std::function<sp<IBinder>(int32_t)> LayerIdToHandleFn;
-    typedef std::function<sp<IBinder>(int32_t)> DisplayIdToHandleFn;
-    typedef std::function<int32_t(const sp<IBinder>&)> LayerHandleToIdFn;
-    typedef std::function<int32_t(const sp<IBinder>&)> DisplayHandleToIdFn;
-
-    static proto::TransactionState toProto(const TransactionState&, LayerHandleToIdFn getLayerIdFn,
-                                           DisplayHandleToIdFn getDisplayIdFn);
-    static proto::TransactionState toProto(
-            const std::map<int32_t /* layerId */, TracingLayerState>&);
-
-    static proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args);
-
-    static TransactionState fromProto(const proto::TransactionState&,
-                                      LayerIdToHandleFn getLayerHandleFn,
-                                      DisplayIdToHandleFn getDisplayHandleFn);
-    static void mergeFromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandleFn,
-                               TracingLayerState& outState);
-    static void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs);
+    BufferDataStub(uint64_t bufferId, uint32_t width, uint32_t height, int32_t pixelFormat,
+                   uint64_t outUsage)
+          : mBufferId(bufferId),
+            mWidth(width),
+            mHeight(height),
+            mPixelFormat(pixelFormat),
+            mOutUsage(outUsage) {}
+    bool hasBuffer() const override { return mBufferId != 0; }
+    bool hasSameBuffer(const BufferData& other) const override {
+        return getId() == other.getId() && frameNumber == other.frameNumber;
+    }
+    uint32_t getWidth() const override { return mWidth; }
+    uint32_t getHeight() const override { return mHeight; }
+    uint64_t getId() const override { return mBufferId; }
+    PixelFormat getPixelFormat() const override { return mPixelFormat; }
+    uint64_t getUsage() const override { return mOutUsage; }
 
 private:
-    static proto::LayerState toProto(const layer_state_t&, LayerHandleToIdFn getLayerId);
-    static proto::DisplayState toProto(const DisplayState&, DisplayHandleToIdFn getDisplayId);
-    static void fromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandle,
-                          layer_state_t& out);
-    static DisplayState fromProto(const proto::DisplayState&, DisplayIdToHandleFn getDisplayHandle);
+    uint64_t mBufferId;
+    uint32_t mWidth;
+    uint32_t mHeight;
+    int32_t mPixelFormat;
+    uint64_t mOutUsage;
+};
+
+class TransactionProtoParser {
+public:
+    // Utility class to map handles to ids and buffers to buffer properties without pulling
+    // in SurfaceFlinger dependencies.
+    class FlingerDataMapper {
+    public:
+        virtual ~FlingerDataMapper() = default;
+        virtual sp<IBinder> getLayerHandle(int32_t /* layerId */) const { return nullptr; }
+        virtual int32_t getLayerId(const sp<IBinder>& /* layerHandle */) const { return -1; }
+        virtual sp<IBinder> getDisplayHandle(int32_t /* displayId */) const { return nullptr; }
+        virtual int32_t getDisplayId(const sp<IBinder>& /* displayHandle */) const { return -1; }
+        virtual std::shared_ptr<BufferData> getGraphicData(uint64_t bufferId, uint32_t width,
+                                                           uint32_t height, int32_t pixelFormat,
+                                                           uint64_t usage) const {
+            return std::make_shared<BufferDataStub>(bufferId, width, height, pixelFormat, usage);
+        }
+        virtual void getGraphicBufferPropertiesFromCache(client_cache_t /* cachedBuffer */,
+                                                         uint64_t* /* outBufferId */,
+                                                         uint32_t* /* outWidth */,
+                                                         uint32_t* /* outHeight */,
+                                                         int32_t* /* outPixelFormat */,
+                                                         uint64_t* /* outUsage */) const {}
+    };
+
+    TransactionProtoParser(std::unique_ptr<FlingerDataMapper> provider)
+          : mMapper(std::move(provider)) {}
+
+    proto::TransactionState toProto(const TransactionState&);
+    proto::TransactionState toProto(const std::map<int32_t /* layerId */, TracingLayerState>&);
+    proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args);
+
+    TransactionState fromProto(const proto::TransactionState&);
+    void mergeFromProto(const proto::LayerState&, TracingLayerState& outState);
+    void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs);
+
+private:
+    proto::LayerState toProto(const layer_state_t&);
+    proto::DisplayState toProto(const DisplayState&);
+    void fromProto(const proto::LayerState&, layer_state_t& out);
+    DisplayState fromProto(const proto::DisplayState&);
+
+    std::unique_ptr<FlingerDataMapper> mMapper;
 };
 
 } // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index a46b795..d5e837f 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -23,11 +23,57 @@
 #include <utils/SystemClock.h>
 #include <utils/Trace.h>
 
+#include "ClientCache.h"
 #include "TransactionTracing.h"
+#include "renderengine/ExternalTexture.h"
 
 namespace android {
 
-TransactionTracing::TransactionTracing() {
+class FlingerDataMapper : public TransactionProtoParser::FlingerDataMapper {
+    std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */>& mLayerHandles;
+
+public:
+    FlingerDataMapper(std::unordered_map<BBinder* /* handle */, int32_t /* id */>& layerHandles)
+          : mLayerHandles(layerHandles) {}
+
+    int32_t getLayerId(const sp<IBinder>& layerHandle) const override {
+        if (layerHandle == nullptr) {
+            return -1;
+        }
+        auto it = mLayerHandles.find(layerHandle->localBinder());
+        if (it == mLayerHandles.end()) {
+            ALOGW("Could not find layer handle %p", layerHandle->localBinder());
+            return -1;
+        }
+        return it->second;
+    }
+
+    void getGraphicBufferPropertiesFromCache(client_cache_t cachedBuffer, uint64_t* outBufferId,
+                                             uint32_t* outWidth, uint32_t* outHeight,
+                                             int32_t* outPixelFormat,
+                                             uint64_t* outUsage) const override {
+        std::shared_ptr<renderengine::ExternalTexture> buffer =
+                ClientCache::getInstance().get(cachedBuffer);
+        if (!buffer || !buffer->getBuffer()) {
+            *outBufferId = 0;
+            *outWidth = 0;
+            *outHeight = 0;
+            *outPixelFormat = 0;
+            *outUsage = 0;
+            return;
+        }
+
+        *outBufferId = buffer->getId();
+        *outWidth = buffer->getWidth();
+        *outHeight = buffer->getHeight();
+        *outPixelFormat = buffer->getPixelFormat();
+        *outUsage = buffer->getUsage();
+        return;
+    }
+};
+
+TransactionTracing::TransactionTracing()
+      : mProtoParser(std::make_unique<FlingerDataMapper>(mLayerHandles)) {
     std::scoped_lock lock(mTraceLock);
 
     mBuffer.setSize(mBufferSizeInBytes);
@@ -53,11 +99,11 @@
     writeToFile();
 }
 
-status_t TransactionTracing::writeToFile() {
+status_t TransactionTracing::writeToFile(std::string filename) {
     std::scoped_lock lock(mTraceLock);
     proto::TransactionTraceFile fileProto = createTraceFileProto();
     addStartingStateToProtoLocked(fileProto);
-    return mBuffer.writeToFile(fileProto, FILE_NAME);
+    return mBuffer.writeToFile(fileProto, filename);
 }
 
 void TransactionTracing::setBufferSize(size_t bufferSizeInBytes) {
@@ -85,11 +131,7 @@
 void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
     std::scoped_lock lock(mTraceLock);
     ATRACE_CALL();
-    mQueuedTransactions[transaction.id] =
-            TransactionProtoParser::toProto(transaction,
-                                            std::bind(&TransactionTracing::getLayerIdLocked, this,
-                                                      std::placeholders::_1),
-                                            nullptr);
+    mQueuedTransactions[transaction.id] = mProtoParser.toProto(transaction);
 }
 
 void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
@@ -212,9 +254,7 @@
         ALOGW("Duplicate handles found. %p", layerHandle);
     }
     mLayerHandles[layerHandle] = layerId;
-    proto::LayerCreationArgs protoArgs = TransactionProtoParser::toProto(args);
-    proto::LayerCreationArgs protoArgsCopy = protoArgs;
-    mCreatedLayers.push_back(protoArgs);
+    mCreatedLayers.push_back(mProtoParser.toProto(args));
 }
 
 void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId,
@@ -225,7 +265,7 @@
         ALOGW("Duplicate handles found. %p", layerHandle);
     }
     mLayerHandles[layerHandle] = layerId;
-    mCreatedLayers.emplace_back(TransactionProtoParser::toProto(args));
+    mCreatedLayers.emplace_back(mProtoParser.toProto(args));
 }
 
 void TransactionTracing::onLayerRemoved(int32_t layerId) {
@@ -263,18 +303,6 @@
     }
 }
 
-int32_t TransactionTracing::getLayerIdLocked(const sp<IBinder>& layerHandle) {
-    if (layerHandle == nullptr) {
-        return -1;
-    }
-    auto it = mLayerHandles.find(layerHandle->localBinder());
-    if (it == mLayerHandles.end()) {
-        ALOGW("Could not find layer handle %p", layerHandle->localBinder());
-        return -1;
-    }
-    return it->second;
-}
-
 void TransactionTracing::updateStartingStateLocked(
         const proto::TransactionTraceEntry& removedEntry) {
     mStartingTimestamp = removedEntry.elapsed_realtime_nanos();
@@ -283,7 +311,7 @@
     for (const proto::LayerCreationArgs& addedLayer : removedEntry.added_layers()) {
         TracingLayerState& startingState = mStartingStates[addedLayer.layer_id()];
         startingState.layerId = addedLayer.layer_id();
-        TransactionProtoParser::fromProto(addedLayer, startingState.args);
+        mProtoParser.fromProto(addedLayer, startingState.args);
     }
 
     // Merge layer states to starting transaction state.
@@ -294,7 +322,7 @@
                 ALOGW("Could not find layer id %d", layerState.layer_id());
                 continue;
             }
-            TransactionProtoParser::mergeFromProto(layerState, nullptr, it->second);
+            mProtoParser.mergeFromProto(layerState, it->second);
         }
     }
 
@@ -316,10 +344,10 @@
 
     entryProto->mutable_added_layers()->Reserve(static_cast<int32_t>(mStartingStates.size()));
     for (auto& [layerId, state] : mStartingStates) {
-        entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(state.args));
+        entryProto->mutable_added_layers()->Add(mProtoParser.toProto(state.args));
     }
 
-    proto::TransactionState transactionProto = TransactionProtoParser::toProto(mStartingStates);
+    proto::TransactionState transactionProto = mProtoParser.toProto(mStartingStates);
     transactionProto.set_vsync_id(0);
     transactionProto.set_post_time(mStartingTimestamp);
     entryProto->mutable_transactions()->Add(std::move(transactionProto));
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
index d5d98ce..95256c4 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.h
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -55,7 +55,7 @@
 
     void addQueuedTransaction(const TransactionState&);
     void addCommittedTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId);
-    status_t writeToFile();
+    status_t writeToFile(std::string filename = FILE_NAME);
     void setBufferSize(size_t bufferSizeInBytes);
     void onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, uint32_t flags,
                       int parentId);
@@ -84,6 +84,7 @@
             GUARDED_BY(mTraceLock);
     std::vector<int32_t /* layerId */> mRemovedLayerHandles GUARDED_BY(mTraceLock);
     std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock);
+    TransactionProtoParser mProtoParser GUARDED_BY(mTraceLock);
 
     // We do not want main thread to block so main thread will try to acquire mMainThreadLock,
     // otherwise will push data to temporary container.
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index b705d9c..e1f348f 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -167,7 +167,7 @@
                                           handle->gpuCompositionDoneFence->getSnapshot().fence,
                                           handle->compositorTiming, handle->refreshStartTime,
                                           handle->dequeueReadyTime);
-        transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
+        transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTimeOrFence,
                                                     handle->previousReleaseFence,
                                                     handle->transformHint,
                                                     handle->currentMaxAcquiredBufferCount,
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 5ef5475..a68cd87 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -47,7 +47,7 @@
     std::string name;
     sp<Fence> previousReleaseFence;
     std::vector<std::shared_future<renderengine::RenderEngineResult>> previousReleaseFences;
-    nsecs_t acquireTime = -1;
+    std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence = -1;
     nsecs_t latchTime = -1;
     uint32_t transformHint = 0;
     uint32_t currentMaxAcquiredBufferCount = 0;
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index 72434e9..23cd993 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -67,8 +67,7 @@
 void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
                                                     const std::vector<DisplayInfo>& displayInfos,
                                                     bool shouldSync) {
-    std::unordered_set<sp<IWindowInfosListener>, ISurfaceComposer::SpHash<IWindowInfosListener>>
-            windowInfosListeners;
+    std::unordered_set<sp<IWindowInfosListener>, SpHash<IWindowInfosListener>> windowInfosListeners;
 
     {
         std::scoped_lock lock(mListenersMutex);
diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp
index b0d216e..d2f6f71 100644
--- a/services/surfaceflinger/fuzzer/Android.bp
+++ b/services/surfaceflinger/fuzzer/Android.bp
@@ -15,6 +15,15 @@
  *
  */
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "surfaceflinger_fuzz_defaults",
     include_dirs: [
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
index 816d2f1..3c4ab95 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -44,6 +44,7 @@
 
 using namespace android::hardware::graphics::common;
 using namespace android::hardware::graphics::composer;
+namespace aidl = aidl::android::hardware::graphics::composer3;
 namespace hal = android::hardware::graphics::composer::hal;
 using Config = hal::V2_1::Config;
 using Display = hal::V2_1::Display;
@@ -58,10 +59,11 @@
                                                  hal::Transform::ROT_90, hal::Transform::ROT_180,
                                                  hal::Transform::ROT_270};
 
-static constexpr hal::Capability kCapability[] = {hal::Capability::INVALID,
-                                                  hal::Capability::SIDEBAND_STREAM,
-                                                  hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM,
-                                                  hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE};
+static constexpr aidl::Capability kCapability[] = {aidl::Capability::INVALID,
+                                                   aidl::Capability::SIDEBAND_STREAM,
+                                                   aidl::Capability::SKIP_CLIENT_COLOR_TRANSFORM,
+                                                   aidl::Capability::PRESENT_FENCE_IS_NOT_RELIABLE,
+                                                   aidl::Capability::SKIP_VALIDATE};
 
 static constexpr hal::BlendMode kBlendModes[] = {hal::BlendMode::INVALID, hal::BlendMode::NONE,
                                                  hal::BlendMode::PREMULTIPLIED,
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index 4f89cd9..30a6fbd 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -25,7 +25,7 @@
 
 static constexpr LatchUnsignaledConfig kLatchUnsignaledConfig[] = {
         LatchUnsignaledConfig::Always,
-        LatchUnsignaledConfig::Auto,
+        LatchUnsignaledConfig::AutoSingleLayer,
         LatchUnsignaledConfig::Disabled,
 };
 
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 51a5081..09ffb02 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -63,8 +63,7 @@
     FuzzedDataProvider mFdp;
 
 protected:
-    void onVSyncEvent(nsecs_t /* when */, nsecs_t /* expectedVSyncTimestamp */,
-                      nsecs_t /* deadlineTimestamp */) {}
+    void onVSyncEvent(nsecs_t /* when */, VSyncSource::VSyncData) {}
 };
 
 PhysicalDisplayId SchedulerFuzzer::getPhysicalDisplayId() {
@@ -101,8 +100,9 @@
 void SchedulerFuzzer::fuzzDispSyncSource() {
     std::unique_ptr<FuzzImplVSyncDispatch> vSyncDispatch =
             std::make_unique<FuzzImplVSyncDispatch>();
+    std::unique_ptr<FuzzImplVSyncTracker> vSyncTracker = std::make_unique<FuzzImplVSyncTracker>();
     std::unique_ptr<scheduler::DispSyncSource> dispSyncSource = std::make_unique<
-            scheduler::DispSyncSource>(*vSyncDispatch,
+            scheduler::DispSyncSource>(*vSyncDispatch, *vSyncTracker,
                                        (std::chrono::nanoseconds)
                                                mFdp.ConsumeIntegral<uint64_t>() /*workDuration*/,
                                        (std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>()
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
index 89cf819..84b3912 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
@@ -103,6 +103,8 @@
     void setDuration(std::chrono::nanoseconds /* workDuration */,
                      std::chrono::nanoseconds /* readyDuration */) override {}
 
+    VSyncData getLatestVSyncData() const override { return {}; }
+
     void dump(std::string& /* result */) const override {}
 };
 
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 7b86229..efcc386 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -31,6 +31,7 @@
         "Credentials_test.cpp",
         "DereferenceSurfaceControl_test.cpp",
         "DisplayConfigs_test.cpp",
+        "DisplayEventReceiver_test.cpp",
         "EffectLayer_test.cpp",
         "InvalidHandles_test.cpp",
         "LayerCallback_test.cpp",
@@ -47,6 +48,7 @@
         "ReleaseBufferCallback_test.cpp",
         "ScreenCapture_test.cpp",
         "SetFrameRate_test.cpp",
+        "SetFrameRateOverride_test.cpp",
         "SetGeometry_test.cpp",
         "Stress_test.cpp",
         "SurfaceInterceptor_test.cpp",
diff --git a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
new file mode 100644
index 0000000..01adbc8
--- /dev/null
+++ b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <gui/DisplayEventReceiver.h>
+
+namespace android {
+
+class DisplayEventReceiverTest : public ::testing::Test {
+public:
+    void SetUp() override { EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.initCheck()); }
+
+    DisplayEventReceiver mDisplayEventReceiver;
+};
+
+TEST_F(DisplayEventReceiverTest, getLatestVsyncEventData) {
+    const nsecs_t now = systemTime();
+    VsyncEventData vsyncEventData;
+    EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.getLatestVsyncEventData(&vsyncEventData));
+
+    EXPECT_NE(std::numeric_limits<size_t>::max(), vsyncEventData.preferredFrameTimelineIndex);
+    EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now)
+            << "Deadline timestamp should be greater than frame time";
+    for (size_t i = 0; i < vsyncEventData.frameTimelines.size(); i++) {
+        EXPECT_NE(FrameTimelineInfo::INVALID_VSYNC_ID, vsyncEventData.frameTimelines[i].id);
+        EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime,
+                  vsyncEventData.frameTimelines[i].deadlineTimestamp)
+                << "Expected vsync timestamp should be greater than deadline";
+        if (i > 0) {
+            EXPECT_GT(vsyncEventData.frameTimelines[i].deadlineTimestamp,
+                      vsyncEventData.frameTimelines[i - 1].deadlineTimestamp)
+                    << "Deadline timestamp out of order for frame timeline " << i;
+            EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime,
+                      vsyncEventData.frameTimelines[i - 1].expectedPresentTime)
+                    << "Expected vsync timestamp out of order for frame timeline " << i;
+        }
+    }
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp b/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp
new file mode 100644
index 0000000..4efec77
--- /dev/null
+++ b/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <gui/DisplayEventReceiver.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <sys/epoll.h>
+#include <algorithm>
+
+namespace android {
+namespace {
+using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
+
+class SetFrameRateOverrideTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        const ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp;
+        const ISurfaceComposer::EventRegistrationFlags eventRegistration = {
+                ISurfaceComposer::EventRegistration::frameRateOverride};
+
+        mDisplayEventReceiver =
+                std::make_unique<DisplayEventReceiver>(vsyncSource, eventRegistration);
+        EXPECT_EQ(NO_ERROR, mDisplayEventReceiver->initCheck());
+
+        mEpollFd = epoll_create1(EPOLL_CLOEXEC);
+        EXPECT_GT(mEpollFd, 1);
+
+        epoll_event event;
+        event.events = EPOLLIN;
+        EXPECT_EQ(0, epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mDisplayEventReceiver->getFd(), &event));
+    }
+
+    void TearDown() override { close(mEpollFd); }
+
+    void setFrameRateAndListenEvents(uid_t uid, float frameRate) {
+        status_t ret = SurfaceComposerClient::setOverrideFrameRate(uid, frameRate);
+        ASSERT_EQ(NO_ERROR, ret);
+
+        DisplayEventReceiver::Event event;
+        bool isOverrideFlushReceived = false;
+        mFrameRateOverrides.clear();
+
+        epoll_event epollEvent;
+        while (epoll_wait(mEpollFd, &epollEvent, 1, 1000) > 0) {
+            while (mDisplayEventReceiver->getEvents(&event, 1) > 0) {
+                if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE) {
+                    mFrameRateOverrides.emplace_back(event.frameRateOverride);
+                }
+                if (event.header.type ==
+                    DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH) {
+                    isOverrideFlushReceived = true;
+                }
+            }
+
+            if (isOverrideFlushReceived) break;
+        }
+    }
+
+    std::unique_ptr<DisplayEventReceiver> mDisplayEventReceiver;
+    std::vector<FrameRateOverride> mFrameRateOverrides;
+
+    int mEpollFd;
+};
+
+TEST_F(SetFrameRateOverrideTest, SetFrameRateOverrideCall) {
+    uid_t uid = getuid();
+    float frameRate = 30.0f;
+    setFrameRateAndListenEvents(uid, frameRate);
+    // check if the frame rate override we set exists
+    ASSERT_TRUE(std::find_if(mFrameRateOverrides.begin(), mFrameRateOverrides.end(),
+                             [uid = uid, frameRate = frameRate](auto i) {
+                                 return uid == i.uid && frameRate == i.frameRateHz;
+                             }) != mFrameRateOverrides.end());
+
+    // test removing frame rate override
+    frameRate = 0.0f;
+    setFrameRateAndListenEvents(uid, frameRate);
+    ASSERT_TRUE(std::find_if(mFrameRateOverrides.begin(), mFrameRateOverrides.end(),
+                             [uid = uid, frameRate = frameRate](auto i) {
+                                 return uid == i.uid && frameRate == i.frameRateHz;
+                             }) == mFrameRateOverrides.end());
+}
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 48f18b9..1db5e61 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -80,6 +80,7 @@
         "FpsReporterTest.cpp",
         "FpsTest.cpp",
         "FramebufferSurfaceTest.cpp",
+        "FrameRateOverrideMappingsTest.cpp",
         "FrameTimelineTest.cpp",
         "GameModeTest.cpp",
         "HWComposerTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 3716f59..1669075 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -61,6 +61,8 @@
 using hal::PowerMode;
 using hal::Transform;
 
+using aidl::android::hardware::graphics::composer3::Capability;
+
 using testing::_;
 using testing::AtLeast;
 using testing::DoAll;
@@ -169,7 +171,7 @@
     template <typename Case>
     void captureScreenComposition();
 
-    std::unordered_set<hal::Capability> mDefaultCapabilities = {hal::Capability::SIDEBAND_STREAM};
+    std::unordered_set<Capability> mDefaultCapabilities = {Capability::SIDEBAND_STREAM};
 
     bool mDisplayOff = false;
     TestableSurfaceFlinger mFlinger;
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index f613e43..0b6b475 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -28,6 +28,7 @@
 #include "AsyncCallRecorder.h"
 #include "Scheduler/DispSyncSource.h"
 #include "Scheduler/VSyncDispatch.h"
+#include "mock/MockVSyncTracker.h"
 
 namespace android {
 namespace {
@@ -125,16 +126,16 @@
     DispSyncSourceTest();
     ~DispSyncSourceTest() override;
 
-    void createDispSync();
+    void SetUp() override;
     void createDispSyncSource();
 
-    void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
-                      nsecs_t deadlineTimestamp) override;
+    void onVSyncEvent(nsecs_t when, VSyncSource::VSyncData) override;
 
     std::unique_ptr<MockVSyncDispatch> mVSyncDispatch;
+    std::unique_ptr<mock::VSyncTracker> mVSyncTracker;
     std::unique_ptr<scheduler::DispSyncSource> mDispSyncSource;
 
-    AsyncCallRecorder<void (*)(nsecs_t, nsecs_t, nsecs_t)> mVSyncEventCallRecorder;
+    AsyncCallRecorder<void (*)(nsecs_t, VSyncSource::VSyncData)> mVSyncEventCallRecorder;
 
     static constexpr std::chrono::nanoseconds mWorkDuration = 20ms;
     static constexpr std::chrono::nanoseconds mReadyDuration = 10ms;
@@ -155,21 +156,21 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
-                                      nsecs_t deadlineTimestamp) {
-    ALOGD("onVSyncEvent: %" PRId64, when);
-
-    mVSyncEventCallRecorder.recordCall(when, expectedVSyncTimestamp, deadlineTimestamp);
+void DispSyncSourceTest::SetUp() {
+    mVSyncDispatch = std::make_unique<MockVSyncDispatch>();
+    mVSyncTracker = std::make_unique<mock::VSyncTracker>();
 }
 
-void DispSyncSourceTest::createDispSync() {
-    mVSyncDispatch = std::make_unique<MockVSyncDispatch>();
+void DispSyncSourceTest::onVSyncEvent(nsecs_t when, VSyncSource::VSyncData vsyncData) {
+    ALOGD("onVSyncEvent: %" PRId64, when);
+
+    mVSyncEventCallRecorder.recordCall(when, vsyncData);
 }
 
 void DispSyncSourceTest::createDispSyncSource() {
-    mDispSyncSource =
-            std::make_unique<scheduler::DispSyncSource>(*mVSyncDispatch, mWorkDuration,
-                                                        mReadyDuration, true, mName.c_str());
+    mDispSyncSource = std::make_unique<scheduler::DispSyncSource>(*mVSyncDispatch, *mVSyncTracker,
+                                                                  mWorkDuration, mReadyDuration,
+                                                                  true, mName.c_str());
     mDispSyncSource->setCallback(this);
 }
 
@@ -178,13 +179,10 @@
  */
 
 TEST_F(DispSyncSourceTest, createDispSync) {
-    createDispSync();
     EXPECT_TRUE(mVSyncDispatch);
 }
 
 TEST_F(DispSyncSourceTest, createDispSyncSource) {
-    createDispSync();
-
     InSequence seq;
     EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).WillOnce(Return(mFakeToken));
     EXPECT_CALL(*mVSyncDispatch, cancel(mFakeToken))
@@ -196,8 +194,6 @@
 }
 
 TEST_F(DispSyncSourceTest, noCallbackAfterInit) {
-    createDispSync();
-
     InSequence seq;
     EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
     EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
@@ -212,8 +208,6 @@
 }
 
 TEST_F(DispSyncSourceTest, waitForCallbacks) {
-    createDispSync();
-
     InSequence seq;
     EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
     EXPECT_CALL(*mVSyncDispatch,
@@ -233,14 +227,14 @@
         mVSyncDispatch->triggerCallbacks();
         const auto callbackData = mVSyncEventCallRecorder.waitForCall();
         ASSERT_TRUE(callbackData.has_value());
-        const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
-        EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count());
+        const auto [when, vsyncData] = callbackData.value();
+        EXPECT_EQ(when,
+                  vsyncData.expectedVSyncTimestamp - mWorkDuration.count() -
+                          mReadyDuration.count());
     }
 }
 
 TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) {
-    createDispSync();
-
     InSequence seq;
     EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
     EXPECT_CALL(*mVSyncDispatch,
@@ -265,8 +259,10 @@
         mVSyncDispatch->triggerCallbacks();
         const auto callbackData = mVSyncEventCallRecorder.waitForCall();
         ASSERT_TRUE(callbackData.has_value());
-        const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
-        EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count());
+        const auto [when, vsyncData] = callbackData.value();
+        EXPECT_EQ(when,
+                  vsyncData.expectedVSyncTimestamp - mWorkDuration.count() -
+                          mReadyDuration.count());
     }
 
     const auto newDuration = mWorkDuration / 2;
@@ -286,13 +282,35 @@
         mVSyncDispatch->triggerCallbacks();
         const auto callbackData = mVSyncEventCallRecorder.waitForCall();
         ASSERT_TRUE(callbackData.has_value());
-        const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
-        EXPECT_EQ(when, expectedVSyncTimestamp - newDuration.count());
+        const auto [when, vsyncData] = callbackData.value();
+        EXPECT_EQ(when, vsyncData.expectedVSyncTimestamp - newDuration.count());
     }
 
     EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
     EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
 }
 
+TEST_F(DispSyncSourceTest, getLatestVsyncData) {
+    const nsecs_t now = systemTime();
+    const nsecs_t vsyncInternalDuration = mWorkDuration.count() + mReadyDuration.count();
+    EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_))
+            .WillOnce(Return(now + vsyncInternalDuration + 1));
+    {
+        InSequence seq;
+        EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
+        EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
+        EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
+    }
+
+    createDispSyncSource();
+    EXPECT_TRUE(mDispSyncSource);
+
+    const auto vsyncData = mDispSyncSource->getLatestVSyncData();
+    ASSERT_GT(vsyncData.deadlineTimestamp, now);
+    ASSERT_GT(vsyncData.expectedVSyncTimestamp, vsyncData.deadlineTimestamp);
+    EXPECT_EQ(vsyncData.deadlineTimestamp,
+              vsyncData.expectedVSyncTimestamp - vsyncInternalDuration);
+}
+
 } // namespace
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 67a0d7e..cc0a40f 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -59,6 +59,7 @@
                  void(std::chrono::nanoseconds workDuration,
                       std::chrono::nanoseconds readyDuration));
     MOCK_METHOD1(pauseVsyncCallback, void(bool));
+    MOCK_METHOD(VSyncSource::VSyncData, getLatestVSyncData, (), (const, override));
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
@@ -257,7 +258,7 @@
     ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp "
                                   << expectedTimestamp;
     const auto& event = std::get<0>(args.value());
-    for (int i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) {
+    for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
         auto prediction =
                 mTokenManager->getPredictionsForToken(event.vsync.frameTimelines[i].vsyncId);
         EXPECT_TRUE(prediction.has_value());
@@ -275,17 +276,16 @@
                       event.vsync.frameTimelines[i - 1].expectedVSyncTimestamp)
                     << "Expected vsync timestamp out of order for frame timeline " << i;
         }
-        if (event.vsync.frameTimelines[i].deadlineTimestamp == preferredDeadline) {
-            EXPECT_EQ(i, event.vsync.preferredFrameTimelineIndex)
-                    << "Preferred frame timeline index should be " << i;
-            // For the platform-preferred frame timeline, the vsync ID is 0 because the first frame
-            // timeline is made before the rest.
-            EXPECT_EQ(0, event.vsync.frameTimelines[i].vsyncId)
-                    << "Vsync ID incorrect for frame timeline " << i;
-        } else {
-            // Vsync ID 0 is used for the preferred frame timeline.
-            EXPECT_EQ(i + 1, event.vsync.frameTimelines[i].vsyncId)
-                    << "Vsync ID incorrect for frame timeline " << i;
+
+        // Vsync ID order lines up with registration into test token manager.
+        EXPECT_EQ(i, event.vsync.frameTimelines[i].vsyncId)
+                << "Vsync ID incorrect for frame timeline " << i;
+        if (i == event.vsync.preferredFrameTimelineIndex) {
+            EXPECT_EQ(event.vsync.frameTimelines[i].deadlineTimestamp, preferredDeadline)
+                    << "Preferred deadline timestamp incorrect" << i;
+            EXPECT_EQ(event.vsync.frameTimelines[i].expectedVSyncTimestamp,
+                      event.vsync.expectedVSyncTimestamp)
+                    << "Preferred expected vsync timestamp incorrect" << i;
         }
     }
 }
@@ -333,6 +333,8 @@
 
 namespace {
 
+using namespace testing;
+
 /* ------------------------------------------------------------------------
  * Test cases
  */
@@ -369,7 +371,7 @@
 
     // Use the received callback to signal a first vsync event.
     // The interceptor should receive the event, as well as the connection.
-    mCallback->onVSyncEvent(123, 456, 789);
+    mCallback->onVSyncEvent(123, {456, 789});
     expectInterceptCallReceived(123);
     expectThrottleVsyncReceived(456, mConnectionUid);
     expectVsyncEventReceivedByConnection(123, 1u);
@@ -377,7 +379,7 @@
     // Use the received callback to signal a second vsync event.
     // The interceptor should receive the event, but the connection should
     // not as it was only interested in the first.
-    mCallback->onVSyncEvent(456, 123, 0);
+    mCallback->onVSyncEvent(456, {123, 0});
     expectInterceptCallReceived(456);
     EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
@@ -395,11 +397,57 @@
 
     // Use the received callback to signal a vsync event.
     // The interceptor should receive the event, as well as the connection.
-    mCallback->onVSyncEvent(123, 456, 789);
+    mCallback->onVSyncEvent(123, {456, 789});
     expectInterceptCallReceived(123);
     expectVsyncEventFrameTimelinesCorrect(123, 789);
 }
 
+TEST_F(EventThreadTest, getLatestVsyncEventData) {
+    const nsecs_t now = systemTime();
+    const nsecs_t preferredDeadline = now + 10000000;
+    const nsecs_t preferredExpectedVSyncTimestamp = now + 20000000;
+    const VSyncSource::VSyncData preferredData = {preferredExpectedVSyncTimestamp,
+                                                  preferredDeadline};
+    EXPECT_CALL(*mVSyncSource, getLatestVSyncData()).WillOnce(Return(preferredData));
+
+    VsyncEventData vsyncEventData = mThread->getLatestVsyncEventData(mConnection);
+    EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now)
+            << "Deadline timestamp should be greater than frame time";
+    for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+        auto prediction =
+                mTokenManager->getPredictionsForToken(vsyncEventData.frameTimelines[i].id);
+        EXPECT_TRUE(prediction.has_value());
+        EXPECT_EQ(prediction.value().endTime, vsyncEventData.frameTimelines[i].deadlineTimestamp)
+                << "Deadline timestamp does not match cached value";
+        EXPECT_EQ(prediction.value().presentTime,
+                  vsyncEventData.frameTimelines[i].expectedPresentTime)
+                << "Expected vsync timestamp does not match cached value";
+        EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime,
+                  vsyncEventData.frameTimelines[i].deadlineTimestamp)
+                << "Expected vsync timestamp should be greater than deadline";
+
+        if (i > 0) {
+            EXPECT_GT(vsyncEventData.frameTimelines[i].deadlineTimestamp,
+                      vsyncEventData.frameTimelines[i - 1].deadlineTimestamp)
+                    << "Deadline timestamp out of order for frame timeline " << i;
+            EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime,
+                      vsyncEventData.frameTimelines[i - 1].expectedPresentTime)
+                    << "Expected vsync timestamp out of order for frame timeline " << i;
+        }
+
+        // Vsync ID order lines up with registration into test token manager.
+        EXPECT_EQ(i, vsyncEventData.frameTimelines[i].id)
+                << "Vsync ID incorrect for frame timeline " << i;
+        if (i == vsyncEventData.preferredFrameTimelineIndex) {
+            EXPECT_EQ(vsyncEventData.frameTimelines[i].deadlineTimestamp, preferredDeadline)
+                    << "Preferred deadline timestamp incorrect" << i;
+            EXPECT_EQ(vsyncEventData.frameTimelines[i].expectedPresentTime,
+                      preferredExpectedVSyncTimestamp)
+                    << "Preferred expected vsync timestamp incorrect" << i;
+        }
+    }
+}
+
 TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) {
     // Create a first connection, register it, and request a vsync rate of zero.
     ConnectionEventRecorder firstConnectionEventRecorder{0};
@@ -422,7 +470,7 @@
     // Send a vsync event. EventThread should then make a call to the
     // interceptor, and the second connection. The first connection should not
     // get the event.
-    mCallback->onVSyncEvent(123, 456, 0);
+    mCallback->onVSyncEvent(123, {456, 0});
     expectInterceptCallReceived(123);
     EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value());
     expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123,
@@ -437,19 +485,19 @@
 
     // Send a vsync event. EventThread should then make a call to the
     // interceptor, and the connection.
-    mCallback->onVSyncEvent(123, 456, 789);
+    mCallback->onVSyncEvent(123, {456, 789});
     expectInterceptCallReceived(123);
     expectThrottleVsyncReceived(456, mConnectionUid);
     expectVsyncEventReceivedByConnection(123, 1u);
 
     // A second event should go to the same places.
-    mCallback->onVSyncEvent(456, 123, 0);
+    mCallback->onVSyncEvent(456, {123, 0});
     expectInterceptCallReceived(456);
     expectThrottleVsyncReceived(123, mConnectionUid);
     expectVsyncEventReceivedByConnection(456, 2u);
 
     // A third event should go to the same places.
-    mCallback->onVSyncEvent(789, 777, 111);
+    mCallback->onVSyncEvent(789, {777, 111});
     expectInterceptCallReceived(789);
     expectThrottleVsyncReceived(777, mConnectionUid);
     expectVsyncEventReceivedByConnection(789, 3u);
@@ -462,25 +510,25 @@
     expectVSyncSetEnabledCallReceived(true);
 
     // The first event will be seen by the interceptor, and not the connection.
-    mCallback->onVSyncEvent(123, 456, 789);
+    mCallback->onVSyncEvent(123, {456, 789});
     expectInterceptCallReceived(123);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
     EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
 
     // The second event will be seen by the interceptor and the connection.
-    mCallback->onVSyncEvent(456, 123, 0);
+    mCallback->onVSyncEvent(456, {123, 0});
     expectInterceptCallReceived(456);
     expectVsyncEventReceivedByConnection(456, 2u);
     EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
 
     // The third event will be seen by the interceptor, and not the connection.
-    mCallback->onVSyncEvent(789, 777, 744);
+    mCallback->onVSyncEvent(789, {777, 744});
     expectInterceptCallReceived(789);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
     EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value());
 
     // The fourth event will be seen by the interceptor and the connection.
-    mCallback->onVSyncEvent(101112, 7847, 86);
+    mCallback->onVSyncEvent(101112, {7847, 86});
     expectInterceptCallReceived(101112);
     expectVsyncEventReceivedByConnection(101112, 4u);
 }
@@ -495,7 +543,7 @@
     mConnection = nullptr;
 
     // The first event will be seen by the interceptor, and not the connection.
-    mCallback->onVSyncEvent(123, 456, 789);
+    mCallback->onVSyncEvent(123, {456, 789});
     expectInterceptCallReceived(123);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
 
@@ -513,13 +561,13 @@
 
     // The first event will be seen by the interceptor, and by the connection,
     // which then returns an error.
-    mCallback->onVSyncEvent(123, 456, 789);
+    mCallback->onVSyncEvent(123, {456, 789});
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
 
     // A subsequent event will be seen by the interceptor and not by the
     // connection.
-    mCallback->onVSyncEvent(456, 123, 0);
+    mCallback->onVSyncEvent(456, {123, 0});
     expectInterceptCallReceived(456);
     EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value());
 
@@ -544,7 +592,7 @@
 
     // The first event will be seen by the interceptor, and by the connection,
     // which then returns an error.
-    mCallback->onVSyncEvent(123, 456, 789);
+    mCallback->onVSyncEvent(123, {456, 789});
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
     expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123,
@@ -562,13 +610,13 @@
 
     // The first event will be seen by the interceptor, and by the connection,
     // which then returns an non-fatal error.
-    mCallback->onVSyncEvent(123, 456, 789);
+    mCallback->onVSyncEvent(123, {456, 789});
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
 
     // A subsequent event will be seen by the interceptor, and by the connection,
     // which still then returns an non-fatal error.
-    mCallback->onVSyncEvent(456, 123, 0);
+    mCallback->onVSyncEvent(456, {123, 0});
     expectInterceptCallReceived(456);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u);
 
@@ -692,7 +740,7 @@
 
     // Use the received callback to signal a first vsync event.
     // The interceptor should receive the event, but not the connection.
-    mCallback->onVSyncEvent(123, 456, 789);
+    mCallback->onVSyncEvent(123, {456, 789});
     expectInterceptCallReceived(123);
     expectThrottleVsyncReceived(456, mThrottledConnectionUid);
     mThrottledConnectionEventCallRecorder.waitForUnexpectedCall();
@@ -700,7 +748,7 @@
     // Use the received callback to signal a second vsync event.
     // The interceptor should receive the event, but the connection should
     // not as it was only interested in the first.
-    mCallback->onVSyncEvent(456, 123, 0);
+    mCallback->onVSyncEvent(456, {123, 0});
     expectInterceptCallReceived(456);
     expectThrottleVsyncReceived(123, mThrottledConnectionUid);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
diff --git a/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp
new file mode 100644
index 0000000..a581c7a
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "FrameRateOverrideMappingsTest"
+
+#include <gtest/gtest.h>
+#include <unordered_map>
+
+#include "Scheduler/FrameRateOverrideMappings.h"
+
+namespace android::scheduler {
+
+using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
+using UidToFrameRateOverride = std::map<uid_t, Fps>;
+
+class FrameRateOverrideMappingsTest : public testing::Test {
+protected:
+    FrameRateOverrideMappings mFrameRateOverrideMappings;
+    UidToFrameRateOverride mFrameRateOverrideByContent;
+};
+
+namespace {
+TEST_F(FrameRateOverrideMappingsTest, testUpdateFrameRateOverridesByContent) {
+    mFrameRateOverrideByContent.clear();
+    mFrameRateOverrideByContent.emplace(0, 30.0_Hz);
+    mFrameRateOverrideByContent.emplace(1, 60.0_Hz);
+    ASSERT_TRUE(mFrameRateOverrideMappings.updateFrameRateOverridesByContent(
+            mFrameRateOverrideByContent));
+
+    ASSERT_TRUE(isApproxEqual(30.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      0, /*supportsFrameRateOverrideByContent*/ true)));
+    ASSERT_TRUE(isApproxEqual(60.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      1, /*supportsFrameRateOverrideByContent*/ true)));
+    ASSERT_EQ(std::nullopt,
+              mFrameRateOverrideMappings
+                      .getFrameRateOverrideForUid(1, /*supportsFrameRateOverrideByContent*/ false));
+    ASSERT_EQ(std::nullopt,
+              mFrameRateOverrideMappings
+                      .getFrameRateOverrideForUid(3, /*supportsFrameRateOverrideByContent*/ true));
+    ASSERT_EQ(std::nullopt,
+              mFrameRateOverrideMappings
+                      .getFrameRateOverrideForUid(3, /*supportsFrameRateOverrideByContent*/ false));
+}
+
+TEST_F(FrameRateOverrideMappingsTest, testSetGameModeRefreshRateForUid) {
+    mFrameRateOverrideMappings.setGameModeRefreshRateForUid({1, 30.0f});
+    mFrameRateOverrideMappings.setGameModeRefreshRateForUid({2, 90.0f});
+
+    ASSERT_TRUE(isApproxEqual(30.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      1, /*supportsFrameRateOverrideByContent*/ true)));
+    ASSERT_TRUE(isApproxEqual(90.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      2, /*supportsFrameRateOverrideByContent*/ false)));
+    ASSERT_EQ(std::nullopt,
+              mFrameRateOverrideMappings
+                      .getFrameRateOverrideForUid(0, /*supportsFrameRateOverrideByContent*/ true));
+    ASSERT_EQ(std::nullopt,
+              mFrameRateOverrideMappings
+                      .getFrameRateOverrideForUid(0, /*supportsFrameRateOverrideByContent*/ false));
+}
+
+TEST_F(FrameRateOverrideMappingsTest, testSetPreferredRefreshRateForUid) {
+    mFrameRateOverrideMappings.setPreferredRefreshRateForUid({0, 60.0f});
+    mFrameRateOverrideMappings.setPreferredRefreshRateForUid({2, 120.0f});
+
+    ASSERT_TRUE(isApproxEqual(60.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      0, /*supportsFrameRateOverrideByContent*/ true)));
+    ASSERT_TRUE(isApproxEqual(120.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      2, /*supportsFrameRateOverrideByContent*/ false)));
+    ASSERT_EQ(std::nullopt,
+              mFrameRateOverrideMappings
+                      .getFrameRateOverrideForUid(1, /*supportsFrameRateOverrideByContent*/ true));
+    ASSERT_EQ(std::nullopt,
+              mFrameRateOverrideMappings
+                      .getFrameRateOverrideForUid(1, /*supportsFrameRateOverrideByContent*/ false));
+}
+
+TEST_F(FrameRateOverrideMappingsTest, testGetFrameRateOverrideForUidMixed) {
+    mFrameRateOverrideByContent.clear();
+    mFrameRateOverrideByContent.emplace(0, 30.0_Hz);
+    mFrameRateOverrideByContent.emplace(1, 60.0_Hz);
+    mFrameRateOverrideByContent.emplace(2, 45.0_Hz);
+    mFrameRateOverrideByContent.emplace(5, 120.0_Hz);
+    ASSERT_TRUE(mFrameRateOverrideMappings.updateFrameRateOverridesByContent(
+            mFrameRateOverrideByContent));
+
+    std::vector<FrameRateOverride> allFrameRateOverrides;
+    ASSERT_EQ(allFrameRateOverrides,
+              mFrameRateOverrideMappings.getAllFrameRateOverrides(
+                      /*supportsFrameRateOverrideByContent*/ false));
+    allFrameRateOverrides = {{0, 30.0f}, {1, 60.0f}, {2, 45.0f}, {5, 120.0f}};
+    ASSERT_EQ(allFrameRateOverrides,
+              mFrameRateOverrideMappings.getAllFrameRateOverrides(
+                      /*supportsFrameRateOverrideByContent*/ true));
+
+    mFrameRateOverrideMappings.setGameModeRefreshRateForUid({1, 30.0f});
+    mFrameRateOverrideMappings.setGameModeRefreshRateForUid({2, 90.0f});
+    mFrameRateOverrideMappings.setGameModeRefreshRateForUid({4, 120.0f});
+
+    allFrameRateOverrides.clear();
+    allFrameRateOverrides = {{1, 30.0f}, {2, 90.0f}, {4, 120.0f}};
+    ASSERT_EQ(allFrameRateOverrides,
+              mFrameRateOverrideMappings.getAllFrameRateOverrides(
+                      /*supportsFrameRateOverrideByContent*/ false));
+    allFrameRateOverrides.clear();
+    allFrameRateOverrides = {{1, 30.0f}, {2, 90.0f}, {4, 120.0f}, {0, 30.0f}, {5, 120.0f}};
+    ASSERT_EQ(allFrameRateOverrides,
+              mFrameRateOverrideMappings.getAllFrameRateOverrides(
+                      /*supportsFrameRateOverrideByContent*/ true));
+
+    mFrameRateOverrideMappings.setPreferredRefreshRateForUid({0, 60.0f});
+    mFrameRateOverrideMappings.setPreferredRefreshRateForUid({2, 120.0f});
+    mFrameRateOverrideMappings.setPreferredRefreshRateForUid({3, 30.0f});
+
+    allFrameRateOverrides.clear();
+    allFrameRateOverrides = {{0, 60.0f}, {2, 120.0f}, {3, 30.0f}, {1, 30.0f}, {4, 120.0f}};
+    ASSERT_EQ(allFrameRateOverrides,
+              mFrameRateOverrideMappings.getAllFrameRateOverrides(
+                      /*supportsFrameRateOverrideByContent*/ false));
+    allFrameRateOverrides.clear();
+    allFrameRateOverrides = {{0, 60.0f}, {2, 120.0f}, {3, 30.0f},
+                             {1, 30.0f}, {4, 120.0f}, {5, 120.0f}};
+    ASSERT_EQ(allFrameRateOverrides,
+              mFrameRateOverrideMappings.getAllFrameRateOverrides(
+                      /*supportsFrameRateOverrideByContent*/ true));
+
+    ASSERT_TRUE(isApproxEqual(60.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      0, /*supportsFrameRateOverrideByContent*/ true)));
+    ASSERT_TRUE(isApproxEqual(30.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      1, /*supportsFrameRateOverrideByContent*/ true)));
+    ASSERT_TRUE(isApproxEqual(120.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      2, /*supportsFrameRateOverrideByContent*/ true)));
+    ASSERT_TRUE(isApproxEqual(30.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      3, /*supportsFrameRateOverrideByContent*/ true)));
+    ASSERT_TRUE(isApproxEqual(120.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      4, /*supportsFrameRateOverrideByContent*/ true)));
+    ASSERT_TRUE(isApproxEqual(120.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      5, /*supportsFrameRateOverrideByContent*/ true)));
+
+    ASSERT_TRUE(isApproxEqual(60.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      0, /*supportsFrameRateOverrideByContent*/ false)));
+    ASSERT_TRUE(isApproxEqual(30.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      1, /*supportsFrameRateOverrideByContent*/ false)));
+    ASSERT_TRUE(isApproxEqual(120.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      2, /*supportsFrameRateOverrideByContent*/ false)));
+    ASSERT_TRUE(isApproxEqual(30.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      3, /*supportsFrameRateOverrideByContent*/ false)));
+    ASSERT_TRUE(isApproxEqual(120.0_Hz,
+                              *mFrameRateOverrideMappings.getFrameRateOverrideForUid(
+                                      4, /*supportsFrameRateOverrideByContent*/ false)));
+    ASSERT_EQ(std::nullopt,
+              mFrameRateOverrideMappings
+                      .getFrameRateOverrideForUid(5, /*supportsFrameRateOverrideByContent*/ false));
+}
+} // namespace
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 0069441..5241604 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -48,6 +48,7 @@
 
 namespace V2_1 = hardware::graphics::composer::V2_1;
 namespace V2_4 = hardware::graphics::composer::V2_4;
+namespace aidl = aidl::android::hardware::graphics::composer3;
 
 using Hwc2::Config;
 
@@ -103,7 +104,7 @@
     const std::string kMetadata2Name = "com.example.metadata.2";
     constexpr bool kMetadata2Mandatory = true;
 
-    EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
+    EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<aidl::Capability>{}));
     EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
             .WillOnce(DoAll(SetArgPointee<0>(std::vector<hal::LayerGenericMetadataKey>{
                                     {kMetadata1Name, kMetadata1Mandatory},
@@ -124,7 +125,7 @@
 }
 
 TEST_F(HWComposerSetCallbackTest, handlesUnsupportedCallToGetLayerGenericMetadataKeys) {
-    EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
+    EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<aidl::Capability>{}));
     EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
             .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
     EXPECT_CALL(*mHal, registerCallback(_));
@@ -140,7 +141,7 @@
     static constexpr hal::HWDisplayId kDisplayId = static_cast<hal::HWDisplayId>(1001);
     static constexpr hal::HWLayerId kLayerId = static_cast<hal::HWLayerId>(1002);
 
-    HWComposerLayerTest(const std::unordered_set<hal::Capability>& capabilities)
+    HWComposerLayerTest(const std::unordered_set<aidl::Capability>& capabilities)
           : mCapabilies(capabilities) {
         EXPECT_CALL(mDisplay, getId()).WillRepeatedly(Return(kDisplayId));
     }
@@ -151,7 +152,7 @@
     }
 
     std::unique_ptr<Hwc2::mock::Composer> mHal{new StrictMock<Hwc2::mock::Composer>()};
-    const std::unordered_set<hal::Capability> mCapabilies;
+    const std::unordered_set<aidl::Capability> mCapabilies;
     StrictMock<HWC2::mock::Display> mDisplay;
     HWC2::impl::Layer mLayer{*mHal, mCapabilies, mDisplay, kLayerId};
 };
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 4fe1e98..8cadb31 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -526,9 +526,11 @@
      * preconditions and assert post-conditions.
      */
     struct HWC2Display : public HWC2::impl::Display {
-        HWC2Display(Hwc2::Composer& composer,
-                    const std::unordered_set<hal::Capability>& capabilities, hal::HWDisplayId id,
-                    hal::DisplayType type)
+        HWC2Display(
+                Hwc2::Composer& composer,
+                const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>&
+                        capabilities,
+                hal::HWDisplayId id, hal::DisplayType type)
               : HWC2::impl::Display(composer, capabilities, id, type) {}
         ~HWC2Display() {
             // Prevents a call to disable vsyncs.
@@ -589,7 +591,9 @@
             return *this;
         }
 
-        auto& setCapabilities(const std::unordered_set<hal::Capability>* capabilities) {
+        auto& setCapabilities(
+                const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>*
+                        capabilities) {
             mCapabilities = capabilities;
             return *this;
         }
@@ -605,7 +609,9 @@
             using ::testing::Return;
             using ::testing::SetArgPointee;
 
-            static const std::unordered_set<hal::Capability> defaultCapabilities;
+            static const std::unordered_set<
+                    aidl::android::hardware::graphics::composer3::Capability>
+                    defaultCapabilities;
             if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities;
 
             // Caution - Make sure that any values passed by reference here do
@@ -682,7 +688,8 @@
         int32_t mConfigGroup = DEFAULT_CONFIG_GROUP;
         hal::HWConfigId mActiveConfig = DEFAULT_ACTIVE_CONFIG;
         hal::PowerMode mPowerMode = DEFAULT_POWER_MODE;
-        const std::unordered_set<hal::Capability>* mCapabilities = nullptr;
+        const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>*
+                mCapabilities = nullptr;
     };
 
     class FakeDisplayDeviceInjector {
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index ed23176..4683c51 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -72,13 +72,6 @@
         EXPECT_CALL(*mVSyncTracker, currentPeriod())
                 .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
 
-        EXPECT_CALL(*mFenceUnsignaled, getStatus())
-                .WillRepeatedly(Return(Fence::Status::Unsignaled));
-        EXPECT_CALL(*mFenceUnsignaled2, getStatus())
-                .WillRepeatedly(Return(Fence::Status::Unsignaled));
-        EXPECT_CALL(*mFenceSignaled, getStatus()).WillRepeatedly(Return(Fence::Status::Signaled));
-        EXPECT_CALL(*mFenceSignaled2, getStatus()).WillRepeatedly(Return(Fence::Status::Signaled));
-
         mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
         mFlinger.setupScheduler(std::unique_ptr<mock::VsyncController>(mVsyncController),
                                 std::unique_ptr<mock::VSyncTracker>(mVSyncTracker),
@@ -89,10 +82,6 @@
 
     mock::VsyncController* mVsyncController = new mock::VsyncController();
     mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker();
-    sp<mock::MockFence> mFenceUnsignaled = sp<mock::MockFence>::make();
-    sp<mock::MockFence> mFenceSignaled = sp<mock::MockFence>::make();
-    sp<mock::MockFence> mFenceUnsignaled2 = sp<mock::MockFence>::make();
-    sp<mock::MockFence> mFenceSignaled2 = sp<mock::MockFence>::make();
 
     struct TransactionInfo {
         Vector<ComposerState> states;
@@ -129,15 +118,6 @@
         transaction.frameTimelineInfo = frameTimelineInfo;
     }
 
-    void setupSingleWithComposer(TransactionInfo& transaction, uint32_t flags,
-                                 bool syncInputWindows, int64_t desiredPresentTime,
-                                 bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo,
-                                 const Vector<ComposerState>* states) {
-        setupSingle(transaction, flags, syncInputWindows, desiredPresentTime, isAutoTimestamp,
-                    frameTimelineInfo);
-        transaction.states = *states;
-    }
-
     void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
         ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
         EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
@@ -263,189 +243,6 @@
         EXPECT_EQ(0u, transactionQueue.size());
     }
 
-    void Flush_removesUnsignaledFromTheQueue(Vector<ComposerState> state1,
-                                             Vector<ComposerState> state2,
-                                             bool updateApplyToken = true) {
-        ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
-
-        TransactionInfo transactionA;
-        setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous,
-                                /*syncInputWindows*/ false,
-                                /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
-                                FrameTimelineInfo{}, &state1);
-
-        mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
-                                     transactionA.displays, transactionA.flags,
-                                     transactionA.applyToken, transactionA.inputWindowCommands,
-                                     transactionA.desiredPresentTime, transactionA.isAutoTimestamp,
-                                     transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
-                                     transactionA.id);
-
-        TransactionInfo transactionB;
-        if (updateApplyToken) {
-            transactionB.applyToken = sp<IBinder>();
-        }
-        setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous,
-                                /*syncInputWindows*/ false,
-                                /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
-                                FrameTimelineInfo{}, &state2);
-        mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states,
-                                     transactionB.displays, transactionB.flags,
-                                     transactionB.applyToken, transactionB.inputWindowCommands,
-                                     transactionB.desiredPresentTime, transactionB.isAutoTimestamp,
-                                     transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
-                                     transactionB.id);
-
-        mFlinger.flushTransactionQueues();
-        EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
-        EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
-        EXPECT_EQ(2ul, mFlinger.getTransactionCommittedSignals().size());
-    }
-
-    void Flush_removesFromTheQueue(const Vector<ComposerState>& state) {
-        ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
-        EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
-
-        TransactionInfo transaction;
-        setupSingleWithComposer(transaction, ISurfaceComposer::eSynchronous,
-                                /*syncInputWindows*/ false,
-                                /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
-                                FrameTimelineInfo{}, &state);
-
-        mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
-                                     transaction.displays, transaction.flags,
-                                     transaction.applyToken, transaction.inputWindowCommands,
-                                     transaction.desiredPresentTime, transaction.isAutoTimestamp,
-                                     transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
-                                     transaction.id);
-
-        mFlinger.flushTransactionQueues();
-        EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
-        EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
-        EXPECT_EQ(1u, mFlinger.getTransactionCommittedSignals().size());
-    }
-
-    void Flush_keepsInTheQueue(const Vector<ComposerState>& state) {
-        ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
-        EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
-
-        TransactionInfo transaction;
-        setupSingleWithComposer(transaction, ISurfaceComposer::eSynchronous,
-                                /*syncInputWindows*/ false,
-                                /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
-                                FrameTimelineInfo{}, &state);
-
-        mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
-                                     transaction.displays, transaction.flags,
-                                     transaction.applyToken, transaction.inputWindowCommands,
-                                     transaction.desiredPresentTime, transaction.isAutoTimestamp,
-                                     transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
-                                     transaction.id);
-
-        mFlinger.flushTransactionQueues();
-        EXPECT_EQ(1u, mFlinger.getPendingTransactionQueue().size());
-        EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
-        EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size());
-    }
-
-    void Flush_KeepsUnsignaledInTheQueue(const Vector<ComposerState>& state1,
-                                         const Vector<ComposerState>& state2,
-                                         bool updateApplyToken = true,
-                                         uint32_t pendingTransactionQueueSize = 1u) {
-        EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
-        ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
-        auto time = systemTime();
-        TransactionInfo transactionA;
-        TransactionInfo transactionB;
-        setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous,
-                                /*syncInputWindows*/ false,
-                                /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true,
-                                FrameTimelineInfo{}, &state1);
-        setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous,
-                                /*syncInputWindows*/ false,
-                                /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true,
-                                FrameTimelineInfo{}, &state2);
-        mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
-                                     transactionA.displays, transactionA.flags,
-                                     transactionA.applyToken, transactionA.inputWindowCommands,
-                                     transactionA.desiredPresentTime, transactionA.isAutoTimestamp,
-                                     transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
-                                     transactionA.id);
-        if (updateApplyToken) {
-            transactionB.applyToken = sp<IBinder>();
-        }
-        mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states,
-                                     transactionB.displays, transactionB.flags,
-                                     transactionB.applyToken, transactionB.inputWindowCommands,
-                                     transactionB.desiredPresentTime, transactionB.isAutoTimestamp,
-                                     transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
-                                     transactionB.id);
-
-        mFlinger.flushTransactionQueues();
-        EXPECT_EQ(pendingTransactionQueueSize, mFlinger.getPendingTransactionQueue().size());
-        EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
-    }
-
-    void Flush_removesSignaledFromTheQueue(const Vector<ComposerState>& state1,
-                                           const Vector<ComposerState>& state2) {
-        ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
-        EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
-
-        auto time = systemTime();
-        TransactionInfo transactionA;
-        TransactionInfo transactionB;
-        setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous,
-                                /*syncInputWindows*/ false,
-                                /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true,
-                                FrameTimelineInfo{}, &state1);
-        setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous,
-                                /*syncInputWindows*/ false,
-                                /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true,
-                                FrameTimelineInfo{}, &state2);
-        mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
-                                     transactionA.displays, transactionA.flags,
-                                     transactionA.applyToken, transactionA.inputWindowCommands,
-                                     transactionA.desiredPresentTime, transactionA.isAutoTimestamp,
-                                     transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
-                                     transactionA.id);
-        mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states,
-                                     transactionB.displays, transactionB.flags,
-                                     transactionB.applyToken, transactionB.inputWindowCommands,
-                                     transactionB.desiredPresentTime, transactionB.isAutoTimestamp,
-                                     transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
-                                     transactionB.id);
-
-        mFlinger.flushTransactionQueues();
-        EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
-        EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
-        EXPECT_EQ(2ul, mFlinger.getTransactionCommittedSignals().size());
-    }
-
-    static Vector<ComposerState> createComposerStateVector(const ComposerState& state1,
-                                                           const ComposerState& state2) {
-        Vector<ComposerState> states;
-        states.push_back(state1);
-        states.push_back(state2);
-        return states;
-    }
-
-    static Vector<ComposerState> createComposerStateVector(const ComposerState& state) {
-        Vector<ComposerState> states;
-        states.push_back(state);
-        return states;
-    }
-
-    static ComposerState createComposerState(int layerId, sp<Fence> fence,
-                                             uint32_t stateFlags = layer_state_t::eBufferChanged) {
-        ComposerState composer_state;
-        composer_state.state.bufferData = std::make_shared<BufferData>();
-        composer_state.state.bufferData->acquireFence = std::move(fence);
-        composer_state.state.layerId = layerId;
-        composer_state.state.bufferData->flags = BufferData::BufferDataChange::fenceChanged;
-        composer_state.state.flags = stateFlags;
-        return composer_state;
-    }
-
     bool mHasListenerCallbacks = false;
     std::vector<ListenerCallbacks> mCallbacks;
     int mTransactionNumber = 0;
@@ -529,215 +326,677 @@
     EXPECT_EQ(nullptr, ret.promote().get());
 }
 
-TEST_F(TransactionApplicationTest, Flush_RemovesSingleSignaledFromTheQueue_LatchUnsignaled_Auto) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
-    Flush_removesFromTheQueue(
-            createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled)));
+class LatchUnsignaledTest : public TransactionApplicationTest {
+public:
+    void TearDown() override {
+        // Clear all transaction queues to release all transactions we sent
+        // in the tests. Otherwise, gmock complains about memory leaks.
+        mFlinger.getTransactionQueue().clear();
+        mFlinger.getPendingTransactionQueue().clear();
+        mFlinger.getTransactionCommittedSignals().clear();
+        mFlinger.commitTransactionsLocked(eTransactionMask);
+        mFlinger.mutableCurrentState().layersSortedByZ.clear();
+        mFlinger.mutableDrawingState().layersSortedByZ.clear();
+    }
+
+    static sp<Fence> fence(Fence::Status status) {
+        const auto fence = sp<mock::MockFence>::make();
+        EXPECT_CALL(*fence, getStatus()).WillRepeatedly(Return(status));
+        return fence;
+    }
+
+    ComposerState createComposerState(int layerId, sp<Fence> fence, uint64_t what) {
+        ComposerState state;
+        state.state.bufferData = std::make_shared<BufferData>();
+        state.state.bufferData->acquireFence = std::move(fence);
+        state.state.layerId = layerId;
+        state.state.surface =
+                sp<BufferStateLayer>::make(
+                        LayerCreationArgs(mFlinger.flinger(), nullptr, "TestLayer", 0, {}))
+                        ->getHandle();
+        state.state.bufferData->flags = BufferData::BufferDataChange::fenceChanged;
+
+        state.state.what = what;
+        if (what & layer_state_t::eCropChanged) {
+            state.state.crop = Rect(1, 2, 3, 4);
+        }
+        return state;
+    }
+
+    TransactionInfo createTransactionInfo(const sp<IBinder>& applyToken,
+                                          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);
+        transaction.applyToken = applyToken;
+        for (const auto& state : states) {
+            transaction.states.push_back(state);
+        }
+
+        return transaction;
+    }
+
+    void setTransactionStates(const std::vector<TransactionInfo>& transactions,
+                              size_t expectedTransactionsApplied,
+                              size_t expectedTransactionsPending) {
+        EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
+        EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
+
+        for (const auto& transaction : transactions) {
+            mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
+                                         transaction.displays, transaction.flags,
+                                         transaction.applyToken, transaction.inputWindowCommands,
+                                         transaction.desiredPresentTime,
+                                         transaction.isAutoTimestamp, transaction.uncacheBuffer,
+                                         mHasListenerCallbacks, mCallbacks, transaction.id);
+        }
+        mFlinger.flushTransactionQueues();
+        EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
+        EXPECT_EQ(expectedTransactionsPending, mFlinger.getPendingTransactionQueue().size());
+        EXPECT_EQ(expectedTransactionsApplied, mFlinger.getTransactionCommittedSignals().size());
+    }
+};
+
+class LatchUnsignaledAutoSingleLayerTest : public LatchUnsignaledTest {
+public:
+    void SetUp() override {
+        LatchUnsignaledTest::SetUp();
+        SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::AutoSingleLayer;
+    }
+};
+
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSingleSignaledFromTheQueue) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId = 1;
+    const auto kExpectedTransactionsApplied = 1u;
+    const auto kExpectedTransactionsPending = 0u;
+
+    const auto signaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {createComposerState(kLayerId, fence(Fence::Status::Signaled),
+                                                       layer_state_t::eBufferChanged)});
+    setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_RemovesSingleUnSignaledFromTheQueue_LatchUnsignaled_Auto) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
-    Flush_removesFromTheQueue(
-            createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled)));
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSingleUnSignaledFromTheQueue) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId = 1;
+    const auto kExpectedTransactionsApplied = 1u;
+    const auto kExpectedTransactionsPending = 0u;
+
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest,
-       Flush_KeepsUnSignaledInTheQueue_NonBufferCropChange_LatchUnsignaled_Auto) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
-    Flush_keepsInTheQueue(createComposerStateVector(
-            createComposerState(/*layerId*/ 1, mFenceUnsignaled, layer_state_t::eCropChanged)));
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_NonBufferCropChange) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId = 1;
+    const auto kExpectedTransactionsApplied = 0u;
+    const auto kExpectedTransactionsPending = 1u;
+
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eCropChanged),
+                                  });
+    setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest,
-       Flush_KeepsUnSignaledInTheQueue_NonBufferChangeClubed_LatchUnsignaled_Auto) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
-    Flush_keepsInTheQueue(createComposerStateVector(
-            createComposerState(/*layerId*/ 1, mFenceUnsignaled,
-                                layer_state_t::eCropChanged | layer_state_t::eBufferChanged)));
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_NonBufferChangeClubed) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId = 1;
+    const auto kExpectedTransactionsApplied = 0u;
+    const auto kExpectedTransactionsPending = 1u;
+
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eCropChanged |
+                                                                      layer_state_t::
+                                                                              eBufferChanged),
+                                  });
+    setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest,
-       Flush_KeepsInTheQueueSameApplyTokenMultiState_LatchUnsignaled_Auto) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
-    Flush_keepsInTheQueue(
-            createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
-                                      createComposerState(/*layerId*/ 1, mFenceSignaled)));
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsInTheQueueSameApplyTokenMultiState) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId = 1;
+    const auto kExpectedTransactionsApplied = 0u;
+    const auto kExpectedTransactionsPending = 1u;
+
+    const auto mixedTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                          createComposerState(kLayerId,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueue_MultipleStateTransaction_Auto) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
-    Flush_keepsInTheQueue(
-            createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
-                                      createComposerState(/*layerId*/ 2, mFenceSignaled)));
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsInTheQueue_MultipleStateTransaction) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 0u;
+    const auto kExpectedTransactionsPending = 1u;
+
+    const auto mixedTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Auto) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
-    Flush_removesSignaledFromTheQueue(createComposerStateVector(
-                                              createComposerState(/*layerId*/ 1, mFenceSignaled)),
-                                      createComposerStateVector(
-                                              createComposerState(/*layerId*/ 2, mFenceSignaled2)));
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSignaledFromTheQueue) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 2u;
+    const auto kExpectedTransactionsPending = 0u;
+
+    const auto signaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    const auto signaledTransaction2 =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_RemoveSignaledWithUnsignaledIntact_LatchUnsignaled_Auto) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
-    Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
-                                            createComposerState(/*layerId*/ 1, mFenceSignaled)),
-                                    createComposerStateVector(
-                                            createComposerState(/*layerId*/ 2, mFenceUnsignaled)));
-    EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size());
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemoveSignaledWithUnsignaledIntact) {
+    const sp<IBinder> kApplyToken1 =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 1u;
+    const auto kExpectedTransactionsPending = 1u;
+
+    const auto signaledTransaction =
+            createTransactionInfo(kApplyToken1,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken2,
+                                  {
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest,
-       Flush_KeepsTransactionInTheQueueSameApplyToken_LatchUnsignaled_Auto) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
-    Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
-                                            createComposerState(/*layerId*/ 1, mFenceUnsignaled)),
-                                    createComposerStateVector(
-                                            createComposerState(/*layerId*/ 2, mFenceSignaled)),
-                                    /*updateApplyToken*/ false);
-    EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size());
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueueSameApplyToken) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 1u;
+    const auto kExpectedTransactionsPending = 1u;
+
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    const auto signaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_KeepsTransactionInTheQueue_LatchUnsignaled_Auto) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto;
-    Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
-                                            createComposerState(/*layerId*/ 1, mFenceUnsignaled)),
-                                    createComposerStateVector(
-                                            createComposerState(/*layerId*/ 2, mFenceUnsignaled)),
-                                    /*updateApplyToken*/ true,
-                                    /*pendingTransactionQueueSize*/ 2u);
-    EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size());
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueue) {
+    const sp<IBinder> kApplyToken1 =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 1u;
+    const auto kExpectedTransactionsPending = 1u;
+
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken1,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    const auto unsignaledTransaction2 =
+            createTransactionInfo(kApplyToken2,
+                                  {
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({unsignaledTransaction, unsignaledTransaction2},
+                         kExpectedTransactionsApplied, kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Disabled) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
-    Flush_removesFromTheQueue(
-            createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled)));
+class LatchUnsignaledDisabledTest : public LatchUnsignaledTest {
+public:
+    void SetUp() override {
+        LatchUnsignaledTest::SetUp();
+        SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
+    }
+};
+
+TEST_F(LatchUnsignaledDisabledTest, Flush_RemovesSignaledFromTheQueue) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId = 1;
+    const auto kExpectedTransactionsApplied = 1u;
+    const auto kExpectedTransactionsPending = 0u;
+
+    const auto signaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {createComposerState(kLayerId, fence(Fence::Status::Signaled),
+                                                       layer_state_t::eBufferChanged)});
+    setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueue_LatchUnsignaled_Disabled) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
-    Flush_keepsInTheQueue(
-            createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled)));
+TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueue) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId = 1;
+    const auto kExpectedTransactionsApplied = 0u;
+    const auto kExpectedTransactionsPending = 1u;
+
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueueSameLayerId_LatchUnsignaled_Disabled) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
-    Flush_keepsInTheQueue(
-            createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
-                                      createComposerState(/*layerId*/ 1, mFenceUnsignaled)));
+TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueueSameLayerId) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId = 1;
+    const auto kExpectedTransactionsApplied = 0u;
+    const auto kExpectedTransactionsPending = 1u;
+
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                          createComposerState(kLayerId,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueueDifferentLayerId_LatchUnsignaled_Disabled) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
-    Flush_keepsInTheQueue(
-            createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
-                                      createComposerState(/*layerId*/ 2, mFenceUnsignaled)));
+TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueueDifferentLayerId) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 0u;
+    const auto kExpectedTransactionsPending = 1u;
+
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnSignaled_Disabled) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
-    Flush_removesSignaledFromTheQueue(createComposerStateVector(
-                                              createComposerState(/*layerId*/ 1, mFenceSignaled)),
-                                      createComposerStateVector(
-                                              createComposerState(/*layerId*/ 2, mFenceSignaled2)));
+TEST_F(LatchUnsignaledDisabledTest, Flush_RemovesSignaledFromTheQueue_MultipleLayers) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 2u;
+    const auto kExpectedTransactionsPending = 0u;
+
+    const auto signaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    const auto signaledTransaction2 =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest,
-       Flush_KeepInTheQueueDifferentApplyToken_LatchUnsignaled_Disabled) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
-    Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
-                                            createComposerState(/*layerId*/ 1, mFenceUnsignaled)),
-                                    createComposerStateVector(
-                                            createComposerState(/*layerId*/ 2, mFenceSignaled)));
-    EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size());
+TEST_F(LatchUnsignaledDisabledTest, Flush_KeepInTheQueueDifferentApplyToken) {
+    const sp<IBinder> kApplyToken1 =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 1u;
+    const auto kExpectedTransactionsPending = 1u;
+
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken1,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    const auto signaledTransaction =
+            createTransactionInfo(kApplyToken2,
+                                  {
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_KeepInTheQueueSameApplyToken_LatchUnsignaled_Disabled) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
-    Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
-                                            createComposerState(/*layerId*/ 1, mFenceSignaled)),
-                                    createComposerStateVector(
-                                            createComposerState(/*layerId*/ 2, mFenceUnsignaled)),
-                                    /*updateApplyToken*/ false);
-    EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size());
+TEST_F(LatchUnsignaledDisabledTest, Flush_KeepInTheQueueSameApplyToken) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 1u;
+    const auto kExpectedTransactionsPending = 1u;
+
+    const auto signaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_KeepInTheUnsignaledTheQueue_LatchUnsignaled_Disabled) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled;
-    Flush_KeepsUnsignaledInTheQueue(createComposerStateVector(
-                                            createComposerState(/*layerId*/ 1, mFenceUnsignaled)),
-                                    createComposerStateVector(
-                                            createComposerState(/*layerId*/ 2, mFenceUnsignaled)),
-                                    /*updateApplyToken*/ false);
-    EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size());
+TEST_F(LatchUnsignaledDisabledTest, Flush_KeepInTheUnsignaledTheQueue) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 0u;
+    const auto kExpectedTransactionsPending = 1u;
+
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    const auto unsignaledTransaction2 =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({unsignaledTransaction, unsignaledTransaction2},
+                         kExpectedTransactionsApplied, kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Always) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
-    Flush_removesFromTheQueue(
-            createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled)));
+class LatchUnsignaledAlwaysTest : public LatchUnsignaledTest {
+public:
+    void SetUp() override {
+        LatchUnsignaledTest::SetUp();
+        SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
+    }
+};
+
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesSignaledFromTheQueue) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId = 1;
+    const auto kExpectedTransactionsApplied = 1u;
+    const auto kExpectedTransactionsPending = 0u;
+
+    const auto signaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {createComposerState(kLayerId, fence(Fence::Status::Signaled),
+                                                       layer_state_t::eBufferChanged)});
+    setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_RemovesFromTheQueue_LatchUnsignaled_Always) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
-    Flush_removesFromTheQueue(
-            createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled)));
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueue) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId = 1;
+    const auto kExpectedTransactionsApplied = 1u;
+    const auto kExpectedTransactionsPending = 0u;
+
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {createComposerState(kLayerId, fence(Fence::Status::Unsignaled),
+                                                       layer_state_t::eBufferChanged)});
+    setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_RemovesFromTheQueueSameLayerId_LatchUnsignaled_Always) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
-    Flush_removesFromTheQueue(
-            createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
-                                      createComposerState(/*layerId*/ 1, mFenceSignaled)));
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueSameLayerId) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId = 1;
+    const auto kExpectedTransactionsApplied = 1u;
+    const auto kExpectedTransactionsPending = 0u;
+
+    const auto mixedTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {createComposerState(kLayerId, fence(Fence::Status::Unsignaled),
+                                                       layer_state_t::eBufferChanged),
+                                   createComposerState(kLayerId, fence(Fence::Status::Signaled),
+                                                       layer_state_t::eBufferChanged)});
+    setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest,
-       Flush_RemovesFromTheQueueDifferentLayerId_LatchUnsignaled_Always) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
-    Flush_removesFromTheQueue(
-            createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled),
-                                      createComposerState(/*layerId*/ 2, mFenceSignaled)));
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueDifferentLayerId) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 1u;
+    const auto kExpectedTransactionsPending = 0u;
+
+    const auto mixedTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {createComposerState(kLayerId1, fence(Fence::Status::Unsignaled),
+                                                       layer_state_t::eBufferChanged),
+                                   createComposerState(kLayerId2, fence(Fence::Status::Signaled),
+                                                       layer_state_t::eBufferChanged)});
+    setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnSignaled_Always) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
-    Flush_removesSignaledFromTheQueue(createComposerStateVector(
-                                              createComposerState(/*layerId*/ 1, mFenceSignaled)),
-                                      createComposerStateVector(
-                                              createComposerState(/*layerId*/ 2, mFenceSignaled2)));
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesSignaledFromTheQueue_MultipleLayers) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 2u;
+    const auto kExpectedTransactionsPending = 0u;
+
+    const auto signaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    const auto signaledTransaction2 =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest,
-       Flush_RemovesFromTheQueueDifferentApplyToken_LatchUnsignaled_Always) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
-    Flush_removesUnsignaledFromTheQueue(createComposerStateVector(
-                                                createComposerState(/*layerId*/ 1, mFenceSignaled)),
-                                        createComposerStateVector(
-                                                createComposerState(/*layerId*/ 2,
-                                                                    mFenceUnsignaled)));
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueDifferentApplyToken) {
+    const sp<IBinder> kApplyToken1 =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 2u;
+    const auto kExpectedTransactionsPending = 0u;
+
+    const auto signaledTransaction =
+            createTransactionInfo(kApplyToken1,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken2,
+                                  {
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest,
-       Flush_RemovesUnsignaledFromTheQueueSameApplyToken_LatchUnsignaled_Always) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
-    Flush_removesUnsignaledFromTheQueue(createComposerStateVector(
-                                                createComposerState(/*layerId*/ 1,
-                                                                    mFenceUnsignaled)),
-                                        createComposerStateVector(
-                                                createComposerState(/*layerId*/ 2, mFenceSignaled)),
-                                        /*updateApplyToken*/ false);
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesUnsignaledFromTheQueueSameApplyToken) {
+    const sp<IBinder> kApplyToken =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 2u;
+    const auto kExpectedTransactionsPending = 0u;
+
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    const auto signaledTransaction =
+            createTransactionInfo(kApplyToken,
+                                  {
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
 }
 
-TEST_F(TransactionApplicationTest, Flush_RemovesUnsignaledFromTheQueue_LatchUnsignaled_Always) {
-    SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always;
-    Flush_removesUnsignaledFromTheQueue(createComposerStateVector(
-                                                createComposerState(/*layerId*/ 1,
-                                                                    mFenceUnsignaled)),
-                                        createComposerStateVector(
-                                                createComposerState(/*layerId*/ 2,
-                                                                    mFenceUnsignaled)));
+TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesUnsignaledFromTheQueue) {
+    const sp<IBinder> kApplyToken1 =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 2u;
+    const auto kExpectedTransactionsPending = 0u;
+
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken1,
+                                  {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    const auto unsignaledTransaction2 =
+            createTransactionInfo(kApplyToken2,
+                                  {
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Unsignaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    setTransactionStates({unsignaledTransaction, unsignaledTransaction2},
+                         kExpectedTransactionsApplied, kExpectedTransactionsPending);
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index 271b1c0..ab893a3 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -70,23 +70,32 @@
         t1.displays.add(display);
     }
 
-    TransactionProtoParser::LayerHandleToIdFn getLayerIdFn = [&](const sp<IBinder>& handle) {
-        return (handle == layerHandle) ? 42 : -1;
-    };
-    TransactionProtoParser::DisplayHandleToIdFn getDisplayIdFn = [&](const sp<IBinder>& handle) {
-        return (handle == displayHandle) ? 43 : -1;
-    };
-    TransactionProtoParser::LayerIdToHandleFn getLayerHandleFn = [&](int32_t id) {
-        return (id == 42) ? layerHandle : nullptr;
-    };
-    TransactionProtoParser::DisplayIdToHandleFn getDisplayHandleFn = [&](int32_t id) {
-        return (id == 43) ? displayHandle : nullptr;
+    class TestMapper : public TransactionProtoParser::FlingerDataMapper {
+    public:
+        sp<IBinder> layerHandle;
+        sp<IBinder> displayHandle;
+
+        TestMapper(sp<IBinder> layerHandle, sp<IBinder> displayHandle)
+              : layerHandle(layerHandle), displayHandle(displayHandle) {}
+
+        sp<IBinder> getLayerHandle(int32_t id) const override {
+            return (id == 42) ? layerHandle : nullptr;
+        }
+        int32_t getLayerId(const sp<IBinder>& handle) const override {
+            return (handle == layerHandle) ? 42 : -1;
+        }
+        sp<IBinder> getDisplayHandle(int32_t id) const {
+            return (id == 43) ? displayHandle : nullptr;
+        }
+        int32_t getDisplayId(const sp<IBinder>& handle) const {
+            return (handle == displayHandle) ? 43 : -1;
+        }
     };
 
-    proto::TransactionState proto =
-            TransactionProtoParser::toProto(t1, getLayerIdFn, getDisplayIdFn);
-    TransactionState t2 =
-            TransactionProtoParser::fromProto(proto, getLayerHandleFn, getDisplayHandleFn);
+    TransactionProtoParser parser(std::make_unique<TestMapper>(layerHandle, displayHandle));
+
+    proto::TransactionState proto = parser.toProto(t1);
+    TransactionState t2 = parser.fromProto(proto);
 
     ASSERT_EQ(t1.originPid, t2.originPid);
     ASSERT_EQ(t1.originUid, t2.originUid);
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index 39dbb07..61b72a0 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -178,8 +178,8 @@
     // verify we can still retrieve the layer change from the first entry containing starting
     // states.
     EXPECT_GT(proto.entry().size(), 0);
-    EXPECT_GT(proto.entry(0).transactions().size(), 0);
-    EXPECT_GT(proto.entry(0).added_layers().size(), 0);
+    EXPECT_EQ(proto.entry(0).transactions().size(), 1);
+    EXPECT_EQ(proto.entry(0).added_layers().size(), 2);
     EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 2);
     EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
     EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 42);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 0765d5b..a1aa7e8 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -43,6 +43,8 @@
 using android::hardware::graphics::composer::V2_4::IComposerCallback;
 using android::hardware::graphics::composer::V2_4::IComposerClient;
 
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
+
 class Composer : public Hwc2::Composer {
 public:
     using Display = android::hardware::graphics::composer::V2_1::Display;
@@ -50,7 +52,8 @@
     ~Composer() override;
 
     MOCK_METHOD(bool, isSupported, (OptionalFeature), (const, override));
-    MOCK_METHOD0(getCapabilities, std::vector<IComposer::Capability>());
+    MOCK_METHOD0(getCapabilities,
+                 std::vector<aidl::android::hardware::graphics::composer3::Capability>());
     MOCK_METHOD0(dumpDebugInfo, std::string());
     MOCK_METHOD1(registerCallback, void(HWC2::ComposerCallback&));
     MOCK_METHOD0(resetCommands, void());
@@ -149,9 +152,11 @@
                  V2_4::Error(std::vector<IComposerClient::LayerGenericMetadataKey>*));
     MOCK_METHOD3(getClientTargetProperty,
                  Error(Display, IComposerClient::ClientTargetProperty*, float*));
-    MOCK_METHOD3(setLayerWhitePointNits, Error(Display, Layer, float));
+    MOCK_METHOD3(setLayerBrightness, Error(Display, Layer, float));
     MOCK_METHOD3(setLayerBlockingRegion,
                  Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
+    MOCK_METHOD2(getDisplayDecorationSupport,
+                 Error(Display, std::optional<DisplayDecorationSupport>*));
 };
 
 } // namespace Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 9015944..570ffeb 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -95,6 +95,10 @@
     MOCK_METHOD(hal::Error, setContentType, (hal::ContentType), (override));
     MOCK_METHOD(hal::Error, getClientTargetProperty, (hal::ClientTargetProperty *, float *),
                 (override));
+    MOCK_METHOD(
+            hal::Error, getDisplayDecorationSupport,
+            (std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport> *),
+            (override));
 };
 
 class Layer : public HWC2::Layer {
@@ -127,7 +131,7 @@
     MOCK_METHOD(hal::Error, setColorTransform, (const android::mat4 &), (override));
     MOCK_METHOD(hal::Error, setLayerGenericMetadata,
                 (const std::string &, bool, const std::vector<uint8_t> &), (override));
-    MOCK_METHOD(hal::Error, setWhitePointNits, (float whitePointNits), (override));
+    MOCK_METHOD(hal::Error, setBrightness, (float), (override));
     MOCK_METHOD(hal::Error, setBlockingRegion, (const android::Region &), (override));
 };
 
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index d25973e..c5ca86a 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -44,6 +44,8 @@
                  status_t(const sp<android::EventThreadConnection> &));
     MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
     MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
+    MOCK_METHOD(VsyncEventData, getLatestVsyncEventData,
+                (const sp<android::EventThreadConnection> &), (const));
     MOCK_METHOD1(requestLatestConfig, void(const sp<android::EventThreadConnection> &));
     MOCK_METHOD1(pauseVsyncCallback, void(bool));
     MOCK_METHOD0(getEventThreadConnectionCount, size_t());