Merge "Map the hwc-id -> SF-id in getPreferredBootDisplayMode and SF-Id -> HWC id in setUserPreferredDisplayMode"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index bb1d206..08a3d9a 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -246,7 +246,7 @@
         { OPT,      "events/gpu_mem/gpu_mem_total/enable" },
         { OPT,      "events/fastrpc/fastrpc_dma_stat/enable" },
     } },
-    { "thermal",  "Thermal event", 0, {
+    { "thermal",  "Thermal event", ATRACE_TAG_THERMAL, {
         { REQ,      "events/thermal/thermal_temperature/enable" },
         { OPT,      "events/thermal/cdev_update/enable" },
     } },
diff --git a/cmds/dumpstate/DumpPool.cpp b/cmds/dumpstate/DumpPool.cpp
index c2c8a72..4d3a67b 100644
--- a/cmds/dumpstate/DumpPool.cpp
+++ b/cmds/dumpstate/DumpPool.cpp
@@ -33,6 +33,20 @@
 
 const std::string DumpPool::PREFIX_TMPFILE_NAME = "dump-tmp.";
 
+
+void WaitForTask(std::future<std::string> future, const std::string& title, int out_fd) {
+    DurationReporter duration_reporter("Wait for " + title, true);
+
+    std::string result = future.get();
+    if (result.empty()) {
+        return;
+    }
+    DumpFileToFd(out_fd, title, result);
+    if (unlink(result.c_str())) {
+        MYLOGE("Failed to unlink (%s): %s\n", result.c_str(), strerror(errno));
+    }
+}
+
 DumpPool::DumpPool(const std::string& tmp_root) : tmp_root_(tmp_root), shutdown_(false),
         log_duration_(true) {
     assert(!tmp_root.empty());
@@ -40,31 +54,10 @@
 }
 
 DumpPool::~DumpPool() {
-    shutdown();
-}
-
-void DumpPool::start(int thread_counts) {
-    assert(thread_counts > 0);
-    assert(threads_.empty());
-    if (thread_counts > MAX_THREAD_COUNT) {
-        thread_counts = MAX_THREAD_COUNT;
-    }
-    MYLOGI("Start thread pool:%d", thread_counts);
-    shutdown_ = false;
-    for (int i = 0; i < thread_counts; i++) {
-        threads_.emplace_back(std::thread([=]() {
-            setThreadName(pthread_self(), i + 1);
-            loop();
-        }));
-    }
-}
-
-void DumpPool::shutdown() {
     std::unique_lock lock(lock_);
     if (shutdown_ || threads_.empty()) {
         return;
     }
-    futures_map_.clear();
     while (!tasks_.empty()) tasks_.pop();
 
     shutdown_ = true;
@@ -76,27 +69,22 @@
     }
     threads_.clear();
     deleteTempFiles(tmp_root_);
-    MYLOGI("shutdown thread pool");
+    MYLOGI("shutdown thread pool\n");
 }
 
-void DumpPool::waitForTask(const std::string& task_name, const std::string& title,
-        int out_fd) {
-    DurationReporter duration_reporter("Wait for " + task_name, true);
-    auto iterator = futures_map_.find(task_name);
-    if (iterator == futures_map_.end()) {
-        MYLOGW("Task %s does not exist", task_name.c_str());
-        return;
+void DumpPool::start(int thread_counts) {
+    assert(thread_counts > 0);
+    assert(threads_.empty());
+    if (thread_counts > MAX_THREAD_COUNT) {
+        thread_counts = MAX_THREAD_COUNT;
     }
-    Future future = iterator->second;
-    futures_map_.erase(iterator);
-
-    std::string result = future.get();
-    if (result.empty()) {
-        return;
-    }
-    DumpFileToFd(out_fd, title, result);
-    if (unlink(result.c_str())) {
-        MYLOGE("Failed to unlink (%s): %s\n", result.c_str(), strerror(errno));
+    MYLOGI("Start thread pool:%d\n", thread_counts);
+    shutdown_ = false;
+    for (int i = 0; i < thread_counts; i++) {
+        threads_.emplace_back(std::thread([=]() {
+            setThreadName(pthread_self(), i + 1);
+            loop();
+        }));
     }
 }
 
diff --git a/cmds/dumpstate/DumpPool.h b/cmds/dumpstate/DumpPool.h
index 0c3c2cc..9fb0fcc 100644
--- a/cmds/dumpstate/DumpPool.h
+++ b/cmds/dumpstate/DumpPool.h
@@ -18,7 +18,6 @@
 #define FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
 
 #include <future>
-#include <map>
 #include <queue>
 #include <string>
 
@@ -32,8 +31,26 @@
 class DumpPoolTest;
 
 /*
+ * Waits until the task is finished. Dumps the task results to the specified
+ * out_fd.
+ *
+ * |future| The task future.
+ * |title| Dump title string to the out_fd, an empty string for nothing.
+ * |out_fd| The target file to dump the result from the task.
+ */
+void WaitForTask(std::future<std::string> future, const std::string& title, int out_fd);
+
+/*
+ * Waits until the task is finished. Dumps the task results to the STDOUT_FILENO.
+ */
+
+inline void WaitForTask(std::future<std::string> future) {
+    WaitForTask(std::move(future), "", STDOUT_FILENO);
+}
+
+/*
  * A thread pool with the fixed number of threads to execute multiple dump tasks
- * simultaneously for the dumpstate. The dump task is a callable function. It
+ * simultaneously for dumpstate. The dump task is a callable function. It
  * could include a file descriptor as a parameter to redirect dump results, if
  * it needs to output results to the bugreport. This can avoid messing up
  * bugreport's results when multiple dump tasks are running at the same time.
@@ -44,13 +61,16 @@
  * }
  * ...
  * DumpPool pool(tmp_root);
- * pool.enqueueTaskWithFd("TaskName", &DumpFoo, std::placeholders::_1);
+ * auto task = pool.enqueueTaskWithFd("TaskName", &DumpFoo, std::placeholders::_1);
  * ...
- * pool.waitForTask("TaskName");
+ * WaitForTask(task);
  *
  * DumpFoo is a callable function included a out_fd parameter. Using the
  * enqueueTaskWithFd method in DumpPool to enqueue the task to the pool. The
  * std::placeholders::_1 is a placeholder for DumpPool to pass a fd argument.
+ *
+ * std::futures returned by `enqueueTask*()` must all have their `get` methods
+ * called, or have been destroyed before the DumpPool itself is destroyed.
  */
 class DumpPool {
   friend class android::os::dumpstate::DumpPoolTest;
@@ -63,6 +83,12 @@
      * files.
      */
     explicit DumpPool(const std::string& tmp_root);
+
+    /*
+     * Will waits until all threads exit the loop. Destroying DumpPool before destroying the
+     * associated std::futures created by `enqueueTask*` will cause an abort on Android because
+     * Android is built with `-fno-exceptions`.
+     */
     ~DumpPool();
 
     /*
@@ -73,68 +99,47 @@
     void start(int thread_counts = MAX_THREAD_COUNT);
 
     /*
-     * Requests to shutdown the pool and waits until all threads exit the loop.
-     */
-    void shutdown();
-
-    /*
      * Adds a task into the queue of the thread pool.
      *
-     * |task_name| The name of the task. It's also the title of the
+     * |duration_title| The name of the task. It's also the title of the
      * DurationReporter log.
      * |f| Callable function to execute the task.
      * |args| A list of arguments.
      *
      * TODO(b/164369078): remove this api to have just one enqueueTask for consistency.
      */
-    template<class F, class... Args> void enqueueTask(const std::string& task_name, F&& f,
-            Args&&... args) {
+    template<class F, class... Args>
+    std::future<std::string> enqueueTask(const std::string& duration_title, F&& f, Args&&... args) {
         std::function<void(void)> func = std::bind(std::forward<F>(f),
                 std::forward<Args>(args)...);
-        futures_map_[task_name] = post(task_name, func);
+        auto future = post(duration_title, func);
         if (threads_.empty()) {
             start();
         }
+        return future;
     }
 
     /*
      * Adds a task into the queue of the thread pool. The task takes a file
      * descriptor as a parameter to redirect dump results to a temporary file.
      *
-     * |task_name| The name of the task. It's also the title of the
-     * DurationReporter log.
+     * |duration_title| The title of the DurationReporter log.
      * |f| Callable function to execute the task.
      * |args| A list of arguments. A placeholder std::placeholders::_1 as a fd
      * argument needs to be included here.
      */
-    template<class F, class... Args> void enqueueTaskWithFd(const std::string& task_name, F&& f,
-            Args&&... args) {
+    template<class F, class... Args> std::future<std::string> enqueueTaskWithFd(
+            const std::string& duration_title, F&& f, Args&&... args) {
         std::function<void(int)> func = std::bind(std::forward<F>(f),
                 std::forward<Args>(args)...);
-        futures_map_[task_name] = post(task_name, func);
+        auto future = post(duration_title, func);
         if (threads_.empty()) {
             start();
         }
+        return future;
     }
 
     /*
-     * Waits until the task is finished. Dumps the task results to the STDOUT_FILENO.
-     */
-    void waitForTask(const std::string& task_name) {
-        waitForTask(task_name, "", STDOUT_FILENO);
-    }
-
-    /*
-     * Waits until the task is finished. Dumps the task results to the specified
-     * out_fd.
-     *
-     * |task_name| The name of the task.
-     * |title| Dump title string to the out_fd, an empty string for nothing.
-     * |out_fd| The target file to dump the result from the task.
-     */
-    void waitForTask(const std::string& task_name, const std::string& title, int out_fd);
-
-    /*
      * Deletes temporary files created by DumpPool.
      */
     void deleteTempFiles();
@@ -143,22 +148,22 @@
 
   private:
     using Task = std::packaged_task<std::string()>;
-    using Future = std::shared_future<std::string>;
 
     template<class T> void invokeTask(T dump_func, const std::string& duration_title, int out_fd);
 
-    template<class T> Future post(const std::string& task_name, T dump_func) {
+    template<class T>
+    std::future<std::string> post(const std::string& duration_title, T dump_func) {
         Task packaged_task([=]() {
             std::unique_ptr<TmpFile> tmp_file_ptr = createTempFile();
             if (!tmp_file_ptr) {
                 return std::string("");
             }
-            invokeTask(dump_func, task_name, tmp_file_ptr->fd.get());
+            invokeTask(dump_func, duration_title, tmp_file_ptr->fd.get());
             fsync(tmp_file_ptr->fd.get());
             return std::string(tmp_file_ptr->path);
         });
         std::unique_lock lock(lock_);
-        auto future = packaged_task.get_future().share();
+        auto future = packaged_task.get_future();
         tasks_.push(std::move(packaged_task));
         condition_variable_.notify_one();
         return future;
@@ -194,7 +199,6 @@
 
     std::vector<std::thread> threads_;
     std::queue<Task> tasks_;
-    std::map<std::string, Future> futures_map_;
 
     DISALLOW_COPY_AND_ASSIGN(DumpPool);
 };
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index c833d0e..aa42541 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -48,11 +48,26 @@
     sigemptyset(&child_mask);
     sigaddset(&child_mask, SIGCHLD);
 
+    // block SIGCHLD before we check if a process has exited
     if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) {
         printf("*** sigprocmask failed: %s\n", strerror(errno));
         return false;
     }
 
+    // if the child has exited already, handle and reset signals before leaving
+    pid_t child_pid = waitpid(pid, status, WNOHANG);
+    if (child_pid != pid) {
+        if (child_pid > 0) {
+            printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
+            sigprocmask(SIG_SETMASK, &old_mask, nullptr);
+            return false;
+        }
+    } else {
+        sigprocmask(SIG_SETMASK, &old_mask, nullptr);
+        return true;
+    }
+
+    // wait for a SIGCHLD
     timespec ts;
     ts.tv_sec = MSEC_TO_SEC(timeout_ms);
     ts.tv_nsec = (timeout_ms % 1000) * 1000000;
@@ -76,7 +91,7 @@
         return false;
     }
 
-    pid_t child_pid = waitpid(pid, status, WNOHANG);
+    child_pid = waitpid(pid, status, WNOHANG);
     if (child_pid != pid) {
         if (child_pid != -1) {
             printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
@@ -232,7 +247,6 @@
             dprintf(out_fd, "*** Error dumping %s (%s): %s\n", path.c_str(), title.c_str(),
                     strerror(err));
         }
-        fsync(out_fd);
         return -1;
     }
     return DumpFileFromFdToFd(title, path, fd.get(), out_fd, PropertiesHelper::IsDryRun());
@@ -280,7 +294,6 @@
 
     if (!title.empty()) {
         dprintf(fd, "------ %s (%s) ------\n", title.c_str(), command);
-        fsync(fd);
     }
 
     const std::string& logging_message = options.LoggingMessage();
@@ -299,14 +312,13 @@
             // There is no title, but we should still print a dry-run message
             dprintf(fd, "%s: skipped on dry run\n", command_string.c_str());
         }
-        fsync(fd);
         return 0;
     }
 
     const char* path = args[0];
 
     uint64_t start = Nanotime();
-    pid_t pid = fork();
+    pid_t pid = vfork();
 
     /* handle error case */
     if (pid < 0) {
@@ -323,7 +335,7 @@
                         strerror(errno));
             }
             MYLOGE("*** could not drop root before running %s: %s\n", command, strerror(errno));
-            return -1;
+            _exit(EXIT_FAILURE);
         }
 
         if (options.ShouldCloseAllFileDescriptorsOnExec()) {
@@ -376,7 +388,6 @@
     /* handle parent case */
     int status;
     bool ret = waitpid_with_timeout(pid, options.TimeoutInMs(), &status);
-    fsync(fd);
 
     uint64_t elapsed = Nanotime() - start;
     if (!ret) {
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8ccd940..0e9ce89 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -120,6 +120,7 @@
 using android::os::dumpstate::DumpPool;
 using android::os::dumpstate::PropertiesHelper;
 using android::os::dumpstate::TaskQueue;
+using android::os::dumpstate::WaitForTask;
 
 // Keep in sync with
 // frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -218,9 +219,9 @@
     RUN_SLOW_FUNCTION_AND_LOG(log_title, func_ptr, __VA_ARGS__);               \
     RETURN_IF_USER_DENIED_CONSENT();
 
-#define WAIT_TASK_WITH_CONSENT_CHECK(task_name, pool_ptr) \
+#define WAIT_TASK_WITH_CONSENT_CHECK(future) \
     RETURN_IF_USER_DENIED_CONSENT();                      \
-    pool_ptr->waitForTask(task_name);                     \
+    WaitForTask(future);                     \
     RETURN_IF_USER_DENIED_CONSENT();
 
 static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
@@ -1549,15 +1550,18 @@
     DurationReporter duration_reporter("DUMPSTATE");
 
     // Enqueue slow functions into the thread pool, if the parallel run is enabled.
+    std::future<std::string> dump_hals, dump_incident_report, dump_board, dump_checkins;
     if (ds.dump_pool_) {
         // Pool was shutdown in DumpstateDefaultAfterCritical method in order to
         // drop root user. Restarts it with two threads for the parallel run.
         ds.dump_pool_->start(/* thread_counts = */2);
 
-        ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
-        ds.dump_pool_->enqueueTask(DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
-        ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
-        ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
+        dump_hals = ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
+        dump_incident_report = ds.dump_pool_->enqueueTask(
+            DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
+        dump_board = ds.dump_pool_->enqueueTaskWithFd(
+            DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
+        dump_checkins = ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
     }
 
     // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
@@ -1582,7 +1586,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",
@@ -1592,7 +1595,7 @@
                                          CommandOptions::AS_ROOT);
 
     if (ds.dump_pool_) {
-        WAIT_TASK_WITH_CONSENT_CHECK(DUMP_HALS_TASK, ds.dump_pool_);
+        WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_hals));
     } else {
         RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_HALS_TASK, DumpHals);
     }
@@ -1689,7 +1692,7 @@
     ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
 
     if (ds.dump_pool_) {
-        WAIT_TASK_WITH_CONSENT_CHECK(DUMP_BOARD_TASK, ds.dump_pool_);
+        WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_board));
     } else {
         RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
     }
@@ -1718,7 +1721,7 @@
     ds.AddDir("/data/misc/bluetooth/logs", true);
 
     if (ds.dump_pool_) {
-        WAIT_TASK_WITH_CONSENT_CHECK(DUMP_CHECKINS_TASK, ds.dump_pool_);
+        WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_checkins));
     } else {
         RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_CHECKINS_TASK, DumpCheckins);
     }
@@ -1752,7 +1755,7 @@
     dump_frozen_cgroupfs();
 
     if (ds.dump_pool_) {
-        WAIT_TASK_WITH_CONSENT_CHECK(DUMP_INCIDENT_REPORT_TASK, ds.dump_pool_);
+        WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_incident_report));
     } else {
         RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_INCIDENT_REPORT_TASK,
                 DumpIncidentReport);
@@ -1777,6 +1780,7 @@
     time_t logcat_ts = time(nullptr);
 
     /* collect stack traces from Dalvik and native processes (needs root) */
+    std::future<std::string> dump_traces;
     if (dump_pool_) {
         RETURN_IF_USER_DENIED_CONSENT();
         // One thread is enough since we only need to enqueue DumpTraces here.
@@ -1784,7 +1788,8 @@
 
         // DumpTraces takes long time, post it to the another thread in the
         // pool, if pool is available
-        dump_pool_->enqueueTask(DUMP_TRACES_TASK, &Dumpstate::DumpTraces, &ds, &dump_traces_path);
+        dump_traces = dump_pool_->enqueueTask(
+            DUMP_TRACES_TASK, &Dumpstate::DumpTraces, &ds, &dump_traces_path);
     } else {
         RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_TRACES_TASK, ds.DumpTraces,
                 &dump_traces_path);
@@ -1833,12 +1838,11 @@
 
     if (dump_pool_) {
         RETURN_IF_USER_DENIED_CONSENT();
-        dump_pool_->waitForTask(DUMP_TRACES_TASK);
+        WaitForTask(std::move(dump_traces));
 
-        // Current running thread in the pool is the root user also. Shutdown
-        // the pool and restart later to ensure all threads in the pool could
-        // drop the root user.
-        dump_pool_->shutdown();
+        // Current running thread in the pool is the root user also. Delete
+        // the pool and make a new one later to ensure none of threads in the pool are root.
+        dump_pool_ = std::make_unique<DumpPool>(bugreport_internal_dir_);
     }
     if (!DropRootUser()) {
         return Dumpstate::RunStatus::ERROR;
@@ -1869,8 +1873,9 @@
     } else {
         // DumpHals takes long time, post it to the another thread in the pool,
         // if pool is available.
+        std::future<std::string> dump_hals;
         if (ds.dump_pool_) {
-            ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
+            dump_hals = ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
         }
         // Contains various system properties and process startup info.
         do_dmesg();
@@ -1880,7 +1885,7 @@
         DoKmsg();
         // DumpHals contains unrelated hardware info (camera, NFC, biometrics, ...).
         if (ds.dump_pool_) {
-            ds.dump_pool_->waitForTask(DUMP_HALS_TASK);
+            WaitForTask(std::move(dump_hals));
         } else {
             RUN_SLOW_FUNCTION_AND_LOG(DUMP_HALS_TASK, DumpHals);
         }
@@ -1914,12 +1919,14 @@
 
     // Starts thread pool after the root user is dropped, and two additional threads
     // are created for DumpHals in the DumpstateRadioCommon and DumpstateBoard.
+    std::future<std::string> dump_board;
     if (ds.dump_pool_) {
         ds.dump_pool_->start(/*thread_counts =*/2);
 
         // DumpstateBoard takes long time, post it to the another thread in the pool,
         // if pool is available.
-        ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
+        dump_board = ds.dump_pool_->enqueueTaskWithFd(
+            DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
     }
 
     DumpstateRadioCommon(include_sensitive_info);
@@ -2002,7 +2009,7 @@
     printf("========================================================\n");
 
     if (ds.dump_pool_) {
-        ds.dump_pool_->waitForTask(DUMP_BOARD_TASK);
+        WaitForTask(std::move(dump_board));
     } else {
         RUN_SLOW_FUNCTION_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
     }
@@ -3226,8 +3233,7 @@
 
 void Dumpstate::ShutdownDumpPool() {
     if (dump_pool_) {
-        dump_pool_->shutdown();
-        dump_pool_ = nullptr;
+        dump_pool_.reset();
     }
     if (zip_entry_tasks_) {
         zip_entry_tasks_->run(/* do_cancel = */true);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 4a99cd8..ee6b1ae 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -478,7 +478,7 @@
     // This is useful for debugging.
     std::string log_path_;
 
-    // Full path of the bugreport file, be it zip or text, inside bugreport_internal_dir_.
+    // Full path of the bugreport zip file inside bugreport_internal_dir_.
     std::string path_;
 
     // Full path of the file containing the screenshot (when requested).
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 42beb2b..70b4e5c 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -1720,14 +1720,13 @@
         dprintf(out_fd, "C");
     };
     setLogDuration(/* log_duration = */false);
-    dump_pool_->enqueueTaskWithFd(/* task_name = */"1", dump_func_1, std::placeholders::_1);
-    dump_pool_->enqueueTaskWithFd(/* task_name = */"2", dump_func_2, std::placeholders::_1);
-    dump_pool_->enqueueTaskWithFd(/* task_name = */"3", dump_func_3, std::placeholders::_1);
+    auto t1 = dump_pool_->enqueueTaskWithFd("", dump_func_1, std::placeholders::_1);
+    auto t2 = dump_pool_->enqueueTaskWithFd("", dump_func_2, std::placeholders::_1);
+    auto t3 = dump_pool_->enqueueTaskWithFd("", dump_func_3, std::placeholders::_1);
 
-    dump_pool_->waitForTask("1", "", out_fd_.get());
-    dump_pool_->waitForTask("2", "", out_fd_.get());
-    dump_pool_->waitForTask("3", "", out_fd_.get());
-    dump_pool_->shutdown();
+    WaitForTask(std::move(t1), "", out_fd_.get());
+    WaitForTask(std::move(t2), "", out_fd_.get());
+    WaitForTask(std::move(t3), "", out_fd_.get());
 
     std::string result;
     ReadFileToString(out_path_, &result);
@@ -1741,9 +1740,8 @@
         run_1 = true;
     };
 
-    dump_pool_->enqueueTask(/* task_name = */"1", dump_func_1);
-    dump_pool_->waitForTask("1", "", out_fd_.get());
-    dump_pool_->shutdown();
+    auto t1 = dump_pool_->enqueueTask(/* duration_title = */"1", dump_func_1);
+    WaitForTask(std::move(t1), "", out_fd_.get());
 
     std::string result;
     ReadFileToString(out_path_, &result);
@@ -1752,27 +1750,6 @@
     EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
 }
 
-TEST_F(DumpPoolTest, Shutdown_withoutCrash) {
-    bool run_1 = false;
-    auto dump_func_1 = [&]() {
-        run_1 = true;
-    };
-    auto dump_func = []() {
-        sleep(1);
-    };
-
-    dump_pool_->start(/* thread_counts = */1);
-    dump_pool_->enqueueTask(/* task_name = */"1", dump_func_1);
-    dump_pool_->enqueueTask(/* task_name = */"2", dump_func);
-    dump_pool_->enqueueTask(/* task_name = */"3", dump_func);
-    dump_pool_->enqueueTask(/* task_name = */"4", dump_func);
-    dump_pool_->waitForTask("1", "", out_fd_.get());
-    dump_pool_->shutdown();
-
-    EXPECT_TRUE(run_1);
-    EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
-}
-
 class TaskQueueTest : public DumpstateBaseTest {
 public:
     void SetUp() {
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 00babc3..c9f680b 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -51,6 +51,7 @@
     ],
     static_libs: [
         "libasync_safe",
+        "libext2_uuid",
     ],
     export_shared_lib_headers: [
         "libbinder",
@@ -262,6 +263,7 @@
         "libasync_safe",
         "libdiskusage",
         "libotapreoptparameters",
+        "libext2_uuid",
     ],
 
     shared_libs: [
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 4ce48d5..e7bde21 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -18,13 +18,9 @@
 
 #define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
 
-#include <algorithm>
 #include <errno.h>
-#include <fstream>
 #include <fts.h>
-#include <functional>
 #include <inttypes.h>
-#include <regex>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -40,6 +36,11 @@
 #include <sys/wait.h>
 #include <sys/xattr.h>
 #include <unistd.h>
+#include <algorithm>
+#include <filesystem>
+#include <fstream>
+#include <functional>
+#include <regex>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -720,6 +721,76 @@
             return error("Failed to prepare profiles for " + packageName);
         }
     }
+
+    // TODO(b/220095381): Due to boot time regression, we have omitted call to
+    // createAppDirectoryForSupplementalData from here temporarily (unless it's for testing)
+    if (uuid_ != nullptr && strcmp(uuid_, "TEST") == 0) {
+        auto status = createAppDirectoryForSupplementalData(uuid, packageName, userId, appId,
+                                                            previousAppId, seInfo, flags);
+        if (!status.isOk()) {
+            return status;
+        }
+    }
+
+    return ok();
+}
+
+/**
+ * Responsible for creating /data/user/0/supplemental/<app-name> directory and other
+ * app level sub directories, such as ./shared
+ */
+binder::Status InstalldNativeService::createAppDirectoryForSupplementalData(
+        const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+        int32_t appId, int32_t previousAppId, const std::string& seInfo, int32_t flags) {
+    int32_t supplementalUid = multiuser_get_supplemental_uid(userId, appId);
+    if (supplementalUid == -1) {
+        // There no valid supplemental process for this app. Skip creation of data directory
+        return ok();
+    }
+
+    // TODO(b/211763739): what if uuid is not nullptr or TEST?
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+    constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+    for (int i = 0; i < 2; i++) {
+        int currentFlag = storageFlags[i];
+        if ((flags & currentFlag) == 0) {
+            continue;
+        }
+        bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+
+        // /data/misc_{ce,de}/<user-id>/supplemental directory gets created by vold
+        // during user creation
+
+        // Prepare the app directory
+        auto appPath = create_data_misc_supplemental_package_path(uuid_, isCeData, userId,
+                                                                  packageName.c_str());
+        if (prepare_app_dir(appPath, 0751, AID_SYSTEM)) {
+            return error("Failed to prepare " + appPath);
+        }
+
+        // Now prepare the shared directory which will be accessible by all codes
+        auto sharedPath = create_data_misc_supplemental_shared_path(uuid_, isCeData, userId,
+                                                                    packageName.c_str());
+
+        int32_t previousSupplementalUid = multiuser_get_supplemental_uid(userId, previousAppId);
+        int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
+        if (cacheGid == -1) {
+            return exception(binder::Status::EX_ILLEGAL_STATE,
+                             StringPrintf("cacheGid cannot be -1 for supplemental data"));
+        }
+        auto status = createAppDataDirs(sharedPath, supplementalUid, &previousSupplementalUid,
+                                        cacheGid, seInfo, 0700);
+        if (!status.isOk()) {
+            return status;
+        }
+
+        // TODO(b/211763739): We also need to handle art profile creations
+
+        // TODO(b/211763739): And return the CE inode of the supplemental root directory and
+        // app directory under it so we can clear contents while CE storage is locked
+    }
+
     return ok();
 }
 
@@ -957,13 +1028,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) {
@@ -997,7 +1068,6 @@
             if (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) {
                 res = error("Failed to delete contents of " + path);
@@ -3190,5 +3260,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 6e74884..6b4ba1f 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -47,14 +47,9 @@
             int32_t flags);
 
     binder::Status createAppData(const std::optional<std::string>& uuid,
-            const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
-            int32_t previousAppId, const std::string& seInfo, int32_t targetSdkVersion,
-            int64_t* _aidl_return);
-    binder::Status createAppDataLocked(const std::optional<std::string>& uuid,
-                                       const std::string& packageName, int32_t userId,
-                                       int32_t flags, int32_t appId, int32_t previousAppId,
-                                       const std::string& seInfo, int32_t targetSdkVersion,
-                                       int64_t* _aidl_return);
+                                 const std::string& packageName, int32_t userId, int32_t flags,
+                                 int32_t appId, int32_t previousAppId, const std::string& seInfo,
+                                 int32_t targetSdkVersion, int64_t* _aidl_return);
 
     binder::Status createAppData(
             const android::os::CreateAppDataArgs& args,
@@ -185,6 +180,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;
@@ -200,6 +198,18 @@
     std::unordered_map<uid_t, int64_t> mCacheQuotas;
 
     std::string findDataMediaPath(const std::optional<std::string>& uuid, userid_t userid);
+
+    binder::Status createAppDataLocked(const std::optional<std::string>& uuid,
+                                       const std::string& packageName, int32_t userId,
+                                       int32_t flags, int32_t appId, int32_t previousAppId,
+                                       const std::string& seInfo, int32_t targetSdkVersion,
+                                       int64_t* _aidl_return);
+
+    binder::Status createAppDirectoryForSupplementalData(const std::optional<std::string>& uuid,
+                                                         const std::string& packageName,
+                                                         int32_t userId, int32_t appId,
+                                                         int32_t previousAppId,
+                                                         const std::string& seInfo, int32_t flags);
 };
 
 }  // namespace installd
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 44c9667..afedcc6 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -126,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/dexopt.cpp b/cmds/installd/dexopt.cpp
index c796da6..9647865 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -74,10 +74,19 @@
 using android::base::ReadFully;
 using android::base::StringPrintf;
 using android::base::WriteFully;
+using android::base::borrowed_fd;
 using android::base::unique_fd;
 
 namespace {
 
+// Timeout for short operations, such as merging profiles.
+constexpr int kShortTimeoutMs = 60000; // 1 minute.
+
+// Timeout for long operations, such as compilation. This should be smaller than the Package Manager
+// watchdog (PackageManagerService.WATCHDOG_TIMEOUT, 10 minutes), so that the operation will be
+// aborted before that watchdog would take down the system server.
+constexpr int kLongTimeoutMs = 570000; // 9.5 minutes.
+
 class DexOptStatus {
  public:
     // Check if dexopt is cancelled and fork if it is not cancelled.
@@ -486,6 +495,25 @@
     }
 }
 
+// Cleans up an output file specified by a file descriptor. This function should be called whenever
+// a subprocess that modifies a system-managed file crashes.
+// If the subprocess crashes while it's writing to the file, the file is likely corrupted, so we
+// should remove it.
+// If the subprocess times out and is killed while it's acquiring a flock on the file, there is
+// probably a deadlock, so it's also good to remove the file so that later operations won't
+// encounter the same problem. It's safe to do so because the process that is holding the flock will
+// still have access to the file until the file descriptor is closed.
+// Note that we can't do `clear_reference_profile` here even if the fd points to a reference profile
+// because that also requires a flock and is therefore likely to be stuck in the second case.
+static bool cleanup_output_fd(int fd) {
+    std::string path;
+    bool ret = remove_file_at_fd(fd, &path);
+    if (ret) {
+        LOG(INFO) << "Removed file at path " << path;
+    }
+    return ret;
+}
+
 static constexpr int PROFMAN_BIN_RETURN_CODE_SUCCESS = 0;
 static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 1;
 static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION_NOT_ENOUGH_DELTA = 2;
@@ -497,13 +525,14 @@
 
 class RunProfman : public ExecVHelper {
   public:
-   void SetupArgs(const std::vector<unique_fd>& profile_fds,
-                  const unique_fd& reference_profile_fd,
-                  const std::vector<unique_fd>& apk_fds,
-                  const std::vector<std::string>& dex_locations,
-                  bool copy_and_update,
-                  bool for_snapshot,
-                  bool for_boot_image) {
+    template <typename T, typename U>
+    void SetupArgs(const std::vector<T>& profile_fds,
+                   const unique_fd& reference_profile_fd,
+                   const std::vector<U>& apk_fds,
+                   const std::vector<std::string>& dex_locations,
+                   bool copy_and_update,
+                   bool for_snapshot,
+                   bool for_boot_image) {
 
         // TODO(calin): Assume for now we run in the bg compile job (which is in
         // most of the invocation). With the current data flow, is not very easy or
@@ -519,11 +548,11 @@
             AddArg("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get()));
         }
 
-        for (const unique_fd& fd : profile_fds) {
+        for (const T& fd : profile_fds) {
             AddArg("--profile-file-fd=" + std::to_string(fd.get()));
         }
 
-        for (const unique_fd& fd : apk_fds) {
+        for (const U& fd : apk_fds) {
             AddArg("--apk-fd=" + std::to_string(fd.get()));
         }
 
@@ -582,20 +611,14 @@
                   for_boot_image);
     }
 
-    void SetupCopyAndUpdate(unique_fd&& profile_fd,
-                            unique_fd&& reference_profile_fd,
-                            unique_fd&& apk_fd,
+    void SetupCopyAndUpdate(const unique_fd& profile_fd,
+                            const unique_fd& reference_profile_fd,
+                            const unique_fd& apk_fd,
                             const std::string& dex_location) {
-        // The fds need to stay open longer than the scope of the function, so put them into a local
-        // variable vector.
-        profiles_fd_.push_back(std::move(profile_fd));
-        apk_fds_.push_back(std::move(apk_fd));
-        reference_profile_fd_ = std::move(reference_profile_fd);
-        std::vector<std::string> dex_locations = {dex_location};
-        SetupArgs(profiles_fd_,
-                  reference_profile_fd_,
-                  apk_fds_,
-                  dex_locations,
+        SetupArgs(std::vector<borrowed_fd>{profile_fd},
+                  reference_profile_fd,
+                  std::vector<borrowed_fd>{apk_fd},
+                  {dex_location},
                   /*copy_and_update=*/true,
                   /*for_snapshot*/false,
                   /*for_boot_image*/false);
@@ -621,11 +644,6 @@
     void Exec() {
         ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
     }
-
-  private:
-    unique_fd reference_profile_fd_;
-    std::vector<unique_fd> profiles_fd_;
-    std::vector<unique_fd> apk_fds_;
 };
 
 static int analyze_profiles(uid_t uid, const std::string& package_name,
@@ -657,13 +675,14 @@
         profman_merge.Exec();
     }
     /* parent */
-    int return_code = wait_child(pid);
+    int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
     bool need_to_compile = false;
     bool empty_profiles = false;
     bool should_clear_current_profiles = false;
     bool should_clear_reference_profile = false;
     if (!WIFEXITED(return_code)) {
         LOG(WARNING) << "profman failed for location " << location << ": " << return_code;
+        cleanup_output_fd(reference_profile_fd.get());
     } else {
         return_code = WEXITSTATUS(return_code);
         switch (return_code) {
@@ -797,10 +816,10 @@
         profman_dump.Exec();
     }
     /* parent */
-    int return_code = wait_child(pid);
+    int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
     if (!WIFEXITED(return_code)) {
-        LOG(WARNING) << "profman failed for package " << pkgname << ": "
-                << return_code;
+        LOG(WARNING) << "profman failed for package " << pkgname << ": " << return_code;
+        cleanup_output_fd(output_fd.get());
         return false;
     }
     return true;
@@ -871,7 +890,11 @@
         _exit(0);
     }
     /* parent */
-    int return_code = wait_child(pid);
+    int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
+    if (!WIFEXITED(return_code)) {
+        cleanup_output_fd(out_fd.get());
+        return false;
+    }
     return return_code == 0;
 }
 
@@ -1521,7 +1544,7 @@
     }
     pipe_read.reset();
 
-    int return_code = wait_child(pid);
+    int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
     if (!WIFEXITED(return_code)) {
         PLOG(ERROR) << "Error waiting for child dexoptanalyzer process";
         return false;
@@ -1695,7 +1718,7 @@
     }
 
     /* parent */
-    int result = wait_child(pid);
+    int result = wait_child_with_timeout(pid, kShortTimeoutMs);
     cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid);
     if (!WIFEXITED(result)) {
         if ((WTERMSIG(result) == SIGKILL) && cancelled) {
@@ -1954,7 +1977,7 @@
 
         runner.Exec(DexoptReturnCodes::kDex2oatExec);
     } else {
-        int res = wait_child(pid);
+        int res = wait_child_with_timeout(pid, kLongTimeoutMs);
         bool cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid);
         if (res == 0) {
             LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' (success) ---";
@@ -2143,7 +2166,7 @@
         _exit(result ? kReconcileSecondaryDexCleanedUp : kReconcileSecondaryDexAccessIOError);
     }
 
-    int return_code = wait_child(pid);
+    int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
     if (!WIFEXITED(return_code)) {
         LOG(WARNING) << "reconcile dex failed for location " << dex_path << ": " << return_code;
     } else {
@@ -2261,7 +2284,7 @@
     if (!ReadFully(pipe_read, out_secondary_dex_hash->data(), out_secondary_dex_hash->size())) {
         out_secondary_dex_hash->clear();
     }
-    return wait_child(pid) == 0;
+    return wait_child_with_timeout(pid, kShortTimeoutMs) == 0;
 }
 
 // Helper for move_ab, so that we can have common failure-case cleanup.
@@ -2591,9 +2614,10 @@
     }
 
     /* parent */
-    int return_code = wait_child(pid);
+    int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
     if (!WIFEXITED(return_code)) {
         LOG(WARNING) << "profman failed for " << package_name << ":" << profile_name;
+        cleanup_output_fd(snapshot_fd.get());
         return false;
     }
 
@@ -2700,10 +2724,11 @@
         }
 
         /* parent */
-        int return_code = wait_child(pid);
+        int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
 
         if (!WIFEXITED(return_code)) {
             PLOG(WARNING) << "profman failed for " << package_name << ":" << profile_name;
+            cleanup_output_fd(snapshot_fd.get());
             return false;
         }
 
@@ -2774,9 +2799,9 @@
     }
 
     RunProfman args;
-    args.SetupCopyAndUpdate(std::move(dex_metadata_fd),
-                            std::move(ref_profile_fd),
-                            std::move(apk_fd),
+    args.SetupCopyAndUpdate(dex_metadata_fd,
+                            ref_profile_fd,
+                            apk_fd,
                             code_path);
     pid_t pid = fork();
     if (pid == 0) {
@@ -2789,9 +2814,10 @@
     }
 
     /* parent */
-    int return_code = wait_child(pid);
+    int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
     if (!WIFEXITED(return_code)) {
         PLOG(WARNING) << "profman failed for " << package_name << ":" << profile_name;
+        cleanup_output_fd(ref_profile_fd.get());
         return false;
     }
     return true;
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 51f7716..e390bab 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -25,6 +25,7 @@
     static_libs: [
         "libasync_safe",
         "libdiskusage",
+        "libext2_uuid",
         "libinstalld",
         "liblog",
     ],
@@ -53,6 +54,7 @@
     static_libs: [
         "libasync_safe",
         "libdiskusage",
+        "libext2_uuid",
         "libinstalld",
         "libziparchive",
         "liblog",
@@ -99,6 +101,7 @@
     static_libs: [
         "libasync_safe",
         "libdiskusage",
+        "libext2_uuid",
         "libinstalld",
         "libziparchive",
         "liblog",
@@ -144,6 +147,7 @@
     static_libs: [
         "libasync_safe",
         "libdiskusage",
+        "libext2_uuid",
         "libinstalld",
         "liblog",
         "liblogwrap",
@@ -204,6 +208,7 @@
         "libutils",
     ],
     static_libs: [
+        "libext2_uuid",
         "libinstalld",
         "liblog",
     ],
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index bb36c39..f21a304 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -50,6 +50,8 @@
 namespace android {
 namespace installd {
 
+constexpr int kTimeoutMs = 60000;
+
 // TODO(calin): try to dedup this code.
 #if defined(__arm__)
 static const std::string kRuntimeIsa = "arm";
@@ -1073,7 +1075,7 @@
             _exit(0);
         }
         /* parent */
-        ASSERT_TRUE(WIFEXITED(wait_child(pid)));
+        ASSERT_TRUE(WIFEXITED(wait_child_with_timeout(pid, kTimeoutMs)));
     }
 
     void mergePackageProfiles(const std::string& package_name,
@@ -1377,7 +1379,7 @@
             _exit(0);
         }
         /* parent */
-        ASSERT_TRUE(WIFEXITED(wait_child(pid)));
+        ASSERT_TRUE(WIFEXITED(wait_child_with_timeout(pid, kTimeoutMs)));
     }
   protected:
     std::string intial_android_profiles_dir;
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index b831515..703a096 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -74,7 +74,14 @@
 }
 namespace installd {
 
-constexpr const char* kTestUuid = "TEST";
+static constexpr const char* kTestUuid = "TEST";
+static constexpr const char* kTestPath = "/data/local/tmp/user/0";
+static constexpr const uid_t kSystemUid = 1000;
+static constexpr const int32_t kTestUserId = 0;
+static constexpr const uid_t kTestAppId = 19999;
+
+const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId);
+const uid_t kTestAppSupplementalUid = multiuser_get_supplemental_uid(kTestUserId, kTestAppId);
 
 #define FLAG_FORCE InstalldNativeService::FLAG_FORCE
 
@@ -97,7 +104,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 +114,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 +138,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, [](const std::string& name, bool is_dir) {
+        return is_dir && is_renamed_deleted_dir(name);
+    });
+}
+
 class ServiceTest : public testing::Test {
 protected:
     InstalldNativeService* service;
@@ -193,6 +233,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";
 
@@ -768,5 +936,120 @@
           "com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE));
 }
 
+class AppSupplementalDataTest : public testing::Test {
+public:
+    void CheckFileAccess(const std::string& path, uid_t uid, mode_t mode) {
+        const auto fullPath = "/data/local/tmp/" + path;
+        ASSERT_TRUE(exists(fullPath.c_str())) << "For path: " << fullPath;
+        struct stat st;
+        ASSERT_EQ(0, stat(fullPath.c_str(), &st));
+        ASSERT_EQ(uid, st.st_uid) << "For path: " << fullPath;
+        ASSERT_EQ(uid, st.st_gid) << "For path: " << fullPath;
+        ASSERT_EQ(mode, st.st_mode) << "For path: " << fullPath;
+    }
+
+    bool exists(const char* path) { return ::access(path, F_OK) == 0; }
+
+    // Creates a default CreateAppDataArgs object
+    android::os::CreateAppDataArgs createAppDataArgs() {
+        android::os::CreateAppDataArgs args;
+        args.uuid = kTestUuid;
+        args.packageName = "com.foo";
+        args.userId = kTestUserId;
+        args.appId = kTestAppId;
+        args.seInfo = "default";
+        args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+        return args;
+    }
+
+protected:
+    InstalldNativeService* service;
+
+    virtual void SetUp() {
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
+
+        service = new InstalldNativeService();
+        clearAppData();
+        ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700));
+        ASSERT_TRUE(mkdirs("/data/local/tmp/user_de/0", 0700));
+        ASSERT_TRUE(mkdirs("/data/local/tmp/misc_ce/0/supplemental", 0700));
+        ASSERT_TRUE(mkdirs("/data/local/tmp/misc_de/0/supplemental", 0700));
+
+        init_globals_from_data_and_root();
+    }
+
+    virtual void TearDown() {
+        delete service;
+        clearAppData();
+    }
+
+private:
+    void clearAppData() {
+        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true));
+        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_ce", true));
+        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_de", true));
+        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true));
+    }
+};
+
+TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs();
+    args.packageName = "com.foo";
+    args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+    CheckFileAccess("misc_ce/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751);
+    CheckFileAccess("misc_ce/0/supplemental/com.foo/shared", kTestAppSupplementalUid,
+                    S_IFDIR | 0700);
+    CheckFileAccess("misc_ce/0/supplemental/com.foo/shared/cache", kTestAppSupplementalUid,
+                    S_IFDIR | S_ISGID | 0771);
+    CheckFileAccess("misc_ce/0/supplemental/com.foo/shared/code_cache", kTestAppSupplementalUid,
+                    S_IFDIR | S_ISGID | 0771);
+
+    CheckFileAccess("misc_de/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751);
+    CheckFileAccess("misc_de/0/supplemental/com.foo/shared", kTestAppSupplementalUid,
+                    S_IFDIR | 0700);
+    CheckFileAccess("misc_de/0/supplemental/com.foo/shared/cache", kTestAppSupplementalUid,
+                    S_IFDIR | S_ISGID | 0771);
+    CheckFileAccess("misc_de/0/supplemental/com.foo/shared/code_cache", kTestAppSupplementalUid,
+                    S_IFDIR | S_ISGID | 0771);
+}
+
+TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData_WithoutDeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs();
+    args.packageName = "com.foo";
+    args.flags = FLAG_STORAGE_CE;
+
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+    // Only CE paths should exist
+    CheckFileAccess("misc_ce/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751);
+
+    // DE paths should not exist
+    ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/supplemental/com.foo"));
+}
+
+TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData_WithoutCeFlag) {
+    android::os::CreateAppDataResult result;
+    android::os::CreateAppDataArgs args = createAppDataArgs();
+    args.packageName = "com.foo";
+    args.flags = FLAG_STORAGE_DE;
+
+    // Create the app user data.
+    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+    // CE paths should not exist
+    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/supplemental/com.foo"));
+
+    // Only DE paths should exist
+    CheckFileAccess("misc_de/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751);
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index ed87b67..8d1ccdc 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
+#include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <android-base/logging.h>
 #include <android-base/scopeguard.h>
@@ -555,6 +557,24 @@
     EXPECT_EQ(0, MatchExtension("docx"));
 }
 
+TEST_F(UtilsTest, TestIsRenamedDeletedDir) {
+    EXPECT_FALSE(is_renamed_deleted_dir(""));
+    EXPECT_FALSE(is_renamed_deleted_dir("1"));
+    EXPECT_FALSE(is_renamed_deleted_dir("="));
+    EXPECT_FALSE(is_renamed_deleted_dir("=="));
+    EXPECT_FALSE(is_renamed_deleted_dir("d=="));
+    EXPECT_FALSE(is_renamed_deleted_dir("ed=="));
+    EXPECT_FALSE(is_renamed_deleted_dir("ted=="));
+    EXPECT_FALSE(is_renamed_deleted_dir("eted=="));
+    EXPECT_FALSE(is_renamed_deleted_dir("leted=="));
+    EXPECT_FALSE(is_renamed_deleted_dir("eleted=="));
+    EXPECT_FALSE(is_renamed_deleted_dir("deleted=="));
+    EXPECT_FALSE(is_renamed_deleted_dir("=deleted=="));
+    EXPECT_TRUE(is_renamed_deleted_dir("==deleted=="));
+    EXPECT_TRUE(is_renamed_deleted_dir("123==deleted=="));
+    EXPECT_TRUE(is_renamed_deleted_dir("5b14b6458a44==deleted=="));
+}
+
 TEST_F(UtilsTest, TestRollbackPaths) {
     EXPECT_EQ("/data/misc_ce/0/rollback/239/com.foo",
             create_data_misc_ce_rollback_package_path(nullptr, 0, 239, "com.foo"));
@@ -638,5 +658,79 @@
     ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700));
 }
 
+TEST_F(UtilsTest, TestSupplementalDataPaths) {
+    // Ce data paths
+    EXPECT_EQ("/data/misc_ce/0/supplemental",
+              create_data_misc_supplemental_path(nullptr, /*isCeData=*/true, 0));
+    EXPECT_EQ("/data/misc_ce/10/supplemental",
+              create_data_misc_supplemental_path(nullptr, true, 10));
+
+    EXPECT_EQ("/data/misc_ce/0/supplemental/com.foo",
+              create_data_misc_supplemental_package_path(nullptr, true, 0, "com.foo"));
+    EXPECT_EQ("/data/misc_ce/10/supplemental/com.foo",
+              create_data_misc_supplemental_package_path(nullptr, true, 10, "com.foo"));
+
+    EXPECT_EQ("/data/misc_ce/0/supplemental/com.foo/shared",
+              create_data_misc_supplemental_shared_path(nullptr, true, 0, "com.foo"));
+    EXPECT_EQ("/data/misc_ce/10/supplemental/com.foo/shared",
+              create_data_misc_supplemental_shared_path(nullptr, true, 10, "com.foo"));
+
+    // De data paths
+    EXPECT_EQ("/data/misc_de/0/supplemental",
+              create_data_misc_supplemental_path(nullptr, /*isCeData=*/false, 0));
+    EXPECT_EQ("/data/misc_de/10/supplemental",
+              create_data_misc_supplemental_path(nullptr, false, 10));
+
+    EXPECT_EQ("/data/misc_de/0/supplemental/com.foo",
+              create_data_misc_supplemental_package_path(nullptr, false, 0, "com.foo"));
+    EXPECT_EQ("/data/misc_de/10/supplemental/com.foo",
+              create_data_misc_supplemental_package_path(nullptr, false, 10, "com.foo"));
+
+    EXPECT_EQ("/data/misc_de/0/supplemental/com.foo/shared",
+              create_data_misc_supplemental_shared_path(nullptr, false, 0, "com.foo"));
+    EXPECT_EQ("/data/misc_de/10/supplemental/com.foo/shared",
+              create_data_misc_supplemental_shared_path(nullptr, false, 10, "com.foo"));
+}
+
+TEST_F(UtilsTest, WaitChild) {
+    pid_t pid = fork();
+    if (pid == 0) {
+        /* child */
+        // Do nothing.
+        _exit(0);
+    }
+    /* parent */
+    int return_code = wait_child_with_timeout(pid, /*timeout_ms=*/100);
+    EXPECT_TRUE(WIFEXITED(return_code));
+    EXPECT_EQ(WEXITSTATUS(return_code), 0);
+}
+
+TEST_F(UtilsTest, WaitChildTimeout) {
+    pid_t pid = fork();
+    if (pid == 0) {
+        /* child */
+        sleep(1);
+        _exit(0);
+    }
+    /* parent */
+    int return_code = wait_child_with_timeout(pid, /*timeout_ms=*/1);
+    EXPECT_FALSE(WIFEXITED(return_code));
+    EXPECT_EQ(WTERMSIG(return_code), SIGKILL);
+}
+
+TEST_F(UtilsTest, RemoveFileAtFd) {
+    std::string filename = "/data/local/tmp/tempfile-XXXXXX";
+    int fd = mkstemp(filename.data());
+    ASSERT_GE(fd, 0);
+    ASSERT_EQ(access(filename.c_str(), F_OK), 0);
+
+    std::string actual_filename;
+    remove_file_at_fd(fd, &actual_filename);
+    EXPECT_NE(access(filename.c_str(), F_OK), 0);
+    EXPECT_EQ(filename, actual_filename);
+
+    close(fd);
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 0f8a732..6650b76 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -19,17 +19,21 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <fts.h>
+#include <poll.h>
 #include <stdlib.h>
 #include <sys/capability.h>
+#include <sys/pidfd.h>
 #include <sys/stat.h>
+#include <sys/statvfs.h>
 #include <sys/wait.h>
 #include <sys/xattr.h>
-#include <sys/statvfs.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <android-base/strings.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/fs.h>
 #include <cutils/properties.h>
@@ -47,6 +51,7 @@
 
 #define DEBUG_XATTRS 0
 
+using android::base::Dirname;
 using android::base::EndsWith;
 using android::base::Fdopendir;
 using android::base::StringPrintf;
@@ -55,6 +60,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.
@@ -188,6 +197,43 @@
     return StringPrintf("%s/user_de/%u", data.c_str(), userid);
 }
 
+/**
+ * Create the path name where supplemental data for all apps will be stored.
+ * E.g. /data/misc_ce/0/supplemental
+ */
+std::string create_data_misc_supplemental_path(const char* uuid, bool isCeData, userid_t user) {
+    std::string data(create_data_path(uuid));
+    if (isCeData) {
+        return StringPrintf("%s/misc_ce/%d/supplemental", data.c_str(), user);
+    } else {
+        return StringPrintf("%s/misc_de/%d/supplemental", data.c_str(), user);
+    }
+}
+
+/**
+ * Create the path name where code data for all codes in a particular app will be stored.
+ * E.g. /data/misc_ce/0/supplemental/<app-name>
+ */
+std::string create_data_misc_supplemental_package_path(const char* volume_uuid, bool isCeData,
+                                                       userid_t user, const char* package_name) {
+    check_package_name(package_name);
+    return StringPrintf("%s/%s",
+                        create_data_misc_supplemental_path(volume_uuid, isCeData, user).c_str(),
+                        package_name);
+}
+
+/**
+ * Create the path name where shared code data for a particular app will be stored.
+ * E.g. /data/misc_ce/0/supplemental/<app-name>/shared
+ */
+std::string create_data_misc_supplemental_shared_path(const char* volume_uuid, bool isCeData,
+                                                      userid_t user, const char* package_name) {
+    return StringPrintf("%s/shared",
+                        create_data_misc_supplemental_package_path(volume_uuid, isCeData, user,
+                                                                   package_name)
+                                .c_str());
+}
+
 std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) {
     return StringPrintf("%s/misc_ce/%u/rollback", create_data_path(volume_uuid).c_str(), user);
 }
@@ -595,6 +641,97 @@
     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(const std::string& path) {
+    if (path.size() < deletedSuffix.size()) {
+        return false;
+    }
+    std::string_view pathSuffix{path.c_str() + path.size() - deletedSuffix.size()};
+    return pathSuffix == 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;
@@ -962,30 +1099,45 @@
     return fs_prepare_dir(path.c_str(), 0750, uid, gid);
 }
 
-int wait_child(pid_t pid)
-{
+static int wait_child(pid_t pid) {
     int status;
-    pid_t got_pid;
+    pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, /*options=*/0));
 
-    while (1) {
-        got_pid = waitpid(pid, &status, 0);
-        if (got_pid == -1 && errno == EINTR) {
-            printf("waitpid interrupted, retrying\n");
-        } else {
-            break;
-        }
-    }
     if (got_pid != pid) {
-        ALOGW("waitpid failed: wanted %d, got %d: %s\n",
-            (int) pid, (int) got_pid, strerror(errno));
-        return 1;
+        PLOG(ERROR) << "waitpid failed: wanted " << pid << ", got " << got_pid;
+        return W_EXITCODE(/*exit_code=*/255, /*signal_number=*/0);
     }
 
-    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
-        return 0;
-    } else {
-        return status;      /* always nonzero */
+    return status;
+}
+
+int wait_child_with_timeout(pid_t pid, int timeout_ms) {
+    int pidfd = pidfd_open(pid, /*flags=*/0);
+    if (pidfd < 0) {
+        PLOG(ERROR) << "pidfd_open failed for pid " << pid;
+        kill(pid, SIGKILL);
+        return wait_child(pid);
     }
+
+    struct pollfd pfd;
+    pfd.fd = pidfd;
+    pfd.events = POLLIN;
+    int poll_ret = TEMP_FAILURE_RETRY(poll(&pfd, /*nfds=*/1, timeout_ms));
+
+    close(pidfd);
+
+    if (poll_ret < 0) {
+        PLOG(ERROR) << "poll failed for pid " << pid;
+        kill(pid, SIGKILL);
+        return wait_child(pid);
+    }
+    if (poll_ret == 0) {
+        LOG(WARNING) << "Child process " << pid << " timed out after " << timeout_ms
+                     << "ms. Killing it";
+        kill(pid, SIGKILL);
+        return wait_child(pid);
+    }
+    return wait_child(pid);
 }
 
 /**
@@ -1198,5 +1350,27 @@
     }
 }
 
+bool remove_file_at_fd(int fd, /*out*/ std::string* path) {
+    char path_buffer[PATH_MAX + 1];
+    std::string proc_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
+    ssize_t len = readlink(proc_path.c_str(), path_buffer, PATH_MAX);
+    if (len < 0) {
+        PLOG(WARNING) << "Could not remove file at fd " << fd << ": Failed to get file path";
+        return false;
+    }
+    path_buffer[len] = '\0';
+    if (path != nullptr) {
+        *path = path_buffer;
+    }
+    if (unlink(path_buffer) != 0) {
+        if (errno == ENOENT) {
+            return true;
+        }
+        PLOG(WARNING) << "Could not remove file at path " << path_buffer;
+        return false;
+    }
+    return true;
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 549fc6c..2d00845 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -60,6 +60,13 @@
 std::string create_data_user_ce_package_path_as_user_link(
         const char* volume_uuid, userid_t userid, const char* package_name);
 
+std::string create_data_misc_supplemental_path(const char* volume_uuid, bool isCeData,
+                                               userid_t userid);
+std::string create_data_misc_supplemental_package_path(const char* volume_uuid, bool isCeData,
+                                                       userid_t userid, const char* package_name);
+std::string create_data_misc_supplemental_shared_path(const char* volume_uuid, bool isCeData,
+                                                      userid_t userid, const char* package_name);
+
 std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user);
 std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user);
 std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
@@ -120,6 +127,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(const std::string& path);
+int rename_delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = true);
+
+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),
@@ -148,7 +160,8 @@
 
 int ensure_config_user_dirs(userid_t userid);
 
-int wait_child(pid_t pid);
+// Waits for a child process, or kills it if it times out. Returns the exit code.
+int wait_child_with_timeout(pid_t pid, int timeout_ms);
 
 int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
         uid_t uid, gid_t gid);
@@ -165,6 +178,10 @@
 
 void drop_capabilities(uid_t uid);
 
+// Removes a file specified by a file descriptor. Returns true on success. Reports the file path to
+// `path` if present.
+bool remove_file_at_fd(int fd, /*out*/ std::string* path = nullptr);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/view_compiler.cpp b/cmds/installd/view_compiler.cpp
index 60d6492..8c000a1 100644
--- a/cmds/installd/view_compiler.cpp
+++ b/cmds/installd/view_compiler.cpp
@@ -33,7 +33,13 @@
 namespace android {
 namespace installd {
 
-using base::unique_fd;
+namespace {
+
+using ::android::base::unique_fd;
+
+constexpr int kTimeoutMs = 300000;
+
+} // namespace
 
 bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
                    int uid) {
@@ -88,7 +94,17 @@
         _exit(1);
     }
 
-    return wait_child(pid) == 0;
+    int return_code = wait_child_with_timeout(pid, kTimeoutMs);
+    if (!WIFEXITED(return_code)) {
+        LOG(WARNING) << "viewcompiler failed for " << package_name << ":" << apk_path;
+        if (WTERMSIG(return_code) == SIGKILL) {
+            // If the subprocess is killed while it's writing to the file, the file is likely
+            // corrupted, so we should remove it.
+            remove_file_at_fd(outfd.get());
+        }
+        return false;
+    }
+    return WEXITSTATUS(return_code) == 0;
 }
 
 } // namespace installd
diff --git a/data/etc/android.hardware.telephony.euicc.mep.xml b/data/etc/android.hardware.telephony.euicc.mep.xml
new file mode 100644
index 0000000..f958e4b
--- /dev/null
+++ b/data/etc/android.hardware.telephony.euicc.mep.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices with an eUICC supporting MEP(Multiple enabled profiles) -->
+<permissions>
+    <feature name="android.hardware.telephony.euicc" />
+    <feature name="android.hardware.telephony.euicc.mep" />
+</permissions>
\ No newline at end of file
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/choreographer.h b/include/android/choreographer.h
index 98f0eec..63aa7ff 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -76,7 +76,7 @@
  * It's passed the frame data that should not outlive the callback, as well as the data pointer
  * provided by the application that registered a callback.
  */
-typedef void (*AChoreographer_extendedFrameCallback)(
+typedef void (*AChoreographer_vsyncCallback)(
         const AChoreographerFrameCallbackData* callbackData, void* data);
 
 /**
@@ -134,8 +134,8 @@
  * Posts a callback to run on the next frame. The data pointer provided will
  * be passed to the callback function when it's called.
  */
-void AChoreographer_postExtendedFrameCallback(AChoreographer* choreographer,
-                                        AChoreographer_extendedFrameCallback callback, void* data)
+void AChoreographer_postVsyncCallback(AChoreographer* choreographer,
+                                        AChoreographer_vsyncCallback callback, void* data)
         __INTRODUCED_IN(33);
 
 /**
@@ -215,7 +215,7 @@
 /**
  * The time in nanoseconds which the frame at given index is expected to be presented.
  */
-int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos(
+int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(
         const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
 
 /**
diff --git a/include/android/input.h b/include/android/input.h
index e6ad943f..fb5e204 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -808,6 +808,33 @@
 };
 
 /**
+ * Constants that identify different gesture classification types.
+ */
+enum {
+    /**
+     * Classification constant: None.
+     *
+     * No additional information is available about the current motion event stream.
+     */
+    AMOTION_EVENT_CLASSIFICATION_NONE = 0,
+    /**
+     * Classification constant: Ambiguous gesture.
+     *
+     * The user's intent with respect to the current event stream is not yet determined.
+     * Gestural actions, such as scrolling, should be inhibited until the classification resolves
+     * to another value or the event stream ends.
+     */
+    AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE = 1,
+    /**
+     * Classification constant: Deep press.
+     *
+     * The current event stream represents the user intentionally pressing harder on the screen.
+     * This classification type should be used to accelerate the long press behaviour.
+     */
+    AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS = 2,
+};
+
+/**
  * Input source masks.
  *
  * Refer to the documentation on android.view.InputDevice for more details about input sources
@@ -1327,6 +1354,23 @@
         int32_t axis, size_t pointer_index, size_t history_index);
 
 /**
+ * Get the action button for the motion event. Returns a valid action button when the
+ * event is associated with a button press or button release action. For other actions
+ * the return value is undefined.
+ */
+int32_t AMotionEvent_getActionButton(const AInputEvent* motion_event);
+
+/**
+ * Returns the classification for the current gesture.
+ * The classification may change as more events become available for the same gesture.
+ *
+ * @see #AMOTION_EVENT_CLASSIFICATION_NONE
+ * @see #AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE
+ * @see #AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS
+*/
+int32_t AMotionEvent_getClassification(const AInputEvent* motion_event);
+
+/**
  * Creates a native AInputEvent* object that is a copy of the specified Java
  * android.view.MotionEvent. The result may be used with generic and MotionEvent-specific
  * AInputEvent_* functions. The object returned by this function must be disposed using
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/include/ftl/details/array_traits.h b/include/ftl/details/array_traits.h
index 16e63ec..5234c38 100644
--- a/include/ftl/details/array_traits.h
+++ b/include/ftl/details/array_traits.h
@@ -42,7 +42,7 @@
   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
 
   template <typename... Args>
-  static pointer construct_at(const_iterator it, Args&&... args) {
+  static constexpr pointer construct_at(const_iterator it, Args&&... args) {
     void* const ptr = const_cast<void*>(static_cast<const void*>(it));
     if constexpr (std::is_constructible_v<value_type, Args...>) {
       // TODO: Replace with std::construct_at in C++20.
@@ -52,6 +52,42 @@
       return new (ptr) value_type{std::forward<Args>(args)...};
     }
   }
+
+  // TODO: Make constexpr in C++20.
+  template <typename... Args>
+  static reference replace_at(const_iterator it, Args&&... args) {
+    value_type element{std::forward<Args>(args)...};
+    return replace_at(it, std::move(element));
+  }
+
+  // TODO: Make constexpr in C++20.
+  static reference replace_at(const_iterator it, value_type&& value) {
+    std::destroy_at(it);
+    // This is only safe because exceptions are disabled.
+    return *construct_at(it, std::move(value));
+  }
+
+  // TODO: Make constexpr in C++20.
+  static void in_place_swap(reference a, reference b) {
+    value_type c{std::move(a)};
+    replace_at(&a, std::move(b));
+    replace_at(&b, std::move(c));
+  }
+
+  // TODO: Make constexpr in C++20.
+  static void in_place_swap_ranges(iterator first1, iterator last1, iterator first2) {
+    while (first1 != last1) {
+      in_place_swap(*first1++, *first2++);
+    }
+  }
+
+  // TODO: Replace with std::uninitialized_copy in C++20.
+  template <typename Iterator>
+  static void uninitialized_copy(Iterator first, Iterator last, const_iterator out) {
+    while (first != last) {
+      construct_at(out++, *first++);
+    }
+  }
 };
 
 // CRTP mixin to define iterator functions in terms of non-const Self::begin and Self::end.
@@ -101,33 +137,33 @@
 // TODO: Replace with operator<=> in C++20.
 template <template <typename, std::size_t> class Array>
 struct ArrayComparators {
-  template <typename T, std::size_t N, std::size_t M>
-  friend bool operator==(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+  template <typename T, typename U, std::size_t N, std::size_t M>
+  friend bool operator==(const Array<T, N>& lhs, const Array<U, M>& rhs) {
     return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
   }
 
-  template <typename T, std::size_t N, std::size_t M>
-  friend bool operator<(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+  template <typename T, typename U, std::size_t N, std::size_t M>
+  friend bool operator<(const Array<T, N>& lhs, const Array<U, M>& rhs) {
     return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
   }
 
-  template <typename T, std::size_t N, std::size_t M>
-  friend bool operator>(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+  template <typename T, typename U, std::size_t N, std::size_t M>
+  friend bool operator>(const Array<T, N>& lhs, const Array<U, M>& rhs) {
     return rhs < lhs;
   }
 
-  template <typename T, std::size_t N, std::size_t M>
-  friend bool operator!=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+  template <typename T, typename U, std::size_t N, std::size_t M>
+  friend bool operator!=(const Array<T, N>& lhs, const Array<U, M>& rhs) {
     return !(lhs == rhs);
   }
 
-  template <typename T, std::size_t N, std::size_t M>
-  friend bool operator>=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+  template <typename T, typename U, std::size_t N, std::size_t M>
+  friend bool operator>=(const Array<T, N>& lhs, const Array<U, M>& rhs) {
     return !(lhs < rhs);
   }
 
-  template <typename T, std::size_t N, std::size_t M>
-  friend bool operator<=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+  template <typename T, typename U, std::size_t N, std::size_t M>
+  friend bool operator<=(const Array<T, N>& lhs, const Array<U, M>& rhs) {
     return !(lhs > rhs);
   }
 };
diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h
index 2effaa4..5217e76 100644
--- a/include/ftl/small_map.h
+++ b/include/ftl/small_map.h
@@ -65,6 +65,9 @@
 class SmallMap final {
   using Map = SmallVector<std::pair<const K, V>, N>;
 
+  template <typename, typename, std::size_t, typename>
+  friend class SmallMap;
+
  public:
   using key_type = K;
   using mapped_type = V;
@@ -100,6 +103,10 @@
     deduplicate();
   }
 
+  // Copies or moves key-value pairs from a convertible map.
+  template <typename Q, typename W, std::size_t M, typename E>
+  SmallMap(SmallMap<Q, W, M, E> other) : map_(std::move(other.map_)) {}
+
   size_type max_size() const { return map_.max_size(); }
   size_type size() const { return map_.size(); }
   bool empty() const { return map_.empty(); }
diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h
index 03587e3..339726e 100644
--- a/include/ftl/small_vector.h
+++ b/include/ftl/small_vector.h
@@ -37,6 +37,9 @@
 // augmented by an unstable_erase operation that does not preserve order, and a replace operation
 // that destructively emplaces.
 //
+// Unlike std::vector, T does not require copy/move assignment, so may be an object with const data
+// members, or be const itself.
+//
 // SmallVector<T, 0> is a specialization that thinly wraps std::vector.
 //
 // Example usage:
@@ -105,10 +108,9 @@
   SmallVector(Arg&& arg, Args&&... args)
       : vector_(std::in_place_type<Static>, std::forward<Arg>(arg), std::forward<Args>(args)...) {}
 
-  // Copies at most N elements from a smaller convertible vector.
-  template <typename U, std::size_t M, typename = std::enable_if_t<M <= N>>
-  SmallVector(const SmallVector<U, M>& other)
-      : SmallVector(kIteratorRange, other.begin(), other.end()) {}
+  // Copies or moves elements from a smaller convertible vector.
+  template <typename U, std::size_t M, typename = std::enable_if_t<(M > 0)>>
+  SmallVector(SmallVector<U, M> other) : vector_(convert(std::move(other))) {}
 
   void swap(SmallVector& other) { vector_.swap(other.vector_); }
 
@@ -235,7 +237,30 @@
     }
   }
 
+  // Extracts the elements as std::vector.
+  std::vector<T> promote() && {
+    if (dynamic()) {
+      return std::get<Dynamic>(std::move(vector_)).promote();
+    } else {
+      return {std::make_move_iterator(begin()), std::make_move_iterator(end())};
+    }
+  }
+
  private:
+  template <typename, std::size_t>
+  friend class SmallVector;
+
+  template <typename U, std::size_t M>
+  static std::variant<Static, Dynamic> convert(SmallVector<U, M>&& other) {
+    using Other = SmallVector<U, M>;
+
+    if (other.dynamic()) {
+      return std::get<typename Other::Dynamic>(std::move(other.vector_));
+    } else {
+      return std::get<typename Other::Static>(std::move(other.vector_));
+    }
+  }
+
   template <auto InsertStatic, auto InsertDynamic, typename... Args>
   auto insert(Args&&... args) {
     if (Dynamic* const vector = std::get_if<Dynamic>(&vector_)) {
@@ -267,9 +292,10 @@
 // Partial specialization without static storage.
 template <typename T>
 class SmallVector<T, 0> final : details::ArrayTraits<T>,
+                                details::ArrayComparators<SmallVector>,
                                 details::ArrayIterators<SmallVector<T, 0>, T>,
                                 std::vector<T> {
-  using details::ArrayTraits<T>::construct_at;
+  using details::ArrayTraits<T>::replace_at;
 
   using Iter = details::ArrayIterators<SmallVector, T>;
   using Impl = std::vector<T>;
@@ -291,8 +317,30 @@
   FTL_ARRAY_TRAIT(T, const_iterator);
   FTL_ARRAY_TRAIT(T, const_reverse_iterator);
 
+  // See std::vector for underlying constructors.
   using Impl::Impl;
 
+  // Copies and moves a vector, respectively.
+  SmallVector(const SmallVector&) = default;
+  SmallVector(SmallVector&&) = default;
+
+  // Constructs elements in place. See StaticVector for underlying constructor.
+  template <typename U, std::size_t... Sizes, typename... Types>
+  SmallVector(InitializerList<U, std::index_sequence<Sizes...>, Types...>&& list)
+      : SmallVector(SmallVector<T, sizeof...(Sizes)>(std::move(list))) {}
+
+  // Copies or moves elements from a convertible vector.
+  template <typename U, std::size_t M>
+  SmallVector(SmallVector<U, M> other) : Impl(convert(std::move(other))) {}
+
+  SmallVector& operator=(SmallVector other) {
+    // Define copy/move assignment in terms of copy/move construction.
+    swap(other);
+    return *this;
+  }
+
+  void swap(SmallVector& other) { Impl::swap(other); }
+
   using Impl::empty;
   using Impl::max_size;
   using Impl::size;
@@ -324,10 +372,7 @@
 
   template <typename... Args>
   reference replace(const_iterator it, Args&&... args) {
-    value_type element{std::forward<Args>(args)...};
-    std::destroy_at(it);
-    // This is only safe because exceptions are disabled.
-    return *construct_at(it, std::move(element));
+    return replace_at(it, std::forward<Args>(args)...);
   }
 
   template <typename... Args>
@@ -353,7 +398,26 @@
     pop_back();
   }
 
-  void swap(SmallVector& other) { Impl::swap(other); }
+  std::vector<T> promote() && { return std::move(*this); }
+
+ private:
+  template <typename U, std::size_t M>
+  static Impl convert(SmallVector<U, M>&& other) {
+    if constexpr (std::is_constructible_v<Impl, std::vector<U>&&>) {
+      return std::move(other).promote();
+    } else {
+      SmallVector vector(other.size());
+
+      // Consistently with StaticVector, T only requires copy/move construction from U, rather than
+      // copy/move assignment.
+      auto it = vector.begin();
+      for (auto& element : other) {
+        vector.replace(it++, std::move(element));
+      }
+
+      return vector;
+    }
+  }
 };
 
 template <typename>
diff --git a/include/ftl/static_vector.h b/include/ftl/static_vector.h
index b7f8c29..eb83b85 100644
--- a/include/ftl/static_vector.h
+++ b/include/ftl/static_vector.h
@@ -39,6 +39,9 @@
 // adheres to standard containers, except the unstable_erase operation that does not preserve order,
 // and the replace operation that destructively emplaces.
 //
+// Unlike std::vector, T does not require copy/move assignment, so may be an object with const data
+// members, or be const itself.
+//
 // StaticVector<T, 1> is analogous to an iterable std::optional.
 // StaticVector<T, 0> is an error.
 //
@@ -78,7 +81,14 @@
                            details::ArrayComparators<StaticVector> {
   static_assert(N > 0);
 
+  // For constructor that moves from a smaller convertible vector.
+  template <typename, std::size_t>
+  friend class StaticVector;
+
   using details::ArrayTraits<T>::construct_at;
+  using details::ArrayTraits<T>::replace_at;
+  using details::ArrayTraits<T>::in_place_swap_ranges;
+  using details::ArrayTraits<T>::uninitialized_copy;
 
   using Iter = details::ArrayIterators<StaticVector, T>;
   friend Iter;
@@ -117,14 +127,18 @@
   StaticVector(StaticVector&& other) { swap<true>(other); }
 
   // Copies at most N elements from a smaller convertible vector.
-  template <typename U, std::size_t M, typename = std::enable_if_t<M <= N>>
+  template <typename U, std::size_t M>
   StaticVector(const StaticVector<U, M>& other)
-      : StaticVector(kIteratorRange, other.begin(), other.end()) {}
+      : StaticVector(kIteratorRange, other.begin(), other.end()) {
+    static_assert(N >= M, "Insufficient capacity");
+  }
 
-  // Copies at most N elements from an array.
+  // Copies at most N elements from a smaller convertible array.
   template <typename U, std::size_t M>
   explicit StaticVector(U (&array)[M])
-      : StaticVector(kIteratorRange, std::begin(array), std::end(array)) {}
+      : StaticVector(kIteratorRange, std::begin(array), std::end(array)) {
+    static_assert(N >= M, "Insufficient capacity");
+  }
 
   // Copies at most N elements from the range [first, last).
   //
@@ -139,7 +153,18 @@
   template <typename Iterator>
   StaticVector(IteratorRangeTag, Iterator first, Iterator last)
       : size_(std::min(max_size(), static_cast<size_type>(std::distance(first, last)))) {
-    std::uninitialized_copy(first, first + size_, begin());
+    uninitialized_copy(first, first + size_, begin());
+  }
+
+  // Moves at most N elements from a smaller convertible vector.
+  template <typename U, std::size_t M>
+  StaticVector(StaticVector<U, M>&& other) {
+    static_assert(N >= M, "Insufficient capacity");
+
+    // Same logic as swap<true>, though M need not be equal to N.
+    std::uninitialized_move(other.begin(), other.end(), begin());
+    std::destroy(other.begin(), other.end());
+    std::swap(size_, other.size_);
   }
 
   // Constructs at most N elements. The template arguments T and N are inferred using the
@@ -178,7 +203,9 @@
   template <typename U, std::size_t Size, std::size_t... Sizes, typename... Types>
   StaticVector(InitializerList<U, std::index_sequence<Size, Sizes...>, Types...>&& list)
       : StaticVector(std::index_sequence<0, 0, Size>{}, std::make_index_sequence<Size>{},
-                     std::index_sequence<Sizes...>{}, list.tuple) {}
+                     std::index_sequence<Sizes...>{}, list.tuple) {
+    static_assert(sizeof...(Sizes) < N, "Too many elements");
+  }
 
   ~StaticVector() { std::destroy(begin(), end()); }
 
@@ -238,10 +265,7 @@
   //
   template <typename... Args>
   reference replace(const_iterator it, Args&&... args) {
-    value_type element{std::forward<Args>(args)...};
-    std::destroy_at(it);
-    // This is only safe because exceptions are disabled.
-    return *construct_at(it, std::move(element));
+    return replace_at(it, std::forward<Args>(args)...);
   }
 
   // Appends an element, and returns an iterator to it. If the vector is full, the element is not
@@ -380,7 +404,7 @@
     }
 
     // Swap elements [0, min).
-    std::swap_ranges(begin(), begin() + min, other.begin());
+    in_place_swap_ranges(begin(), begin() + min, other.begin());
 
     // No elements to move if sizes are equal.
     if (min == max) return;
diff --git a/include/input/Input.h b/include/input/Input.h
index e421dee..b23a951 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -275,23 +275,21 @@
 
 /**
  * Classifications of the current gesture, if available.
- *
- * The following values must be kept in sync with MotionEvent.java
  */
 enum class MotionClassification : uint8_t {
     /**
      * No classification is available.
      */
-    NONE = 0,
+    NONE = AMOTION_EVENT_CLASSIFICATION_NONE,
     /**
      * Too early to classify the current gesture. Need more events. Look for changes in the
      * upcoming motion events.
      */
-    AMBIGUOUS_GESTURE = 1,
+    AMBIGUOUS_GESTURE = AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE,
     /**
      * The current gesture likely represents a user intentionally exerting force on the touchscreen.
      */
-    DEEP_PRESS = 2,
+    DEEP_PRESS = AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS,
 };
 
 /**
@@ -816,6 +814,8 @@
     static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy);
     static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&,
                                                const PointerCoords&);
+    static PointerCoords calculateTransformedCoords(uint32_t source, const ui::Transform&,
+                                                    const PointerCoords&);
 
 protected:
     int32_t mAction;
diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp
index 406fee0..1504715 100644
--- a/libs/binder/PersistableBundle.cpp
+++ b/libs/binder/PersistableBundle.cpp
@@ -27,13 +27,6 @@
 
 #include "ParcelValTypes.h"
 
-using android::BAD_TYPE;
-using android::BAD_VALUE;
-using android::NO_ERROR;
-using android::Parcel;
-using android::status_t;
-using android::UNEXPECTED_NULL;
-
 using android::binder::VAL_BOOLEAN;
 using android::binder::VAL_INTEGER;
 using android::binder::VAL_LONG;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 1821729..baa817c 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -19,6 +19,7 @@
 #include <binder/ProcessState.h>
 
 #include <android-base/result.h>
+#include <android-base/strings.h>
 #include <binder/BpBinder.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -367,8 +368,13 @@
 String8 ProcessState::makeBinderThreadName() {
     int32_t s = android_atomic_add(1, &mThreadPoolSeq);
     pid_t pid = getpid();
+
+    std::string_view driverName = mDriverName.c_str();
+    android::base::ConsumePrefix(&driverName, "/dev/");
+
     String8 name;
-    name.appendFormat("%d_%X:%s", pid, s, mDriverName.c_str());
+    name.appendFormat("%.*s:%d_%X", static_cast<int>(driverName.length()), driverName.data(), pid,
+                      s);
     return name;
 }
 
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 1d7de98..dbfb1c2 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -114,8 +114,8 @@
 };
 pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
 pub use proxy::{
-    get_interface, get_service, wait_for_interface, wait_for_service, DeathRecipient, SpIBinder,
-    WpIBinder,
+    get_declared_instances, get_interface, get_service, is_declared, wait_for_interface,
+    wait_for_service, DeathRecipient, SpIBinder, WpIBinder,
 };
 pub use state::{ProcessState, ThreadState};
 
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 12bfde7..e3e4730 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -28,9 +28,10 @@
 
 use std::cmp::Ordering;
 use std::convert::TryInto;
-use std::ffi::{c_void, CString};
+use std::ffi::{c_void, CStr, CString};
 use std::fmt;
 use std::mem;
+use std::os::raw::c_char;
 use std::os::unix::io::AsRawFd;
 use std::ptr;
 use std::sync::Arc;
@@ -778,6 +779,61 @@
     }
 }
 
+/// Check if a service is declared (e.g. in a VINTF manifest)
+pub fn is_declared(interface: &str) -> Result<bool> {
+    let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
+
+    unsafe {
+        // Safety: `interface` is a valid null-terminated C-style string and is
+        // only borrowed for the lifetime of the call. The `interface` local
+        // outlives this call as it lives for the function scope.
+        Ok(sys::AServiceManager_isDeclared(interface.as_ptr()))
+    }
+}
+
+/// Retrieve all declared instances for a particular interface
+///
+/// For instance, if 'android.foo.IFoo/foo' is declared, and 'android.foo.IFoo'
+/// is passed here, then ["foo"] would be returned.
+pub fn get_declared_instances(interface: &str) -> Result<Vec<String>> {
+    unsafe extern "C" fn callback(instance: *const c_char, opaque: *mut c_void) {
+        // Safety: opaque was a mutable pointer created below from a Vec of
+        // CString, and outlives this callback. The null handling here is just
+        // to avoid the possibility of unwinding across C code if this crate is
+        // ever compiled with panic=unwind.
+        if let Some(instances) = opaque.cast::<Vec<CString>>().as_mut() {
+            // Safety: instance is a valid null-terminated C string with a
+            // lifetime at least as long as this function, and we immediately
+            // copy it into an owned CString.
+            instances.push(CStr::from_ptr(instance).to_owned());
+        } else {
+            eprintln!("Opaque pointer was null in get_declared_instances callback!");
+        }
+    }
+
+    let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
+    let mut instances: Vec<CString> = vec![];
+    unsafe {
+        // Safety: `interface` and `instances` are borrowed for the length of
+        // this call and both outlive the call. `interface` is guaranteed to be
+        // a valid null-terminated C-style string.
+        sys::AServiceManager_forEachDeclaredInstance(
+            interface.as_ptr(),
+            &mut instances as *mut _ as *mut c_void,
+            Some(callback),
+        );
+    }
+
+    instances
+        .into_iter()
+        .map(CString::into_string)
+        .collect::<std::result::Result<Vec<String>, _>>()
+        .map_err(|e| {
+            eprintln!("An interface instance name was not a valid UTF-8 string: {}", e);
+            StatusCode::BAD_VALUE
+        })
+}
+
 /// # Safety
 ///
 /// `SpIBinder` guarantees that `binder` always contains a valid pointer to an
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 50daf1c..7c5afde 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -484,6 +484,21 @@
     }
 
     #[test]
+    fn get_declared_instances() {
+        // At the time of writing this test, there is no good VINTF interface
+        // guaranteed to be on all devices. Cuttlefish has light, so this will
+        // generally test things.
+        let has_lights = binder::is_declared("android.hardware.light.ILights/default")
+            .expect("Could not check for declared interface");
+
+        let instances = binder::get_declared_instances("android.hardware.light.ILights")
+            .expect("Could not get declared instances");
+
+        let expected_defaults = if has_lights { 1 } else { 0 };
+        assert_eq!(expected_defaults, instances.iter().filter(|i| i.as_str() == "default").count());
+    }
+
+    #[test]
     fn trivial_client() {
         let service_name = "trivial_client_test";
         let _process = ScopedServiceProcess::new(service_name);
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 1446802..38bde3a 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -26,13 +26,9 @@
     static_libs: [
         "libbase",
         "libbinder_random_parcel",
-        "libcgrouprc",
-        "libcgrouprc_format",
         "libcutils",
         "libhidlbase",
         "liblog",
-        "libprocessgroup",
-        "libjsoncpp",
         "libutils",
     ],
 
diff --git a/libs/ftl/small_map_test.cpp b/libs/ftl/small_map_test.cpp
index ee650e5..1740a2b 100644
--- a/libs/ftl/small_map_test.cpp
+++ b/libs/ftl/small_map_test.cpp
@@ -96,6 +96,33 @@
   }
 }
 
+TEST(SmallMap, Assign) {
+  {
+    // Same types; smaller capacity.
+    SmallMap map1 = ftl::init::map<char, std::string>('k', "kilo")('M', "mega")('G', "giga");
+    const SmallMap map2 = ftl::init::map('T', "tera"s)('P', "peta"s);
+
+    map1 = map2;
+    EXPECT_EQ(map1, map2);
+  }
+  {
+    // Convertible types; same capacity.
+    SmallMap map1 = ftl::init::map<char, std::string>('M', "mega")('G', "giga");
+    const SmallMap map2 = ftl::init::map('T', "tera")('P', "peta");
+
+    map1 = map2;
+    EXPECT_EQ(map1, map2);
+  }
+  {
+    // Convertible types; zero capacity.
+    SmallMap<char, std::string, 0> map1 = ftl::init::map('M', "mega")('G', "giga");
+    const SmallMap<char, std::string, 0> map2 = ftl::init::map('T', "tera")('P', "peta");
+
+    map1 = map2;
+    EXPECT_EQ(map1, map2);
+  }
+}
+
 TEST(SmallMap, UniqueKeys) {
   {
     // Duplicate mappings are discarded.
diff --git a/libs/ftl/small_vector_test.cpp b/libs/ftl/small_vector_test.cpp
index 4237496..b662a81 100644
--- a/libs/ftl/small_vector_test.cpp
+++ b/libs/ftl/small_vector_test.cpp
@@ -138,6 +138,116 @@
   }
 }
 
+TEST(SmallVector, Copy) {
+  {
+    // Same capacity.
+    const SmallVector vector = {"snow"s, "cone"s};
+
+    SmallVector<const std::string, 2> copy(vector);
+    EXPECT_EQ(copy, vector);
+
+    // The vector is assignable even if T is const.
+    const SmallVector<std::string, 2> other = {"tiramisu"s};
+    copy = other;
+    EXPECT_EQ(copy, other);
+  }
+  {
+    // From smaller capacity.
+    const SmallVector vector = {"snow"s, "cone"s};
+
+    SmallVector<const std::string, 3> copy(vector);
+    EXPECT_EQ(copy, vector);
+
+    // The vector is assignable even if T is const.
+    const SmallVector other = {"tiramisu"s};
+    copy = other;
+    EXPECT_EQ(copy, other);
+  }
+  {
+    // To zero capacity.
+    const SmallVector vector = {"snow"s, "cone"s};
+
+    SmallVector<const std::string, 0> copy(vector);
+    EXPECT_EQ(copy, vector);
+
+    // The vector is assignable even if T is const.
+    const SmallVector other = {"tiramisu"s};
+    copy = other;
+    EXPECT_EQ(copy, other);
+  }
+  {
+    // From/to zero capacity.
+    const SmallVector<std::string, 0> vector = {"snow"s, "cone"s};
+
+    SmallVector<const std::string, 0> copy(vector);
+    EXPECT_EQ(copy, vector);
+
+    // The vector is assignable even if T is const.
+    const SmallVector<std::string, 0> other = {"tiramisu"s};
+    copy = other;
+    EXPECT_EQ(copy, other);
+  }
+}
+
+TEST(SmallVector, Move) {
+  {
+    // Same capacity.
+    SmallVector vector = {"snow"s, "cone"s};
+
+    SmallVector<const std::string, 2> move(std::move(vector));
+    EXPECT_TRUE(vector.empty());
+    EXPECT_EQ(move, (SmallVector{"snow"s, "cone"s}));
+
+    // The vector is assignable even if T is const.
+    SmallVector<std::string, 2> other = {"tiramisu"s};
+    move = std::move(other);
+    EXPECT_TRUE(other.empty());
+    EXPECT_EQ(move, (SmallVector{"tiramisu"s}));
+  }
+  {
+    // From smaller capacity.
+    SmallVector vector = {"snow"s, "cone"s};
+
+    SmallVector<const std::string, 3> move(std::move(vector));
+    EXPECT_TRUE(vector.empty());
+    EXPECT_EQ(move, (SmallVector{"snow"s, "cone"s}));
+
+    // The vector is assignable even if T is const.
+    SmallVector other = {"tiramisu"s};
+    move = std::move(other);
+    EXPECT_TRUE(other.empty());
+    EXPECT_EQ(move, (SmallVector{"tiramisu"s}));
+  }
+  {
+    // To zero capacity.
+    SmallVector vector = {"snow"s, "cone"s};
+
+    SmallVector<const std::string, 0> move(std::move(vector));
+    EXPECT_TRUE(vector.empty());
+    EXPECT_EQ(move, (SmallVector{"snow"s, "cone"s}));
+
+    // The vector is assignable even if T is const.
+    SmallVector other = {"tiramisu"s};
+    move = std::move(other);
+    EXPECT_TRUE(other.empty());
+    EXPECT_EQ(move, (SmallVector{"tiramisu"s}));
+  }
+  {
+    // From/to zero capacity.
+    SmallVector<std::string, 0> vector = {"snow"s, "cone"s};
+
+    SmallVector<const std::string, 0> move(std::move(vector));
+    EXPECT_TRUE(vector.empty());
+    EXPECT_EQ(move, (SmallVector{"snow"s, "cone"s}));
+
+    // The vector is assignable even if T is const.
+    SmallVector<std::string, 0> other = {"tiramisu"s};
+    move = std::move(other);
+    EXPECT_TRUE(other.empty());
+    EXPECT_EQ(move, (SmallVector{"tiramisu"s}));
+  }
+}
+
 TEST(SmallVector, String) {
   SmallVector<char, 10> chars;
   char c = 'a';
@@ -366,21 +476,20 @@
   bool alive = true;
 };
 
-void swap(DestroyCounts& lhs, DestroyCounts& rhs) {
-  std::swap(lhs.alive, rhs.alive);
-}
-
 }  // namespace
 
 TEST(SmallVector, Destroy) {
   int live = 0;
   int dead = 0;
-
-  { SmallVector<DestroyCounts, 3> counts; }
+  {
+    // Empty.
+    SmallVector<DestroyCounts, 3> counts;
+  }
   EXPECT_EQ(0, live);
   EXPECT_EQ(0, dead);
 
   {
+    // Static.
     SmallVector<DestroyCounts, 3> counts;
     counts.emplace_back(live, dead);
     counts.emplace_back(live, dead);
@@ -393,6 +502,7 @@
 
   live = 0;
   {
+    // Dynamic.
     SmallVector<DestroyCounts, 3> counts;
     counts.emplace_back(live, dead);
     counts.emplace_back(live, dead);
@@ -406,12 +516,13 @@
 
   live = dead = 0;
   {
+    // Copy.
     SmallVector<DestroyCounts, 2> counts;
     counts.emplace_back(live, dead);
     counts.emplace_back(live, dead);
     counts.emplace_back(live, dead);
 
-    auto copy = counts;
+    const auto copy = counts;
     EXPECT_TRUE(copy.dynamic());
   }
   EXPECT_EQ(6, live);
@@ -419,12 +530,13 @@
 
   live = dead = 0;
   {
+    // Move.
     SmallVector<DestroyCounts, 2> counts;
     counts.emplace_back(live, dead);
     counts.emplace_back(live, dead);
     counts.emplace_back(live, dead);
 
-    auto move = std::move(counts);
+    const auto move = std::move(counts);
     EXPECT_TRUE(move.dynamic());
   }
   EXPECT_EQ(3, live);
@@ -432,6 +544,7 @@
 
   live = dead = 0;
   {
+    // Swap.
     SmallVector<DestroyCounts, 2> counts1;
     counts1.emplace_back(live, dead);
     counts1.emplace_back(live, dead);
@@ -448,7 +561,10 @@
 
     swap(counts1, counts2);
 
+    EXPECT_EQ(1u, counts1.size());
     EXPECT_FALSE(counts1.dynamic());
+
+    EXPECT_EQ(3u, counts2.size());
     EXPECT_TRUE(counts2.dynamic());
 
     EXPECT_EQ(0, live);
@@ -465,29 +581,82 @@
   int dead = 0;
 
   SmallVector<DestroyCounts, 2> counts;
-  counts.emplace_back(live, dead);
-  counts.emplace_back(live, dead);
+  {
+    // Static.
+    counts.emplace_back(live, dead);
+    counts.emplace_back(live, dead);
 
-  counts.clear();
+    counts.clear();
 
-  EXPECT_TRUE(counts.empty());
-  EXPECT_FALSE(counts.dynamic());
-
+    EXPECT_TRUE(counts.empty());
+    EXPECT_FALSE(counts.dynamic());
+  }
   EXPECT_EQ(2, live);
   EXPECT_EQ(0, dead);
 
   live = 0;
-  counts.emplace_back(live, dead);
-  counts.emplace_back(live, dead);
-  counts.emplace_back(live, dead);
+  {
+    // Dynamic.
+    counts.emplace_back(live, dead);
+    counts.emplace_back(live, dead);
+    counts.emplace_back(live, dead);
 
-  counts.clear();
+    counts.clear();
 
-  EXPECT_TRUE(counts.empty());
-  EXPECT_TRUE(counts.dynamic());
-
+    EXPECT_TRUE(counts.empty());
+    EXPECT_TRUE(counts.dynamic());
+  }
   EXPECT_EQ(3, live);
   EXPECT_EQ(2, dead);
 }
 
+TEST(SmallVector, Promote) {
+  {
+    const std::vector vector = {"snow"s, "cone"s};
+    EXPECT_EQ(vector, SmallVector("snow"s, "cone"s).promote());
+    EXPECT_EQ(vector, (SmallVector<std::string, 0>({"snow"s, "cone"s}).promote()));
+  }
+
+  int live = 0;
+  int dead = 0;
+
+  std::vector<DestroyCounts> vector;
+  {
+    // Static.
+    SmallVector<DestroyCounts, 3> counts;
+    counts.emplace_back(live, dead);
+    counts.emplace_back(live, dead);
+
+    vector = std::move(counts).promote();
+
+    ASSERT_EQ(2u, vector.size());
+    EXPECT_TRUE(vector[0].alive);
+    EXPECT_TRUE(vector[1].alive);
+  }
+  EXPECT_EQ(0, live);
+  EXPECT_EQ(2, dead);
+
+  vector.clear();
+  live = dead = 0;
+  {
+    // Dynamic.
+    SmallVector<DestroyCounts, 2> counts;
+    counts.emplace_back(live, dead);
+    counts.emplace_back(live, dead);
+    counts.emplace_back(live, dead);
+
+    EXPECT_EQ(2, dead);
+    dead = 0;
+
+    vector = std::move(counts).promote();
+
+    ASSERT_EQ(3u, vector.size());
+    EXPECT_TRUE(vector[0].alive);
+    EXPECT_TRUE(vector[1].alive);
+    EXPECT_TRUE(vector[2].alive);
+  }
+  EXPECT_EQ(0, live);
+  EXPECT_EQ(0, dead);
+}
+
 }  // namespace android::test
diff --git a/libs/ftl/static_vector_test.cpp b/libs/ftl/static_vector_test.cpp
index 2de3ad2..0e10a5d 100644
--- a/libs/ftl/static_vector_test.cpp
+++ b/libs/ftl/static_vector_test.cpp
@@ -144,6 +144,64 @@
   }
 }
 
+TEST(StaticVector, Copy) {
+  {
+    // Same capacity.
+    const StaticVector vector = {"snow"s, "cone"s};
+
+    StaticVector<const std::string, 2> copy(vector);
+    EXPECT_EQ(copy, vector);
+
+    // The vector is assignable even if T is const.
+    const StaticVector<std::string, 2> other = {"tiramisu"s};
+    copy = other;
+    EXPECT_EQ(copy, other);
+  }
+  {
+    // From smaller capacity.
+    const StaticVector vector = {"snow"s, "cone"s};
+
+    StaticVector<const std::string, 3> copy(vector);
+    EXPECT_EQ(copy, vector);
+
+    // The vector is assignable even if T is const.
+    const StaticVector other = {"tiramisu"s};
+    copy = other;
+    EXPECT_EQ(copy, other);
+  }
+}
+
+TEST(StaticVector, Move) {
+  {
+    // Same capacity.
+    StaticVector vector = {"snow"s, "cone"s};
+
+    StaticVector<const std::string, 2> move(std::move(vector));
+    EXPECT_TRUE(vector.empty());
+    EXPECT_EQ(move, (StaticVector{"snow"s, "cone"s}));
+
+    // The vector is assignable even if T is const.
+    StaticVector<std::string, 2> other = {"tiramisu"s};
+    move = std::move(other);
+    EXPECT_TRUE(other.empty());
+    EXPECT_EQ(move, (StaticVector{"tiramisu"s}));
+  }
+  {
+    // From smaller capacity.
+    StaticVector vector = {"snow"s, "cone"s};
+
+    StaticVector<const std::string, 3> move(std::move(vector));
+    EXPECT_TRUE(vector.empty());
+    EXPECT_EQ(move, (StaticVector{"snow"s, "cone"s}));
+
+    // The vector is assignable even if T is const.
+    StaticVector other = {"tiramisu"s};
+    move = std::move(other);
+    EXPECT_TRUE(other.empty());
+    EXPECT_EQ(move, (StaticVector{"tiramisu"s}));
+  }
+}
+
 TEST(StaticVector, String) {
   StaticVector<char, 10> chars;
   char c = 'a';
@@ -328,21 +386,20 @@
   bool alive = true;
 };
 
-void swap(DestroyCounts& lhs, DestroyCounts& rhs) {
-  std::swap(lhs.alive, rhs.alive);
-}
-
 }  // namespace
 
 TEST(StaticVector, Destroy) {
   int live = 0;
   int dead = 0;
-
-  { StaticVector<DestroyCounts, 5> counts; }
+  {
+    // Empty.
+    StaticVector<DestroyCounts, 5> counts;
+  }
   EXPECT_EQ(0, live);
   EXPECT_EQ(0, dead);
 
   {
+    // Non-empty.
     StaticVector<DestroyCounts, 5> counts;
     counts.emplace_back(live, dead);
     counts.emplace_back(live, dead);
@@ -353,30 +410,33 @@
 
   live = 0;
   {
+    // Copy.
     StaticVector<DestroyCounts, 5> counts;
     counts.emplace_back(live, dead);
     counts.emplace_back(live, dead);
     counts.emplace_back(live, dead);
 
-    auto copy = counts;
+    const auto copy = counts;
   }
   EXPECT_EQ(6, live);
   EXPECT_EQ(0, dead);
 
   live = 0;
   {
+    // Move.
     StaticVector<DestroyCounts, 5> counts;
     counts.emplace_back(live, dead);
     counts.emplace_back(live, dead);
     counts.emplace_back(live, dead);
 
-    auto move = std::move(counts);
+    const auto move = std::move(counts);
   }
   EXPECT_EQ(3, live);
   EXPECT_EQ(3, dead);
 
   live = dead = 0;
   {
+    // Swap.
     StaticVector<DestroyCounts, 5> counts1;
     counts1.emplace_back(live, dead);
     counts1.emplace_back(live, dead);
@@ -384,29 +444,34 @@
 
     StaticVector<DestroyCounts, 5> counts2;
     counts2.emplace_back(live, dead);
+    counts2.emplace_back(live, dead);
 
     swap(counts1, counts2);
 
+    EXPECT_EQ(2u, counts1.size());
+    EXPECT_EQ(3u, counts2.size());
+
     EXPECT_EQ(0, live);
-    EXPECT_EQ(2, dead);
+    EXPECT_EQ(7, dead);  // 3 moves per swap, plus 1 move.
 
     dead = 0;
   }
-  EXPECT_EQ(4, live);
+  EXPECT_EQ(5, live);
   EXPECT_EQ(0, dead);
 }
 
 TEST(StaticVector, Clear) {
   int live = 0;
   int dead = 0;
+  {
+    StaticVector<DestroyCounts, 5> counts;
+    counts.emplace_back(live, dead);
+    counts.emplace_back(live, dead);
 
-  StaticVector<DestroyCounts, 5> counts;
-  counts.emplace_back(live, dead);
-  counts.emplace_back(live, dead);
+    counts.clear();
 
-  counts.clear();
-
-  EXPECT_TRUE(counts.empty());
+    EXPECT_TRUE(counts.empty());
+  }
   EXPECT_EQ(2, live);
   EXPECT_EQ(0, dead);
 }
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/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 7ce72ff..b7a7aa0 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -132,12 +132,13 @@
     }
 }
 
-BLASTBufferQueue::BLASTBufferQueue(const std::string& name)
+BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinationFrame)
       : mSurfaceControl(nullptr),
         mSize(1, 1),
         mRequestedSize(mSize),
         mFormat(PIXEL_FORMAT_RGBA_8888),
-        mSyncTransaction(nullptr) {
+        mSyncTransaction(nullptr),
+        mUpdateDestinationFrame(updateDestinationFrame) {
     createBufferQueue(&mProducer, &mConsumer);
     // since the adapter is in the client process, set dequeue timeout
     // explicitly so that dequeueBuffer will block
@@ -184,7 +185,7 @@
 }
 
 void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
-                              int32_t format, SurfaceComposerClient::Transaction* outTransaction) {
+                              int32_t format) {
     LOG_ALWAYS_FATAL_IF(surface == nullptr, "BLASTBufferQueue: mSurfaceControl must not be NULL");
 
     std::unique_lock _lock{mMutex};
@@ -193,7 +194,6 @@
         mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
     }
 
-    SurfaceComposerClient::Transaction t;
     const bool surfaceControlChanged = !SurfaceControl::isSameSurface(mSurfaceControl, surface);
     if (surfaceControlChanged && mSurfaceControl != nullptr) {
         BQA_LOGD("Updating SurfaceControl without recreating BBQ");
@@ -203,6 +203,7 @@
     // Always update the native object even though they might have the same layer handle, so we can
     // get the updated transform hint from WM.
     mSurfaceControl = surface;
+    SurfaceComposerClient::Transaction t;
     if (surfaceControlChanged) {
         t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
                    layer_state_t::eEnableBackpressure);
@@ -221,12 +222,10 @@
             // If the buffer supports scaling, update the frame immediately since the client may
             // want to scale the existing buffer to the new size.
             mSize = mRequestedSize;
-            SurfaceComposerClient::Transaction* destFrameTransaction =
-                    (outTransaction) ? outTransaction : &t;
-            destFrameTransaction->setDestinationFrame(mSurfaceControl,
-                                                      Rect(0, 0, newSize.getWidth(),
-                                                           newSize.getHeight()));
-            applyTransaction = true;
+            if (mUpdateDestinationFrame) {
+                t.setDestinationFrame(mSurfaceControl, Rect(newSize));
+                applyTransaction = true;
+            }
         }
     }
     if (applyTransaction) {
@@ -498,7 +497,6 @@
     // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
     incStrong((void*)transactionCallbackThunk);
 
-    const bool updateDestinationFrame = mRequestedSize != mSize;
     mSize = mRequestedSize;
     Rect crop = computeCrop(bufferItem);
     mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
@@ -517,12 +515,19 @@
 
     mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
 
-    if (updateDestinationFrame) {
-        t->setDestinationFrame(mSurfaceControl, Rect(0, 0, mSize.getWidth(), mSize.getHeight()));
+    if (mUpdateDestinationFrame) {
+        t->setDestinationFrame(mSurfaceControl, Rect(mSize));
+    } else {
+        const bool ignoreDestinationFrame =
+                bufferItem.mScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE;
+        t->setFlags(mSurfaceControl,
+                    ignoreDestinationFrame ? layer_state_t::eIgnoreDestinationFrame : 0,
+                    layer_state_t::eIgnoreDestinationFrame);
     }
     t->setBufferCrop(mSurfaceControl, crop);
     t->setTransform(mSurfaceControl, bufferItem.mTransform);
     t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
+    t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh);
     if (!bufferItem.mIsAutoTimestamp) {
         t->setDesiredPresentTime(bufferItem.mTimestamp);
     }
@@ -532,10 +537,6 @@
         mNextFrameTimelineInfoQueue.pop();
     }
 
-    if (mAutoRefresh != bufferItem.mAutoRefresh) {
-        t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh);
-        mAutoRefresh = bufferItem.mAutoRefresh;
-    }
     {
         std::unique_lock _lock{mTimestampMutex};
         auto dequeueTime = mDequeueTimestamps.find(buffer->getId());
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 26db59b..39d380d 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -126,7 +126,7 @@
         ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
               ", displayId=%s, count=%d, vsyncId=%" PRId64,
               this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
-              vsyncEventData.id);
+              vsyncEventData.preferredVsyncId());
         mWaitingForVsync = false;
         mLastVsyncCount = vsyncCount;
         dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
@@ -146,18 +146,6 @@
     return 1; // keep the callback
 }
 
-void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event,
-                                                    VsyncEventData* outVsyncEventData) const {
-    for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
-        DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline =
-                event.vsync.frameTimelines[i];
-        outVsyncEventData->frameTimelines[i] =
-                VsyncEventData::FrameTimeline(receiverTimeline.vsyncId,
-                                              receiverTimeline.deadlineTimestamp,
-                                              receiverTimeline.expectedVSyncTimestamp);
-    }
-}
-
 bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
                                                   PhysicalDisplayId* outDisplayId,
                                                   uint32_t* outCount,
@@ -178,12 +166,7 @@
                     *outTimestamp = ev.header.timestamp;
                     *outDisplayId = ev.header.displayId;
                     *outCount = ev.vsync.count;
-                    outVsyncEventData->id = ev.vsync.vsyncId;
-                    outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp;
-                    outVsyncEventData->frameInterval = ev.vsync.frameInterval;
-                    outVsyncEventData->preferredFrameTimelineIndex =
-                            ev.vsync.preferredFrameTimelineIndex;
-                    populateFrameTimelines(ev, outVsyncEventData);
+                    *outVsyncEventData = ev.vsync.vsyncData;
                     break;
                 case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
                     dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index bb659bf..bfb7769 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -85,15 +85,14 @@
     return mInitError.has_value() ? mInitError.value() : NO_INIT;
 }
 
-status_t DisplayEventReceiver::getLatestVsyncEventData(VsyncEventData* outVsyncEventData) const {
+status_t DisplayEventReceiver::getLatestVsyncEventData(
+        ParcelableVsyncEventData* outVsyncEventData) const {
     if (mEventConnection != nullptr) {
-        VsyncEventData vsyncEventData;
-        auto status = mEventConnection->getLatestVsyncEventData(&vsyncEventData);
+        auto status = mEventConnection->getLatestVsyncEventData(outVsyncEventData);
         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 75c5e26..3c02e21 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -46,9 +46,11 @@
 
 namespace android {
 
+using gui::DisplayCaptureArgs;
 using gui::IDisplayEventConnection;
 using gui::IRegionSamplingListener;
 using gui::IWindowInfosListener;
+using gui::LayerCaptureArgs;
 using ui::ColorMode;
 
 class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
@@ -118,36 +120,6 @@
         remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
     }
 
-    status_t captureDisplay(const DisplayCaptureArgs& args,
-                            const sp<IScreenCaptureListener>& captureListener) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(args.write, data);
-        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
-
-        return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply);
-    }
-
-    status_t captureDisplay(DisplayId displayId,
-                            const sp<IScreenCaptureListener>& captureListener) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeUint64, displayId.value);
-        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
-
-        return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply);
-    }
-
-    status_t captureLayers(const LayerCaptureArgs& args,
-                           const sp<IScreenCaptureListener>& captureListener) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(args.write, data);
-        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
-
-        return remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
-    }
-
     bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& bufferProducer) const override {
         Parcel data, reply;
@@ -248,101 +220,6 @@
         return result;
     }
 
-    sp<IBinder> createDisplay(const String8& displayName, bool secure) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        status_t status = data.writeString8(displayName);
-        if (status) {
-            return nullptr;
-        }
-        status = data.writeBool(secure);
-        if (status) {
-            return nullptr;
-        }
-
-        status = remote()->transact(BnSurfaceComposer::CREATE_DISPLAY, data, &reply);
-        if (status) {
-            return nullptr;
-        }
-        sp<IBinder> display;
-        status = reply.readNullableStrongBinder(&display);
-        if (status) {
-            return nullptr;
-        }
-        return display;
-    }
-
-    void destroyDisplay(const sp<IBinder>& display) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-        remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply);
-    }
-
-    std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) ==
-            NO_ERROR) {
-            std::vector<uint64_t> rawIds;
-            if (reply.readUint64Vector(&rawIds) == NO_ERROR) {
-                std::vector<PhysicalDisplayId> displayIds;
-                displayIds.reserve(rawIds.size());
-
-                for (const uint64_t rawId : rawIds) {
-                    if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(rawId)) {
-                        displayIds.push_back(*id);
-                    }
-                }
-                return displayIds;
-            }
-        }
-
-        return {};
-    }
-
-    status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId* displayId) const override {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(remote()->transact, BnSurfaceComposer::GET_PRIMARY_PHYSICAL_DISPLAY_ID, data,
-                    &reply);
-        uint64_t rawId;
-        SAFE_PARCEL(reply.readUint64, &rawId);
-        if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(rawId)) {
-            *displayId = *id;
-            return NO_ERROR;
-        }
-        return NAME_NOT_FOUND;
-    }
-
-    sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeUint64(displayId.value);
-        remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN, data, &reply);
-        return reply.readStrongBinder();
-    }
-
-    void setPowerMode(const sp<IBinder>& display, int mode) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-        data.writeInt32(mode);
-        remote()->transact(BnSurfaceComposer::SET_POWER_MODE, data, &reply);
-    }
-
-    status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState* state) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-        remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATE, data, &reply);
-        const status_t result = reply.readInt32();
-        if (result == NO_ERROR) {
-            memcpy(state, reply.readInplace(sizeof(ui::DisplayState)), sizeof(ui::DisplayState));
-        }
-        return result;
-    }
-
     status_t getStaticDisplayInfo(const sp<IBinder>& display,
                                   ui::StaticDisplayInfo* info) override {
         Parcel data, reply;
@@ -365,20 +242,6 @@
         return reply.read(*info);
     }
 
-    status_t getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-        remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATS, data, &reply);
-        status_t result = reply.readInt32();
-        if (result == NO_ERROR) {
-            memcpy(stats,
-                    reply.readInplace(sizeof(DisplayStatInfo)),
-                    sizeof(DisplayStatInfo));
-        }
-        return result;
-    }
-
     status_t getDisplayNativePrimaries(const sp<IBinder>& display,
                                        ui::DisplayPrimaries& primaries) override {
         Parcel data, reply;
@@ -430,29 +293,6 @@
         return static_cast<status_t>(reply.readInt32());
     }
 
-    // TODO(b/213909104) : Add unit tests to verify surface flinger boot time APIs
-    status_t getBootDisplayModeSupport(bool* outSupport) const override {
-        Parcel data, reply;
-        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (error != NO_ERROR) {
-            ALOGE("getBootDisplayModeSupport: failed to write interface token: %d", error);
-            return error;
-        }
-        error = remote()->transact(BnSurfaceComposer::GET_BOOT_DISPLAY_MODE_SUPPORT, data, &reply);
-        if (error != NO_ERROR) {
-            ALOGE("getBootDisplayModeSupport: failed to transact: %d", error);
-            return error;
-        }
-        bool support;
-        error = reply.readBool(&support);
-        if (error != NO_ERROR) {
-            ALOGE("getBootDisplayModeSupport: failed to read support: %d", error);
-            return error;
-        }
-        *outSupport = support;
-        return NO_ERROR;
-    }
-
     status_t setBootDisplayMode(const sp<IBinder>& display,
                                 ui::DisplayModeId displayModeId) override {
         Parcel data, reply;
@@ -478,73 +318,6 @@
         return result;
     }
 
-    status_t clearBootDisplayMode(const sp<IBinder>& display) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("clearBootDisplayMode failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("clearBootDisplayMode failed to writeStrongBinder: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::CLEAR_BOOT_DISPLAY_MODE, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("clearBootDisplayMode failed to transact: %d", result);
-        }
-        return result;
-    }
-
-    void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("setAutoLowLatencyMode failed to writeInterfaceToken: %d", result);
-            return;
-        }
-
-        result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("setAutoLowLatencyMode failed to writeStrongBinder: %d", result);
-            return;
-        }
-        result = data.writeBool(on);
-        if (result != NO_ERROR) {
-            ALOGE("setAutoLowLatencyMode failed to writeBool: %d", result);
-            return;
-        }
-        result = remote()->transact(BnSurfaceComposer::SET_AUTO_LOW_LATENCY_MODE, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("setAutoLowLatencyMode failed to transact: %d", result);
-            return;
-        }
-    }
-
-    void setGameContentType(const sp<IBinder>& display, bool on) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("setGameContentType failed to writeInterfaceToken: %d", result);
-            return;
-        }
-        result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("setGameContentType failed to writeStrongBinder: %d", result);
-            return;
-        }
-        result = data.writeBool(on);
-        if (result != NO_ERROR) {
-            ALOGE("setGameContentType failed to writeBool: %d", result);
-            return;
-        }
-        result = remote()->transact(BnSurfaceComposer::SET_GAME_CONTENT_TYPE, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("setGameContentType failed to transact: %d", result);
-        }
-    }
-
     status_t clearAnimationFrameStats() override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -819,26 +592,6 @@
         return error;
     }
 
-    status_t isWideColorDisplay(const sp<IBinder>& token,
-                                bool* outIsWideColorDisplay) const override {
-        Parcel data, reply;
-        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (error != NO_ERROR) {
-            return error;
-        }
-        error = data.writeStrongBinder(token);
-        if (error != NO_ERROR) {
-            return error;
-        }
-
-        error = remote()->transact(BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY, data, &reply);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        error = reply.readBool(outIsWideColorDisplay);
-        return error;
-    }
-
     status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
                                        const sp<IRegionSamplingListener>& listener) override {
         Parcel data, reply;
@@ -1071,109 +824,6 @@
         return reply.readInt32();
     }
 
-    status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
-                                         bool* outSupport) const override {
-        Parcel data, reply;
-        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (error != NO_ERROR) {
-            ALOGE("getDisplayBrightnessSupport: failed to write interface token: %d", error);
-            return error;
-        }
-        error = data.writeStrongBinder(displayToken);
-        if (error != NO_ERROR) {
-            ALOGE("getDisplayBrightnessSupport: failed to write display token: %d", error);
-            return error;
-        }
-        error = remote()->transact(BnSurfaceComposer::GET_DISPLAY_BRIGHTNESS_SUPPORT, data, &reply);
-        if (error != NO_ERROR) {
-            ALOGE("getDisplayBrightnessSupport: failed to transact: %d", error);
-            return error;
-        }
-        bool support;
-        error = reply.readBool(&support);
-        if (error != NO_ERROR) {
-            ALOGE("getDisplayBrightnessSupport: failed to read support: %d", error);
-            return error;
-        }
-        *outSupport = support;
-        return NO_ERROR;
-    }
-
-    status_t setDisplayBrightness(const sp<IBinder>& displayToken,
-                                  const gui::DisplayBrightness& brightness) override {
-        Parcel data, reply;
-        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (error != NO_ERROR) {
-            ALOGE("setDisplayBrightness: failed to write interface token: %d", error);
-            return error;
-        }
-        error = data.writeStrongBinder(displayToken);
-        if (error != NO_ERROR) {
-            ALOGE("setDisplayBrightness: failed to write display token: %d", error);
-            return error;
-        }
-        error = data.writeParcelable(brightness);
-        if (error != NO_ERROR) {
-            ALOGE("setDisplayBrightness: failed to write brightness: %d", error);
-            return error;
-        }
-        error = remote()->transact(BnSurfaceComposer::SET_DISPLAY_BRIGHTNESS, data, &reply);
-        if (error != NO_ERROR) {
-            ALOGE("setDisplayBrightness: failed to transact: %d", error);
-            return error;
-        }
-        return NO_ERROR;
-    }
-
-    status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
-                                     const sp<gui::IHdrLayerInfoListener>& listener) override {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeStrongBinder, displayToken);
-        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
-        const status_t error =
-                remote()->transact(BnSurfaceComposer::ADD_HDR_LAYER_INFO_LISTENER, data, &reply);
-        if (error != OK) {
-            ALOGE("addHdrLayerInfoListener: Failed to transact; error = %d", error);
-        }
-        return error;
-    }
-
-    status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
-                                        const sp<gui::IHdrLayerInfoListener>& listener) override {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeStrongBinder, displayToken);
-        SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
-        const status_t error =
-                remote()->transact(BnSurfaceComposer::REMOVE_HDR_LAYER_INFO_LISTENER, data, &reply);
-        if (error != OK) {
-            ALOGE("removeHdrLayerInfoListener: Failed to transact; error = %d", error);
-        }
-        return error;
-    }
-
-    status_t notifyPowerBoost(int32_t boostId) override {
-        Parcel data, reply;
-        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (error != NO_ERROR) {
-            ALOGE("notifyPowerBoost: failed to write interface token: %d", error);
-            return error;
-        }
-        error = data.writeInt32(boostId);
-        if (error != NO_ERROR) {
-            ALOGE("notifyPowerBoost: failed to write boostId: %d", error);
-            return error;
-        }
-        error = remote()->transact(BnSurfaceComposer::NOTIFY_POWER_BOOST, data, &reply,
-                                   IBinder::FLAG_ONEWAY);
-        if (error != NO_ERROR) {
-            ALOGE("notifyPowerBoost: failed to transact: %d", error);
-            return error;
-        }
-        return NO_ERROR;
-    }
-
     status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
                                      float lightPosY, float lightPosZ, float lightRadius) override {
         Parcel data, reply;
@@ -1451,36 +1101,6 @@
             bootFinished();
             return NO_ERROR;
         }
-        case CAPTURE_DISPLAY: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            DisplayCaptureArgs args;
-            sp<IScreenCaptureListener> captureListener;
-            SAFE_PARCEL(args.read, data);
-            SAFE_PARCEL(data.readStrongBinder, &captureListener);
-
-            return captureDisplay(args, captureListener);
-        }
-        case CAPTURE_DISPLAY_BY_ID: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            uint64_t value;
-            SAFE_PARCEL(data.readUint64, &value);
-            const auto id = DisplayId::fromValue(value);
-            if (!id) return BAD_VALUE;
-
-            sp<IScreenCaptureListener> captureListener;
-            SAFE_PARCEL(data.readStrongBinder, &captureListener);
-
-            return captureDisplay(*id, captureListener);
-        }
-        case CAPTURE_LAYERS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            LayerCaptureArgs args;
-            sp<IScreenCaptureListener> captureListener;
-            SAFE_PARCEL(args.read, data);
-            SAFE_PARCEL(data.readStrongBinder, &captureListener);
-
-            return captureLayers(args, captureListener);
-        }
         case AUTHENTICATE_SURFACE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IGraphicBufferProducer> bufferProducer =
@@ -1519,41 +1139,6 @@
             reply->writeStrongBinder(IInterface::asBinder(connection));
             return NO_ERROR;
         }
-        case CREATE_DISPLAY: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            String8 displayName;
-            SAFE_PARCEL(data.readString8, &displayName);
-            bool secure = false;
-            SAFE_PARCEL(data.readBool, &secure);
-            sp<IBinder> display = createDisplay(displayName, secure);
-            SAFE_PARCEL(reply->writeStrongBinder, display);
-            return NO_ERROR;
-        }
-        case DESTROY_DISPLAY: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = data.readStrongBinder();
-            destroyDisplay(display);
-            return NO_ERROR;
-        }
-        case GET_PHYSICAL_DISPLAY_TOKEN: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            const auto id = DisplayId::fromValue<PhysicalDisplayId>(data.readUint64());
-            if (!id) return BAD_VALUE;
-            reply->writeStrongBinder(getPhysicalDisplayToken(*id));
-            return NO_ERROR;
-        }
-        case GET_DISPLAY_STATE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            ui::DisplayState state;
-            const sp<IBinder> display = data.readStrongBinder();
-            const status_t result = getDisplayState(display, &state);
-            reply->writeInt32(result);
-            if (result == NO_ERROR) {
-                memcpy(reply->writeInplace(sizeof(ui::DisplayState)), &state,
-                       sizeof(ui::DisplayState));
-            }
-            return NO_ERROR;
-        }
         case GET_STATIC_DISPLAY_INFO: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             ui::StaticDisplayInfo info;
@@ -1574,18 +1159,6 @@
             SAFE_PARCEL(reply->write, info);
             return NO_ERROR;
         }
-        case GET_DISPLAY_STATS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            DisplayStatInfo stats;
-            sp<IBinder> display = data.readStrongBinder();
-            status_t result = getDisplayStats(display, &stats);
-            reply->writeInt32(result);
-            if (result == NO_ERROR) {
-                memcpy(reply->writeInplace(sizeof(DisplayStatInfo)),
-                        &stats, sizeof(DisplayStatInfo));
-            }
-            return NO_ERROR;
-        }
         case GET_DISPLAY_NATIVE_PRIMARIES: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             ui::DisplayPrimaries primaries;
@@ -1625,15 +1198,6 @@
             result = reply->writeInt32(result);
             return result;
         }
-        case GET_BOOT_DISPLAY_MODE_SUPPORT: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            bool support = false;
-            status_t result = getBootDisplayModeSupport(&support);
-            if (result == NO_ERROR) {
-                reply->writeBool(support);
-            }
-            return result;
-        }
         case SET_BOOT_DISPLAY_MODE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> display = nullptr;
@@ -1650,50 +1214,6 @@
             }
             return setBootDisplayMode(display, displayModeId);
         }
-        case CLEAR_BOOT_DISPLAY_MODE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = nullptr;
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("clearBootDisplayMode failed to readStrongBinder: %d", result);
-                return result;
-            }
-            return clearBootDisplayMode(display);
-        }
-        case SET_AUTO_LOW_LATENCY_MODE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = nullptr;
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("setAutoLowLatencyMode failed to readStrongBinder: %d", result);
-                return result;
-            }
-            bool setAllm = false;
-            result = data.readBool(&setAllm);
-            if (result != NO_ERROR) {
-                ALOGE("setAutoLowLatencyMode failed to readBool: %d", result);
-                return result;
-            }
-            setAutoLowLatencyMode(display, setAllm);
-            return result;
-        }
-        case SET_GAME_CONTENT_TYPE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = nullptr;
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("setGameContentType failed to readStrongBinder: %d", result);
-                return result;
-            }
-            bool setGameContentTypeOn = false;
-            result = data.readBool(&setGameContentTypeOn);
-            if (result != NO_ERROR) {
-                ALOGE("setGameContentType failed to readBool: %d", result);
-                return result;
-            }
-            setGameContentType(display, setGameContentTypeOn);
-            return result;
-        }
         case CLEAR_ANIMATION_FRAME_STATS: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             status_t result = clearAnimationFrameStats();
@@ -1708,13 +1228,6 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
-        case SET_POWER_MODE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = data.readStrongBinder();
-            int32_t mode = data.readInt32();
-            setPowerMode(display, mode);
-            return NO_ERROR;
-        }
         case ENABLE_VSYNC_INJECTIONS: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             bool enable = false;
@@ -1864,38 +1377,6 @@
             }
             return error;
         }
-        case IS_WIDE_COLOR_DISPLAY: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = nullptr;
-            status_t error = data.readStrongBinder(&display);
-            if (error != NO_ERROR) {
-                return error;
-            }
-            bool result;
-            error = isWideColorDisplay(display, &result);
-            if (error == NO_ERROR) {
-                reply->writeBool(result);
-            }
-            return error;
-        }
-        case GET_PHYSICAL_DISPLAY_IDS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            std::vector<PhysicalDisplayId> ids = getPhysicalDisplayIds();
-            std::vector<uint64_t> rawIds(ids.size());
-            std::transform(ids.begin(), ids.end(), rawIds.begin(),
-                           [](PhysicalDisplayId id) { return id.value; });
-            return reply->writeUint64Vector(rawIds);
-        }
-        case GET_PRIMARY_PHYSICAL_DISPLAY_ID: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            PhysicalDisplayId id;
-            status_t result = getPrimaryPhysicalDisplayId(&id);
-            if (result != NO_ERROR) {
-                ALOGE("getPrimaryPhysicalDisplayId: Failed to get id");
-                return result;
-            }
-            return reply->writeUint64(id.value);
-        }
         case ADD_REGION_SAMPLING_LISTENER: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             Rect samplingArea;
@@ -2093,77 +1574,6 @@
             reply->writeInt32(result);
             return result;
         }
-        case GET_DISPLAY_BRIGHTNESS_SUPPORT: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> displayToken;
-            status_t error = data.readNullableStrongBinder(&displayToken);
-            if (error != NO_ERROR) {
-                ALOGE("getDisplayBrightnessSupport: failed to read display token: %d", error);
-                return error;
-            }
-            bool support = false;
-            error = getDisplayBrightnessSupport(displayToken, &support);
-            reply->writeBool(support);
-            return error;
-        }
-        case SET_DISPLAY_BRIGHTNESS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> displayToken;
-            status_t error = data.readNullableStrongBinder(&displayToken);
-            if (error != NO_ERROR) {
-                ALOGE("setDisplayBrightness: failed to read display token: %d", error);
-                return error;
-            }
-            gui::DisplayBrightness brightness;
-            error = data.readParcelable(&brightness);
-            if (error != NO_ERROR) {
-                ALOGE("setDisplayBrightness: failed to read brightness: %d", error);
-                return error;
-            }
-            return setDisplayBrightness(displayToken, brightness);
-        }
-        case ADD_HDR_LAYER_INFO_LISTENER: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> displayToken;
-            status_t error = data.readNullableStrongBinder(&displayToken);
-            if (error != NO_ERROR) {
-                ALOGE("addHdrLayerInfoListener: Failed to read display token");
-                return error;
-            }
-            sp<gui::IHdrLayerInfoListener> listener;
-            error = data.readNullableStrongBinder(&listener);
-            if (error != NO_ERROR) {
-                ALOGE("addHdrLayerInfoListener: Failed to read listener");
-                return error;
-            }
-            return addHdrLayerInfoListener(displayToken, listener);
-        }
-        case REMOVE_HDR_LAYER_INFO_LISTENER: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> displayToken;
-            status_t error = data.readNullableStrongBinder(&displayToken);
-            if (error != NO_ERROR) {
-                ALOGE("removeHdrLayerInfoListener: Failed to read display token");
-                return error;
-            }
-            sp<gui::IHdrLayerInfoListener> listener;
-            error = data.readNullableStrongBinder(&listener);
-            if (error != NO_ERROR) {
-                ALOGE("removeHdrLayerInfoListener: Failed to read listener");
-                return error;
-            }
-            return removeHdrLayerInfoListener(displayToken, listener);
-        }
-        case NOTIFY_POWER_BOOST: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            int32_t boostId;
-            status_t error = data.readInt32(&boostId);
-            if (error != NO_ERROR) {
-                ALOGE("notifyPowerBoost: failed to read boostId: %d", error);
-                return error;
-            }
-            return notifyPowerBoost(boostId);
-        }
         case SET_GLOBAL_SHADOW_SETTINGS: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
 
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index eec4a87..6944d38 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;
 }
 
@@ -674,85 +686,89 @@
 
 // ----------------------------------------------------------------------------
 
-status_t CaptureArgs::write(Parcel& output) const {
-    SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(pixelFormat));
-    SAFE_PARCEL(output.write, sourceCrop);
-    SAFE_PARCEL(output.writeFloat, frameScaleX);
-    SAFE_PARCEL(output.writeFloat, frameScaleY);
-    SAFE_PARCEL(output.writeBool, captureSecureLayers);
-    SAFE_PARCEL(output.writeInt32, uid);
-    SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(dataspace));
-    SAFE_PARCEL(output.writeBool, allowProtected);
-    SAFE_PARCEL(output.writeBool, grayscale);
+namespace gui {
+
+status_t CaptureArgs::writeToParcel(Parcel* output) const {
+    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(pixelFormat));
+    SAFE_PARCEL(output->write, sourceCrop);
+    SAFE_PARCEL(output->writeFloat, frameScaleX);
+    SAFE_PARCEL(output->writeFloat, frameScaleY);
+    SAFE_PARCEL(output->writeBool, captureSecureLayers);
+    SAFE_PARCEL(output->writeInt32, uid);
+    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(dataspace));
+    SAFE_PARCEL(output->writeBool, allowProtected);
+    SAFE_PARCEL(output->writeBool, grayscale);
     return NO_ERROR;
 }
 
-status_t CaptureArgs::read(const Parcel& input) {
+status_t CaptureArgs::readFromParcel(const Parcel* input) {
     int32_t value = 0;
-    SAFE_PARCEL(input.readInt32, &value);
+    SAFE_PARCEL(input->readInt32, &value);
     pixelFormat = static_cast<ui::PixelFormat>(value);
-    SAFE_PARCEL(input.read, sourceCrop);
-    SAFE_PARCEL(input.readFloat, &frameScaleX);
-    SAFE_PARCEL(input.readFloat, &frameScaleY);
-    SAFE_PARCEL(input.readBool, &captureSecureLayers);
-    SAFE_PARCEL(input.readInt32, &uid);
-    SAFE_PARCEL(input.readInt32, &value);
+    SAFE_PARCEL(input->read, sourceCrop);
+    SAFE_PARCEL(input->readFloat, &frameScaleX);
+    SAFE_PARCEL(input->readFloat, &frameScaleY);
+    SAFE_PARCEL(input->readBool, &captureSecureLayers);
+    SAFE_PARCEL(input->readInt32, &uid);
+    SAFE_PARCEL(input->readInt32, &value);
     dataspace = static_cast<ui::Dataspace>(value);
-    SAFE_PARCEL(input.readBool, &allowProtected);
-    SAFE_PARCEL(input.readBool, &grayscale);
+    SAFE_PARCEL(input->readBool, &allowProtected);
+    SAFE_PARCEL(input->readBool, &grayscale);
     return NO_ERROR;
 }
 
-status_t DisplayCaptureArgs::write(Parcel& output) const {
-    SAFE_PARCEL(CaptureArgs::write, output);
+status_t DisplayCaptureArgs::writeToParcel(Parcel* output) const {
+    SAFE_PARCEL(CaptureArgs::writeToParcel, output);
 
-    SAFE_PARCEL(output.writeStrongBinder, displayToken);
-    SAFE_PARCEL(output.writeUint32, width);
-    SAFE_PARCEL(output.writeUint32, height);
-    SAFE_PARCEL(output.writeBool, useIdentityTransform);
+    SAFE_PARCEL(output->writeStrongBinder, displayToken);
+    SAFE_PARCEL(output->writeUint32, width);
+    SAFE_PARCEL(output->writeUint32, height);
+    SAFE_PARCEL(output->writeBool, useIdentityTransform);
     return NO_ERROR;
 }
 
-status_t DisplayCaptureArgs::read(const Parcel& input) {
-    SAFE_PARCEL(CaptureArgs::read, input);
+status_t DisplayCaptureArgs::readFromParcel(const Parcel* input) {
+    SAFE_PARCEL(CaptureArgs::readFromParcel, input);
 
-    SAFE_PARCEL(input.readStrongBinder, &displayToken);
-    SAFE_PARCEL(input.readUint32, &width);
-    SAFE_PARCEL(input.readUint32, &height);
-    SAFE_PARCEL(input.readBool, &useIdentityTransform);
+    SAFE_PARCEL(input->readStrongBinder, &displayToken);
+    SAFE_PARCEL(input->readUint32, &width);
+    SAFE_PARCEL(input->readUint32, &height);
+    SAFE_PARCEL(input->readBool, &useIdentityTransform);
     return NO_ERROR;
 }
 
-status_t LayerCaptureArgs::write(Parcel& output) const {
-    SAFE_PARCEL(CaptureArgs::write, output);
+status_t LayerCaptureArgs::writeToParcel(Parcel* output) const {
+    SAFE_PARCEL(CaptureArgs::writeToParcel, output);
 
-    SAFE_PARCEL(output.writeStrongBinder, layerHandle);
-    SAFE_PARCEL(output.writeInt32, excludeHandles.size());
+    SAFE_PARCEL(output->writeStrongBinder, layerHandle);
+    SAFE_PARCEL(output->writeInt32, excludeHandles.size());
     for (auto el : excludeHandles) {
-        SAFE_PARCEL(output.writeStrongBinder, el);
+        SAFE_PARCEL(output->writeStrongBinder, el);
     }
-    SAFE_PARCEL(output.writeBool, childrenOnly);
+    SAFE_PARCEL(output->writeBool, childrenOnly);
     return NO_ERROR;
 }
 
-status_t LayerCaptureArgs::read(const Parcel& input) {
-    SAFE_PARCEL(CaptureArgs::read, input);
+status_t LayerCaptureArgs::readFromParcel(const Parcel* input) {
+    SAFE_PARCEL(CaptureArgs::readFromParcel, input);
 
-    SAFE_PARCEL(input.readStrongBinder, &layerHandle);
+    SAFE_PARCEL(input->readStrongBinder, &layerHandle);
 
     int32_t numExcludeHandles = 0;
-    SAFE_PARCEL_READ_SIZE(input.readInt32, &numExcludeHandles, input.dataSize());
+    SAFE_PARCEL_READ_SIZE(input->readInt32, &numExcludeHandles, input->dataSize());
     excludeHandles.reserve(numExcludeHandles);
     for (int i = 0; i < numExcludeHandles; i++) {
         sp<IBinder> binder;
-        SAFE_PARCEL(input.readStrongBinder, &binder);
+        SAFE_PARCEL(input->readStrongBinder, &binder);
         excludeHandles.emplace(binder);
     }
 
-    SAFE_PARCEL(input.readBool, &childrenOnly);
+    SAFE_PARCEL(input->readBool, &childrenOnly);
     return NO_ERROR;
 }
 
+}; // namespace gui
+
 ReleaseCallbackId BufferData::generateReleaseCallbackId() const {
     return {buffer->getId(), frameNumber};
 }
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 20c4146..0f0a5c8 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -27,13 +27,13 @@
 
 #include <inttypes.h>
 
+#include <android/gui/DisplayStatInfo.h>
 #include <android/native_window.h>
 
 #include <utils/Log.h>
 #include <utils/Trace.h>
 #include <utils/NativeHandle.h>
 
-#include <ui/DisplayStatInfo.h>
 #include <ui/DynamicDisplayInfo.h>
 #include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
@@ -45,6 +45,7 @@
 #include <gui/ISurfaceComposer.h>
 #include <gui/LayerState.h>
 #include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 
 namespace android {
 
@@ -125,6 +126,10 @@
     return ComposerService::getComposerService();
 }
 
+sp<gui::ISurfaceComposer> Surface::composerServiceAIDL() const {
+    return ComposerServiceAIDL::getComposerService();
+}
+
 nsecs_t Surface::now() const {
     return systemTime();
 }
@@ -174,10 +179,10 @@
 status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) {
     ATRACE_CALL();
 
-    DisplayStatInfo stats;
-    status_t result = composerService()->getDisplayStats(nullptr, &stats);
-    if (result != NO_ERROR) {
-        return result;
+    gui::DisplayStatInfo stats;
+    binder::Status status = composerServiceAIDL()->getDisplayStats(nullptr, &stats);
+    if (!status.isOk()) {
+        return status.transactionError();
     }
 
     *outRefreshDuration = stats.vsyncPeriod;
@@ -343,20 +348,20 @@
 status_t Surface::getWideColorSupport(bool* supported) {
     ATRACE_CALL();
 
-    const sp<IBinder> display = composerService()->getInternalDisplayToken();
+    const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
     if (display == nullptr) {
         return NAME_NOT_FOUND;
     }
 
     *supported = false;
-    status_t error = composerService()->isWideColorDisplay(display, supported);
-    return error;
+    binder::Status status = composerServiceAIDL()->isWideColorDisplay(display, supported);
+    return status.transactionError();
 }
 
 status_t Surface::getHdrSupport(bool* supported) {
     ATRACE_CALL();
 
-    const sp<IBinder> display = composerService()->getInternalDisplayToken();
+    const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
     if (display == nullptr) {
         return NAME_NOT_FOUND;
     }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 9269c3e..447b3ef 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -19,6 +19,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <android/gui/DisplayState.h>
 #include <android/gui/IWindowInfosListener.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
@@ -43,9 +44,11 @@
 #include <gui/WindowInfo.h>
 #include <private/gui/ParcelUtils.h>
 #include <ui/DisplayMode.h>
+#include <ui/DisplayState.h>
 #include <ui/DynamicDisplayInfo.h>
 
 #include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 
 // This server size should always be smaller than the server cache size
 #define BUFFER_CACHE_MAX_SIZE 64
@@ -62,6 +65,7 @@
 // ---------------------------------------------------------------------------
 
 ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService);
+ANDROID_SINGLETON_STATIC_INSTANCE(ComposerServiceAIDL);
 
 namespace {
 // Initialize transaction id counter used to generate transaction ids
@@ -120,6 +124,52 @@
     mDeathObserver = nullptr;
 }
 
+ComposerServiceAIDL::ComposerServiceAIDL() : Singleton<ComposerServiceAIDL>() {
+    std::scoped_lock lock(mMutex);
+    connectLocked();
+}
+
+bool ComposerServiceAIDL::connectLocked() {
+    const String16 name("SurfaceFlingerAIDL");
+    mComposerService = waitForService<gui::ISurfaceComposer>(name);
+    if (mComposerService == nullptr) {
+        return false; // fatal error or permission problem
+    }
+
+    // Create the death listener.
+    class DeathObserver : public IBinder::DeathRecipient {
+        ComposerServiceAIDL& mComposerService;
+        virtual void binderDied(const wp<IBinder>& who) {
+            ALOGW("ComposerService aidl remote (surfaceflinger) died [%p]", who.unsafe_get());
+            mComposerService.composerServiceDied();
+        }
+
+    public:
+        explicit DeathObserver(ComposerServiceAIDL& mgr) : mComposerService(mgr) {}
+    };
+
+    mDeathObserver = new DeathObserver(*const_cast<ComposerServiceAIDL*>(this));
+    IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver);
+    return true;
+}
+
+/*static*/ sp<gui::ISurfaceComposer> ComposerServiceAIDL::getComposerService() {
+    ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
+    std::scoped_lock lock(instance.mMutex);
+    if (instance.mComposerService == nullptr) {
+        if (ComposerServiceAIDL::getInstance().connectLocked()) {
+            ALOGD("ComposerServiceAIDL reconnected");
+        }
+    }
+    return instance.mComposerService;
+}
+
+void ComposerServiceAIDL::composerServiceDied() {
+    std::scoped_lock lock(mMutex);
+    mComposerService = nullptr;
+    mDeathObserver = nullptr;
+}
+
 class DefaultComposerClient: public Singleton<DefaultComposerClient> {
     Mutex mLock;
     sp<SurfaceComposerClient> mClient;
@@ -966,32 +1016,59 @@
 // ---------------------------------------------------------------------------
 
 sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) {
-    return ComposerService::getComposerService()->createDisplay(displayName,
-            secure);
+    sp<IBinder> display = nullptr;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->createDisplay(std::string(
+                                                                             displayName.string()),
+                                                                     secure, &display);
+    return status.isOk() ? display : nullptr;
 }
 
 void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) {
-    return ComposerService::getComposerService()->destroyDisplay(display);
+    ComposerServiceAIDL::getComposerService()->destroyDisplay(display);
 }
 
 std::vector<PhysicalDisplayId> SurfaceComposerClient::getPhysicalDisplayIds() {
-    return ComposerService::getComposerService()->getPhysicalDisplayIds();
+    std::vector<int64_t> displayIds;
+    std::vector<PhysicalDisplayId> physicalDisplayIds;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getPhysicalDisplayIds(&displayIds);
+    if (status.isOk()) {
+        physicalDisplayIds.reserve(displayIds.size());
+        for (auto item : displayIds) {
+            auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(item));
+            physicalDisplayIds.push_back(*id);
+        }
+    }
+    return physicalDisplayIds;
 }
 
 status_t SurfaceComposerClient::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) {
-    return ComposerService::getComposerService()->getPrimaryPhysicalDisplayId(id);
+    int64_t displayId;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getPrimaryPhysicalDisplayId(&displayId);
+    if (status.isOk()) {
+        *id = *DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
+    }
+    return status.transactionError();
 }
 
 std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
-    return ComposerService::getComposerService()->getInternalDisplayId();
+    ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
+    return instance.getInternalDisplayId();
 }
 
 sp<IBinder> SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId displayId) {
-    return ComposerService::getComposerService()->getPhysicalDisplayToken(displayId);
+    sp<IBinder> display = nullptr;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getPhysicalDisplayToken(displayId.value,
+                                                                               &display);
+    return status.isOk() ? display : nullptr;
 }
 
 sp<IBinder> SurfaceComposerClient::getInternalDisplayToken() {
-    return ComposerService::getComposerService()->getInternalDisplayToken();
+    ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
+    return instance.getInternalDisplayToken();
 }
 
 void SurfaceComposerClient::Transaction::setAnimationTransaction() {
@@ -2019,7 +2096,16 @@
 
 status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display,
                                                 ui::DisplayState* state) {
-    return ComposerService::getComposerService()->getDisplayState(display, state);
+    gui::DisplayState ds;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getDisplayState(display, &ds);
+    if (status.isOk()) {
+        state->layerStack = ui::LayerStack::fromValue(ds.layerStack);
+        state->orientation = static_cast<ui::Rotation>(ds.orientation);
+        state->layerStackSpaceRect =
+                ui::Size(ds.layerStackSpaceRect.width, ds.layerStackSpaceRect.height);
+    }
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::getStaticDisplayInfo(const sp<IBinder>& display,
@@ -2083,7 +2169,9 @@
 }
 
 status_t SurfaceComposerClient::getBootDisplayModeSupport(bool* support) {
-    return ComposerService::getComposerService()->getBootDisplayModeSupport(support);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getBootDisplayModeSupport(support);
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::setBootDisplayMode(const sp<IBinder>& display,
@@ -2092,7 +2180,9 @@
 }
 
 status_t SurfaceComposerClient::clearBootDisplayMode(const sp<IBinder>& display) {
-    return ComposerService::getComposerService()->clearBootDisplayMode(display);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->clearBootDisplayMode(display);
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) {
@@ -2100,16 +2190,16 @@
 }
 
 void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
-    ComposerService::getComposerService()->setAutoLowLatencyMode(display, on);
+    ComposerServiceAIDL::getComposerService()->setAutoLowLatencyMode(display, on);
 }
 
 void SurfaceComposerClient::setGameContentType(const sp<IBinder>& display, bool on) {
-    ComposerService::getComposerService()->setGameContentType(display, on);
+    ComposerServiceAIDL::getComposerService()->setGameContentType(display, on);
 }
 
 void SurfaceComposerClient::setDisplayPowerMode(const sp<IBinder>& token,
         int mode) {
-    ComposerService::getComposerService()->setPowerMode(token, mode);
+    ComposerServiceAIDL::getComposerService()->setPowerMode(token, mode);
 }
 
 status_t SurfaceComposerClient::getCompositionPreference(
@@ -2170,8 +2260,10 @@
 
 status_t SurfaceComposerClient::isWideColorDisplay(const sp<IBinder>& display,
                                                    bool* outIsWideColorDisplay) {
-    return ComposerService::getComposerService()->isWideColorDisplay(display,
-                                                                     outIsWideColorDisplay);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->isWideColorDisplay(display,
+                                                                          outIsWideColorDisplay);
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::addRegionSamplingListener(
@@ -2208,28 +2300,39 @@
 
 bool SurfaceComposerClient::getDisplayBrightnessSupport(const sp<IBinder>& displayToken) {
     bool support = false;
-    ComposerService::getComposerService()->getDisplayBrightnessSupport(displayToken, &support);
-    return support;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getDisplayBrightnessSupport(displayToken,
+                                                                                   &support);
+    return status.isOk() ? support : false;
 }
 
 status_t SurfaceComposerClient::setDisplayBrightness(const sp<IBinder>& displayToken,
                                                      const gui::DisplayBrightness& brightness) {
-    return ComposerService::getComposerService()->setDisplayBrightness(displayToken, brightness);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->setDisplayBrightness(displayToken,
+                                                                            brightness);
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::addHdrLayerInfoListener(
         const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
-    return ComposerService::getComposerService()->addHdrLayerInfoListener(displayToken, listener);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->addHdrLayerInfoListener(displayToken,
+                                                                               listener);
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::removeHdrLayerInfoListener(
         const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
-    return ComposerService::getComposerService()->removeHdrLayerInfoListener(displayToken,
-                                                                             listener);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->removeHdrLayerInfoListener(displayToken,
+                                                                                  listener);
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::notifyPowerBoost(int32_t boostId) {
-    return ComposerService::getComposerService()->notifyPowerBoost(boostId);
+    binder::Status status = ComposerServiceAIDL::getComposerService()->notifyPowerBoost(boostId);
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColor,
@@ -2267,26 +2370,29 @@
 
 status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs,
                                           const sp<IScreenCaptureListener>& captureListener) {
-    sp<ISurfaceComposer> s(ComposerService::getComposerService());
+    sp<gui::ISurfaceComposer> s(ComposerServiceAIDL::getComposerService());
     if (s == nullptr) return NO_INIT;
 
-    return s->captureDisplay(captureArgs, captureListener);
+    binder::Status status = s->captureDisplay(captureArgs, captureListener);
+    return status.transactionError();
 }
 
 status_t ScreenshotClient::captureDisplay(DisplayId displayId,
                                           const sp<IScreenCaptureListener>& captureListener) {
-    sp<ISurfaceComposer> s(ComposerService::getComposerService());
+    sp<gui::ISurfaceComposer> s(ComposerServiceAIDL::getComposerService());
     if (s == nullptr) return NO_INIT;
 
-    return s->captureDisplay(displayId, captureListener);
+    binder::Status status = s->captureDisplayById(displayId.value, captureListener);
+    return status.transactionError();
 }
 
 status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs,
                                          const sp<IScreenCaptureListener>& captureListener) {
-    sp<ISurfaceComposer> s(ComposerService::getComposerService());
+    sp<gui::ISurfaceComposer> s(ComposerServiceAIDL::getComposerService());
     if (s == nullptr) return NO_INIT;
 
-    return s->captureLayers(captureArgs, captureListener);
+    binder::Status status = s->captureLayers(captureArgs, captureListener);
+    return status.transactionError();
 }
 
 // ---------------------------------------------------------------------------------
diff --git a/libs/gui/VsyncEventData.cpp b/libs/gui/VsyncEventData.cpp
index aad81d0..23f0921 100644
--- a/libs/gui/VsyncEventData.cpp
+++ b/libs/gui/VsyncEventData.cpp
@@ -23,52 +23,46 @@
 
 namespace android::gui {
 
-status_t VsyncEventData::readFromParcel(const Parcel* parcel) {
+int64_t VsyncEventData::preferredVsyncId() const {
+    return frameTimelines[preferredFrameTimelineIndex].vsyncId;
+}
+
+int64_t VsyncEventData::preferredDeadlineTimestamp() const {
+    return frameTimelines[preferredFrameTimelineIndex].deadlineTimestamp;
+}
+
+int64_t VsyncEventData::preferredExpectedPresentationTime() const {
+    return frameTimelines[preferredFrameTimelineIndex].expectedPresentationTime;
+}
+
+status_t ParcelableVsyncEventData::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);
+    SAFE_PARCEL(parcel->readInt64, &vsync.frameInterval);
 
     uint64_t uintPreferredFrameTimelineIndex;
     SAFE_PARCEL(parcel->readUint64, &uintPreferredFrameTimelineIndex);
-    preferredFrameTimelineIndex = static_cast<size_t>(uintPreferredFrameTimelineIndex);
+    vsync.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;
+    for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+        SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].vsyncId);
+        SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].deadlineTimestamp);
+        SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].expectedPresentationTime);
     }
 
-    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);
+status_t ParcelableVsyncEventData::writeToParcel(Parcel* parcel) const {
+    SAFE_PARCEL(parcel->writeInt64, vsync.frameInterval);
+    SAFE_PARCEL(parcel->writeUint64, vsync.preferredFrameTimelineIndex);
+    for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+        SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].vsyncId);
+        SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].deadlineTimestamp);
+        SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].expectedPresentationTime);
+    }
 
     return OK;
 }
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index a866786..80bd638 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -18,7 +18,6 @@
 #define LOG_TAG "WindowInfo"
 #define LOG_NDEBUG 0
 
-#include <android-base/stringprintf.h>
 #include <binder/Parcel.h>
 #include <gui/WindowInfo.h>
 
@@ -27,6 +26,14 @@
 namespace android::gui {
 
 // --- WindowInfo ---
+void WindowInfo::setInputConfig(Flags<InputConfig> config, bool value) {
+    if (value) {
+        inputConfig |= config;
+        return;
+    }
+    inputConfig &= ~config;
+}
+
 void WindowInfo::addTouchableRegion(const Rect& region) {
     touchableRegion.orSelf(region);
 }
@@ -40,7 +47,7 @@
 }
 
 bool WindowInfo::supportsSplitTouch() const {
-    return flags.test(Flag::SPLIT_TOUCH);
+    return !inputConfig.test(InputConfig::PREVENT_SPLITTING);
 }
 
 bool WindowInfo::isSpy() const {
@@ -58,20 +65,19 @@
 }
 
 bool WindowInfo::operator==(const WindowInfo& info) const {
-    return info.token == token && info.id == id && info.name == name && info.flags == flags &&
-            info.type == type && info.dispatchingTimeout == dispatchingTimeout &&
-            info.frameLeft == frameLeft && info.frameTop == frameTop &&
-            info.frameRight == frameRight && info.frameBottom == frameBottom &&
-            info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor &&
-            info.transform == transform && info.touchableRegion.hasSameRects(touchableRegion) &&
-            info.visible == visible && info.trustedOverlay == trustedOverlay &&
-            info.focusable == focusable && info.touchOcclusionMode == touchOcclusionMode &&
-            info.hasWallpaper == hasWallpaper && info.paused == paused &&
-            info.ownerPid == ownerPid && info.ownerUid == ownerUid &&
-            info.packageName == packageName && info.inputFeatures == inputFeatures &&
+    return info.token == token && info.id == id && info.name == name &&
+            info.dispatchingTimeout == dispatchingTimeout && info.frameLeft == frameLeft &&
+            info.frameTop == frameTop && info.frameRight == frameRight &&
+            info.frameBottom == frameBottom && info.surfaceInset == surfaceInset &&
+            info.globalScaleFactor == globalScaleFactor && info.transform == transform &&
+            info.touchableRegion.hasSameRects(touchableRegion) &&
+            info.touchOcclusionMode == touchOcclusionMode && info.ownerPid == ownerPid &&
+            info.ownerUid == ownerUid && info.packageName == packageName &&
+            info.inputFeatures == inputFeatures && info.inputConfig == inputConfig &&
             info.displayId == displayId &&
             info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
-            info.applicationInfo == applicationInfo;
+            info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType &&
+            info.layoutParamsFlags == layoutParamsFlags;
 }
 
 status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
@@ -85,13 +91,18 @@
     }
     parcel->writeInt32(1);
 
+    // Ensure that the size of the flags that we use is 32 bits for writing into the parcel.
+    static_assert(sizeof(inputFeatures) == 4u);
+    static_assert(sizeof(inputConfig) == 4u);
+
     // clang-format off
     status_t status = parcel->writeStrongBinder(token) ?:
         parcel->writeInt64(dispatchingTimeout.count()) ?:
         parcel->writeInt32(id) ?:
         parcel->writeUtf8AsUtf16(name) ?:
-        parcel->writeInt32(flags.get()) ?:
-        parcel->writeInt32(static_cast<std::underlying_type_t<WindowInfo::Type>>(type)) ?:
+        parcel->writeInt32(layoutParamsFlags.get()) ?:
+        parcel->writeInt32(
+                static_cast<std::underlying_type_t<WindowInfo::Type>>(layoutParamsType)) ?:
         parcel->writeInt32(frameLeft) ?:
         parcel->writeInt32(frameTop) ?:
         parcel->writeInt32(frameRight) ?:
@@ -105,16 +116,12 @@
         parcel->writeFloat(transform.dtdy()) ?:
         parcel->writeFloat(transform.dsdy()) ?:
         parcel->writeFloat(transform.ty()) ?:
-        parcel->writeBool(visible) ?:
-        parcel->writeBool(focusable) ?:
-        parcel->writeBool(hasWallpaper) ?:
-        parcel->writeBool(paused) ?:
-        parcel->writeBool(trustedOverlay) ?:
         parcel->writeInt32(static_cast<int32_t>(touchOcclusionMode)) ?:
         parcel->writeInt32(ownerPid) ?:
         parcel->writeInt32(ownerUid) ?:
         parcel->writeUtf8AsUtf16(packageName) ?:
         parcel->writeInt32(inputFeatures.get()) ?:
+        parcel->writeInt32(inputConfig.get()) ?:
         parcel->writeInt32(displayId) ?:
         applicationInfo.writeToParcel(parcel) ?:
         parcel->write(touchableRegion) ?:
@@ -141,8 +148,8 @@
         return status;
     }
 
-    flags = Flags<Flag>(parcel->readInt32());
-    type = static_cast<Type>(parcel->readInt32());
+    layoutParamsFlags = Flags<Flag>(parcel->readInt32());
+    layoutParamsType = static_cast<Type>(parcel->readInt32());
     float dsdx, dtdx, tx, dtdy, dsdy, ty;
     int32_t touchOcclusionModeInt;
     // clang-format off
@@ -159,11 +166,6 @@
         parcel->readFloat(&dtdy) ?:
         parcel->readFloat(&dsdy) ?:
         parcel->readFloat(&ty) ?:
-        parcel->readBool(&visible) ?:
-        parcel->readBool(&focusable) ?:
-        parcel->readBool(&hasWallpaper) ?:
-        parcel->readBool(&paused) ?:
-        parcel->readBool(&trustedOverlay) ?:
         parcel->readInt32(&touchOcclusionModeInt) ?:
         parcel->readInt32(&ownerPid) ?:
         parcel->readInt32(&ownerUid) ?:
@@ -177,6 +179,7 @@
     touchOcclusionMode = static_cast<TouchOcclusionMode>(touchOcclusionModeInt);
 
     inputFeatures = Flags<Feature>(parcel->readInt32());
+    inputConfig = Flags<InputConfig>(parcel->readInt32());
     // clang-format off
     status = parcel->readInt32(&displayId) ?:
         applicationInfo.readFromParcel(parcel) ?:
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl
similarity index 89%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl
index 7343515..2caa2b9 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl
@@ -16,4 +16,4 @@
 
 package android.gui;
 
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+parcelable DisplayCaptureArgs cpp_header "gui/DisplayCaptureArgs.h";
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/DisplayStatInfo.aidl
similarity index 81%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to libs/gui/aidl/android/gui/DisplayStatInfo.aidl
index 7343515..68f3942 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/DisplayStatInfo.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,4 +16,8 @@
 
 package android.gui;
 
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+/** @hide */
+parcelable DisplayStatInfo {
+    long vsyncTime;
+    long vsyncPeriod;
+}
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/DisplayState.aidl
similarity index 70%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to libs/gui/aidl/android/gui/DisplayState.aidl
index 7343515..9589ab6 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/DisplayState.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,4 +16,12 @@
 
 package android.gui;
 
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+import android.gui.Rotation;
+import android.gui.Size;
+
+/** @hide */
+parcelable DisplayState {
+    int layerStack;
+    Rotation orientation = Rotation.Rotation0;
+    Size layerStackSpaceRect;
+}
diff --git a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl
index e9a6a0c..9781ca9 100644
--- a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl
+++ b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl
@@ -17,7 +17,7 @@
 package android.gui;
 
 import android.gui.BitTube;
-import android.gui.VsyncEventData;
+import android.gui.ParcelableVsyncEventData;
 
 /** @hide */
 interface IDisplayEventConnection {
@@ -43,5 +43,5 @@
     /*
      * getLatestVsyncEventData() gets the latest vsync event data.
      */
-    VsyncEventData getLatestVsyncEventData();
+    ParcelableVsyncEventData getLatestVsyncEventData();
 }
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
new file mode 100644
index 0000000..a9977b0
--- /dev/null
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -0,0 +1,182 @@
+/*
+ * 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;
+
+import android.gui.DisplayCaptureArgs;
+import android.gui.DisplayBrightness;
+import android.gui.DisplayState;
+import android.gui.DisplayStatInfo;
+import android.gui.IHdrLayerInfoListener;
+import android.gui.LayerCaptureArgs;
+import android.gui.IScreenCaptureListener;
+
+/** @hide */
+interface ISurfaceComposer {
+
+    /* create a virtual display
+     * requires ACCESS_SURFACE_FLINGER permission.
+     */
+    @nullable IBinder createDisplay(@utf8InCpp String displayName, boolean secure);
+
+    /* destroy a virtual display
+     * requires ACCESS_SURFACE_FLINGER permission.
+     */
+    void destroyDisplay(IBinder display);
+
+    /* get stable IDs for connected physical displays.
+     */
+    long[] getPhysicalDisplayIds();
+
+    long getPrimaryPhysicalDisplayId();
+
+    /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
+     * DisplayEventReceiver hotplug event.
+     */
+    @nullable IBinder getPhysicalDisplayToken(long displayId);
+
+    /* set display power mode. depending on the mode, it can either trigger
+     * screen on, off or low power mode and wait for it to complete.
+     * requires ACCESS_SURFACE_FLINGER permission.
+     */
+    void setPowerMode(IBinder display, int mode);
+
+    /* returns display statistics for a given display
+     * intended to be used by the media framework to properly schedule
+     * video frames */
+    DisplayStatInfo getDisplayStats(IBinder display);
+
+     /**
+     * Get transactional state of given display.
+     */
+    DisplayState getDisplayState(IBinder display);
+
+    /**
+     * Clears the user-preferred display mode. The device should now boot in system preferred
+     * display mode.
+     */
+    void clearBootDisplayMode(IBinder display);
+
+    /**
+     * Gets whether boot time display mode operations are supported on the device.
+     *
+     * outSupport
+     *      An output parameter for whether boot time display mode operations are supported.
+     *
+     * Returns NO_ERROR upon success. Otherwise,
+     *      NAME_NOT_FOUND if the display is invalid, or
+     *      BAD_VALUE      if the output parameter is invalid.
+     */
+    // TODO(b/213909104) : Add unit tests to verify surface flinger boot time APIs
+    boolean getBootDisplayModeSupport();
+
+    /**
+     * Switches Auto Low Latency Mode on/off on the connected display, if it is
+     * available. This should only be called if the display supports Auto Low
+     * Latency Mode as reported in #getDynamicDisplayInfo.
+     * For more information, see the HDMI 2.1 specification.
+     */
+    void setAutoLowLatencyMode(IBinder display, boolean on);
+
+    /**
+     * This will start sending infoframes to the connected display with
+     * ContentType=Game (if on=true). This should only be called if the display
+     * Game Content Type as reported in #getDynamicDisplayInfo.
+     * For more information, see the HDMI 1.4 specification.
+     */
+    void setGameContentType(IBinder display, boolean on);
+
+    /**
+     * Capture the specified screen. This requires READ_FRAME_BUFFER
+     * permission.  This function will fail if there is a secure window on
+     * screen and DisplayCaptureArgs.captureSecureLayers is false.
+     *
+     * This function can capture a subregion (the source crop) of the screen.
+     * The subregion can be optionally rotated.  It will also be scaled to
+     * match the size of the output buffer.
+     */
+    void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener);
+    void captureDisplayById(long displayId, IScreenCaptureListener listener);
+    /**
+     * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
+     * This requires READ_FRAME_BUFFER permission. This function will fail if there
+     * is a secure window on screen
+     */
+    void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener);
+
+    /*
+     * Queries whether the given display is a wide color display.
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    boolean isWideColorDisplay(IBinder token);
+
+    /*
+     * Gets whether brightness operations are supported on a display.
+     *
+     * displayToken
+     *      The token of the display.
+     * outSupport
+     *      An output parameter for whether brightness operations are supported.
+     *
+     * Returns NO_ERROR upon success. Otherwise,
+     *      NAME_NOT_FOUND if the display is invalid, or
+     *      BAD_VALUE      if the output parameter is invalid.
+     */
+    boolean getDisplayBrightnessSupport(IBinder displayToken);
+
+    /*
+     * Sets the brightness of a display.
+     *
+     * displayToken
+     *      The token of the display whose brightness is set.
+     * brightness
+     *      The DisplayBrightness info to set on the desired display.
+     *
+     * Returns NO_ERROR upon success. Otherwise,
+     *      NAME_NOT_FOUND    if the display is invalid, or
+     *      BAD_VALUE         if the brightness is invalid, or
+     *      INVALID_OPERATION if brightness operations are not supported.
+     */
+    void setDisplayBrightness(IBinder displayToken, in DisplayBrightness brightness);
+
+    /*
+     * Adds a listener that receives HDR layer information. This is used in combination
+     * with setDisplayBrightness to adjust the display brightness depending on factors such
+     * as whether or not HDR is in use.
+     *
+     * Returns NO_ERROR upon success or NAME_NOT_FOUND if the display is invalid.
+     */
+    void addHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
+
+    /*
+     * Removes a listener that was added with addHdrLayerInfoListener.
+     *
+     * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if
+     *     the listener wasn't registered.
+     *
+     */
+    void removeHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
+
+    /*
+     * Sends a power boost to the composer. This function is asynchronous.
+     *
+     * boostId
+     *      boost id according to android::hardware::power::Boost
+     *
+     * Returns NO_ERROR upon success.
+     */
+    void notifyPowerBoost(int boostId);
+}
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl
similarity index 90%
rename from libs/gui/aidl/android/gui/VsyncEventData.aidl
rename to libs/gui/aidl/android/gui/LayerCaptureArgs.aidl
index 7343515..f0def50 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl
@@ -16,4 +16,4 @@
 
 package android.gui;
 
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+parcelable LayerCaptureArgs cpp_header "gui/LayerCaptureArgs.h";
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl
similarity index 89%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl
index 7343515..ba76671 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl
@@ -16,4 +16,4 @@
 
 package android.gui;
 
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+parcelable ParcelableVsyncEventData cpp_header "gui/VsyncEventData.h";
diff --git a/libs/gui/aidl/android/gui/Rect.aidl b/libs/gui/aidl/android/gui/Rect.aidl
new file mode 100644
index 0000000..1b13761
--- /dev/null
+++ b/libs/gui/aidl/android/gui/Rect.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+// copied from libs/arect/include/android/rect.h
+// TODO(b/221473398):
+// use hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
+/** @hide */
+parcelable Rect {
+    /// Minimum X coordinate of the rectangle.
+    int left;
+
+    /// Minimum Y coordinate of the rectangle.
+    int top;
+
+    /// Maximum X coordinate of the rectangle.
+    int right;
+
+    /// Maximum Y coordinate of the rectangle.
+    int bottom;
+}
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/Rotation.aidl
similarity index 76%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to libs/gui/aidl/android/gui/Rotation.aidl
index 7343515..451ff45 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/Rotation.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,4 +16,11 @@
 
 package android.gui;
 
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+/** @hide */
+@Backing(type="int")
+enum Rotation {
+    Rotation0 = 0,
+    Rotation90 = 1,
+    Rotation180 = 2,
+    Rotation270 = 3
+}
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/Size.aidl
similarity index 82%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to libs/gui/aidl/android/gui/Size.aidl
index 7343515..415fa36 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/libs/gui/aidl/android/gui/Size.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,4 +16,8 @@
 
 package android.gui;
 
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+/** @hide */
+parcelable Size {
+    int width = -1;
+    int height = -1;
+}
diff --git a/libs/gui/android/gui/FocusRequest.aidl b/libs/gui/android/gui/FocusRequest.aidl
index 9018635..b13c600 100644
--- a/libs/gui/android/gui/FocusRequest.aidl
+++ b/libs/gui/android/gui/FocusRequest.aidl
@@ -21,7 +21,7 @@
     /**
      * Input channel token used to identify the window that should gain focus.
      */
-    IBinder token;
+    @nullable IBinder token;
     @utf8InCpp String windowName;
     /**
      * The token that the caller expects currently to be focused. If the
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 1ed592b..74addea 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -73,7 +73,7 @@
     : public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener
 {
 public:
-    BLASTBufferQueue(const std::string& name);
+    BLASTBufferQueue(const std::string& name, bool updateDestinationFrame = true);
     BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width,
                      int height, int32_t format);
 
@@ -100,8 +100,7 @@
     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);
+    void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format);
 
     status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
     status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
@@ -218,11 +217,6 @@
     std::vector<std::tuple<uint64_t /* framenumber */, SurfaceComposerClient::Transaction>>
             mPendingTransactions GUARDED_BY(mMutex);
 
-    // Last requested auto refresh state set by the producer. The state indicates that the consumer
-    // should acquire the next frame as soon as it can and not wait for a frame to become available.
-    // This is only relevant for shared buffer mode.
-    bool mAutoRefresh GUARDED_BY(mMutex) = false;
-
     std::queue<FrameTimelineInfo> mNextFrameTimelineInfoQueue GUARDED_BY(mMutex);
 
     // Tracks the last acquired frame number
@@ -250,6 +244,12 @@
     // Flag to determine if syncTransaction should only acquire a single buffer and then clear or
     // continue to acquire buffers until explicitly cleared
     bool mAcquireSingleBuffer GUARDED_BY(mMutex) = true;
+
+    // True if BBQ will update the destination frame used to scale the buffer to the requested size.
+    // If false, the caller is responsible for updating the destination frame on the BBQ
+    // surfacecontol. This is useful if the caller wants to synchronize the buffer scale with
+    // additional scales in the hierarchy.
+    bool mUpdateDestinationFrame GUARDED_BY(mMutex) = true;
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/DisplayCaptureArgs.h b/libs/gui/include/gui/DisplayCaptureArgs.h
new file mode 100644
index 0000000..ec884cf
--- /dev/null
+++ b/libs/gui/include/gui/DisplayCaptureArgs.h
@@ -0,0 +1,71 @@
+/*
+ * 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 <binder/IBinder.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <ui/GraphicTypes.h>
+#include <ui/PixelFormat.h>
+
+namespace android::gui {
+
+struct CaptureArgs : public Parcelable {
+    const static int32_t UNSET_UID = -1;
+    virtual ~CaptureArgs() = default;
+
+    ui::PixelFormat pixelFormat{ui::PixelFormat::RGBA_8888};
+    Rect sourceCrop;
+    float frameScaleX{1};
+    float frameScaleY{1};
+    bool captureSecureLayers{false};
+    int32_t uid{UNSET_UID};
+    // Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured
+    // result will be in the display's colorspace.
+    // The display may use non-RGB dataspace (ex. displayP3) that could cause pixel data could be
+    // different from SRGB (byte per color), and failed when checking colors in tests.
+    // NOTE: In normal cases, we want the screen to be captured in display's colorspace.
+    ui::Dataspace dataspace = ui::Dataspace::UNKNOWN;
+
+    // The receiver of the capture can handle protected buffer. A protected buffer has
+    // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour.
+    // Any read/write access from unprotected context will result in undefined behaviour.
+    // Protected contents are typically DRM contents. This has no direct implication to the
+    // secure property of the surface, which is specified by the application explicitly to avoid
+    // the contents being accessed/captured by screenshot or unsecure display.
+    bool allowProtected = false;
+
+    bool grayscale = false;
+
+    virtual status_t writeToParcel(Parcel* output) const;
+    virtual status_t readFromParcel(const Parcel* input);
+};
+
+struct DisplayCaptureArgs : CaptureArgs {
+    sp<IBinder> displayToken;
+    uint32_t width{0};
+    uint32_t height{0};
+    bool useIdentityTransform{false};
+
+    status_t writeToParcel(Parcel* output) const override;
+    status_t readFromParcel(const Parcel* input) override;
+};
+
+}; // namespace android::gui
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 740d825..cf7a4e5 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -35,6 +35,7 @@
 // ----------------------------------------------------------------------------
 
 using gui::IDisplayEventConnection;
+using gui::ParcelableVsyncEventData;
 using gui::VsyncEventData;
 
 namespace gui {
@@ -76,16 +77,7 @@
 
         struct VSync {
             uint32_t count;
-            nsecs_t expectedVSyncTimestamp __attribute__((aligned(8)));
-            nsecs_t deadlineTimestamp __attribute__((aligned(8)));
-            nsecs_t frameInterval __attribute__((aligned(8)));
-            int64_t vsyncId;
-            size_t preferredFrameTimelineIndex __attribute__((aligned(8)));
-            struct FrameTimeline {
-                nsecs_t expectedVSyncTimestamp __attribute__((aligned(8)));
-                nsecs_t deadlineTimestamp __attribute__((aligned(8)));
-                int64_t vsyncId;
-            } frameTimelines[VsyncEventData::kFrameTimelinesLength];
+            VsyncEventData vsyncData;
         };
 
         struct Hotplug {
@@ -175,7 +167,7 @@
     /**
      * getLatestVsyncEventData() gets the latest vsync event data.
      */
-    status_t getLatestVsyncEventData(VsyncEventData* outVsyncEventData) const;
+    status_t getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) const;
 
 private:
     sp<IDisplayEventConnection> mEventConnection;
@@ -183,6 +175,11 @@
     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/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 0a59f52..2e4d6b4 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -58,11 +58,9 @@
 
 struct client_cache_t;
 struct ComposerState;
-struct DisplayCaptureArgs;
 struct DisplayStatInfo;
 struct DisplayState;
 struct InputWindowCommands;
-struct LayerCaptureArgs;
 class LayerDebugInfo;
 class HdrCapabilities;
 class IGraphicBufferProducer;
@@ -75,6 +73,13 @@
 using gui::IScreenCaptureListener;
 using gui::SpHash;
 
+namespace gui {
+
+struct DisplayCaptureArgs;
+struct LayerCaptureArgs;
+
+} // namespace gui
+
 namespace ui {
 
 struct DisplayMode;
@@ -132,40 +137,6 @@
             VsyncSource vsyncSource = eVsyncSourceApp,
             EventRegistrationFlags eventRegistration = {}) = 0;
 
-    /* create a virtual display
-     * requires ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual sp<IBinder> createDisplay(const String8& displayName,
-            bool secure) = 0;
-
-    /* destroy a virtual display
-     * requires ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual void destroyDisplay(const sp<IBinder>& display) = 0;
-
-    /* get stable IDs for connected physical displays.
-     */
-    virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0;
-
-    virtual status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const = 0;
-
-    // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
-    std::optional<PhysicalDisplayId> getInternalDisplayId() const {
-        const auto displayIds = getPhysicalDisplayIds();
-        return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
-    }
-
-    /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
-     * DisplayEventReceiver hotplug event.
-     */
-    virtual sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const = 0;
-
-    // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
-    sp<IBinder> getInternalDisplayToken() const {
-        const auto displayId = getInternalDisplayId();
-        return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
-    }
-
     /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
     virtual status_t setTransactionState(
             const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state,
@@ -189,24 +160,6 @@
     virtual status_t getSupportedFrameTimestamps(
             std::vector<FrameEvent>* outSupported) const = 0;
 
-    /* set display power mode. depending on the mode, it can either trigger
-     * screen on, off or low power mode and wait for it to complete.
-     * requires ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual void setPowerMode(const sp<IBinder>& display, int mode) = 0;
-
-
-    /* returns display statistics for a given display
-     * intended to be used by the media framework to properly schedule
-     * video frames */
-    virtual status_t getDisplayStats(const sp<IBinder>& display,
-            DisplayStatInfo* stats) = 0;
-
-    /**
-     * Get transactional state of given display.
-     */
-    virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*) = 0;
-
     /**
      * Gets immutable information about given physical display.
      */
@@ -227,61 +180,6 @@
      */
     virtual status_t setBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId) = 0;
 
-    /**
-     * Clears the user-preferred display mode. The device should now boot in system preferred
-     * display mode.
-     */
-    virtual status_t clearBootDisplayMode(const sp<IBinder>& display) = 0;
-
-    /**
-     * Gets whether boot time display mode operations are supported on the device.
-     *
-     * outSupport
-     *      An output parameter for whether boot time display mode operations are supported.
-     *
-     * 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 getBootDisplayModeSupport(bool* outSupport) const = 0;
-
-    /**
-     * Switches Auto Low Latency Mode on/off on the connected display, if it is
-     * available. This should only be called if the display supports Auto Low
-     * Latency Mode as reported in #getDynamicDisplayInfo.
-     * For more information, see the HDMI 2.1 specification.
-     */
-    virtual void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) = 0;
-
-    /**
-     * This will start sending infoframes to the connected display with
-     * ContentType=Game (if on=true). This should only be called if the display
-     * Game Content Type as reported in #getDynamicDisplayInfo.
-     * For more information, see the HDMI 1.4 specification.
-     */
-    virtual void setGameContentType(const sp<IBinder>& display, bool on) = 0;
-
-    /**
-     * Capture the specified screen. This requires READ_FRAME_BUFFER
-     * permission.  This function will fail if there is a secure window on
-     * screen and DisplayCaptureArgs.captureSecureLayers is false.
-     *
-     * This function can capture a subregion (the source crop) of the screen.
-     * The subregion can be optionally rotated.  It will also be scaled to
-     * match the size of the output buffer.
-     */
-    virtual status_t captureDisplay(const DisplayCaptureArgs&,
-                                    const sp<IScreenCaptureListener>&) = 0;
-
-    virtual status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) = 0;
-
-    /**
-     * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
-     * This requires READ_FRAME_BUFFER permission. This function will fail if there
-     * is a secure window on screen
-     */
-    virtual status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) = 0;
-
     /* Clears the frame statistics for animations.
      *
      * Requires the ACCESS_SURFACE_FLINGER permission.
@@ -360,13 +258,6 @@
      */
     virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
 
-    /*
-     * Queries whether the given display is a wide color display.
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t isWideColorDisplay(const sp<IBinder>& token,
-                                        bool* outIsWideColorDisplay) const = 0;
-
     /* Registers a listener to stream median luma updates from SurfaceFlinger.
      *
      * The sampling area is bounded by both samplingArea and the given stopLayerHandle
@@ -447,65 +338,6 @@
                                                 float* outPrimaryRefreshRateMax,
                                                 float* outAppRequestRefreshRateMin,
                                                 float* outAppRequestRefreshRateMax) = 0;
-    /*
-     * Gets whether brightness operations are supported on a display.
-     *
-     * displayToken
-     *      The token of the display.
-     * outSupport
-     *      An output parameter for whether brightness operations are supported.
-     *
-     * 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 getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
-                                                 bool* outSupport) const = 0;
-
-    /*
-     * Sets the brightness of a display.
-     *
-     * displayToken
-     *      The token of the display whose brightness is set.
-     * brightness
-     *      The DisplayBrightness info to set on the desired display.
-     *
-     * Returns NO_ERROR upon success. Otherwise,
-     *      NAME_NOT_FOUND    if the display is invalid, or
-     *      BAD_VALUE         if the brightness is invalid, or
-     *      INVALID_OPERATION if brightness operations are not supported.
-     */
-    virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken,
-                                          const gui::DisplayBrightness& brightness) = 0;
-
-    /*
-     * Adds a listener that receives HDR layer information. This is used in combination
-     * with setDisplayBrightness to adjust the display brightness depending on factors such
-     * as whether or not HDR is in use.
-     *
-     * Returns NO_ERROR upon success or NAME_NOT_FOUND if the display is invalid.
-     */
-    virtual status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
-                                             const sp<gui::IHdrLayerInfoListener>& listener) = 0;
-    /*
-     * Removes a listener that was added with addHdrLayerInfoListener.
-     *
-     * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if
-     *     the listener wasn't registered.
-     *
-     */
-    virtual status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
-                                                const sp<gui::IHdrLayerInfoListener>& listener) = 0;
-
-    /*
-     * Sends a power boost to the composer. This function is asynchronous.
-     *
-     * boostId
-     *      boost id according to android::hardware::power::Boost
-     *
-     * Returns NO_ERROR upon success.
-     */
-    virtual status_t notifyPowerBoost(int32_t boostId) = 0;
 
     /*
      * Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows
@@ -612,20 +444,20 @@
         CREATE_CONNECTION,
         GET_STATIC_DISPLAY_INFO,
         CREATE_DISPLAY_EVENT_CONNECTION,
-        CREATE_DISPLAY,
-        DESTROY_DISPLAY,
-        GET_PHYSICAL_DISPLAY_TOKEN,
+        CREATE_DISPLAY,             // Deprecated. Autogenerated by .aidl now.
+        DESTROY_DISPLAY,            // Deprecated. Autogenerated by .aidl now.
+        GET_PHYSICAL_DISPLAY_TOKEN, // Deprecated. Autogenerated by .aidl now.
         SET_TRANSACTION_STATE,
         AUTHENTICATE_SURFACE,
         GET_SUPPORTED_FRAME_TIMESTAMPS,
         GET_DISPLAY_MODES,       // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
         GET_ACTIVE_DISPLAY_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
         GET_DISPLAY_STATE,
-        CAPTURE_DISPLAY,
-        CAPTURE_LAYERS,
+        CAPTURE_DISPLAY, // Deprecated. Autogenerated by .aidl now.
+        CAPTURE_LAYERS,  // Deprecated. Autogenerated by .aidl now.
         CLEAR_ANIMATION_FRAME_STATS,
         GET_ANIMATION_FRAME_STATS,
-        SET_POWER_MODE,
+        SET_POWER_MODE, // Deprecated. Autogenerated by .aidl now.
         GET_DISPLAY_STATS,
         GET_HDR_CAPABILITIES,    // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
         GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
@@ -640,22 +472,22 @@
         SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
         GET_DISPLAYED_CONTENT_SAMPLE,
         GET_PROTECTED_CONTENT_SUPPORT,
-        IS_WIDE_COLOR_DISPLAY,
+        IS_WIDE_COLOR_DISPLAY, // Deprecated. Autogenerated by .aidl now.
         GET_DISPLAY_NATIVE_PRIMARIES,
-        GET_PHYSICAL_DISPLAY_IDS,
+        GET_PHYSICAL_DISPLAY_IDS, // Deprecated. Autogenerated by .aidl now.
         ADD_REGION_SAMPLING_LISTENER,
         REMOVE_REGION_SAMPLING_LISTENER,
         SET_DESIRED_DISPLAY_MODE_SPECS,
         GET_DESIRED_DISPLAY_MODE_SPECS,
-        GET_DISPLAY_BRIGHTNESS_SUPPORT,
-        SET_DISPLAY_BRIGHTNESS,
-        CAPTURE_DISPLAY_BY_ID,
-        NOTIFY_POWER_BOOST,
+        GET_DISPLAY_BRIGHTNESS_SUPPORT, // Deprecated. Autogenerated by .aidl now.
+        SET_DISPLAY_BRIGHTNESS,         // Deprecated. Autogenerated by .aidl now.
+        CAPTURE_DISPLAY_BY_ID,          // Deprecated. Autogenerated by .aidl now.
+        NOTIFY_POWER_BOOST,             // Deprecated. Autogenerated by .aidl now.
         SET_GLOBAL_SHADOW_SETTINGS,
         GET_AUTO_LOW_LATENCY_MODE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
-        SET_AUTO_LOW_LATENCY_MODE,
-        GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
-        SET_GAME_CONTENT_TYPE,
+        SET_AUTO_LOW_LATENCY_MODE,         // Deprecated. Autogenerated by .aidl now.
+        GET_GAME_CONTENT_TYPE_SUPPORT,     // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        SET_GAME_CONTENT_TYPE,             // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
         SET_FRAME_RATE,
         // Deprecated. Use DisplayManager.setShouldAlwaysRespectAppRequestedMode(true);
         ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
@@ -667,18 +499,18 @@
         ADD_FPS_LISTENER,
         REMOVE_FPS_LISTENER,
         OVERRIDE_HDR_TYPES,
-        ADD_HDR_LAYER_INFO_LISTENER,
-        REMOVE_HDR_LAYER_INFO_LISTENER,
+        ADD_HDR_LAYER_INFO_LISTENER,    // Deprecated. Autogenerated by .aidl now.
+        REMOVE_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now.
         ON_PULL_ATOM,
         ADD_TUNNEL_MODE_ENABLED_LISTENER,
         REMOVE_TUNNEL_MODE_ENABLED_LISTENER,
         ADD_WINDOW_INFOS_LISTENER,
         REMOVE_WINDOW_INFOS_LISTENER,
-        GET_PRIMARY_PHYSICAL_DISPLAY_ID,
+        GET_PRIMARY_PHYSICAL_DISPLAY_ID, // Deprecated. Autogenerated by .aidl now.
         GET_DISPLAY_DECORATION_SUPPORT,
-        GET_BOOT_DISPLAY_MODE_SUPPORT,
+        GET_BOOT_DISPLAY_MODE_SUPPORT, // Deprecated. Autogenerated by .aidl now.
         SET_BOOT_DISPLAY_MODE,
-        CLEAR_BOOT_DISPLAY_MODE,
+        CLEAR_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now.
         SET_OVERRIDE_FRAME_RATE,
         // Always append new enum to the end.
     };
diff --git a/libs/gui/include/gui/LayerCaptureArgs.h b/libs/gui/include/gui/LayerCaptureArgs.h
new file mode 100644
index 0000000..05ff9d5
--- /dev/null
+++ b/libs/gui/include/gui/LayerCaptureArgs.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <gui/DisplayCaptureArgs.h>
+#include <gui/SpHash.h>
+#include <unordered_set>
+
+namespace android::gui {
+
+struct LayerCaptureArgs : CaptureArgs {
+    sp<IBinder> layerHandle;
+    std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles;
+    bool childrenOnly{false};
+
+    status_t writeToParcel(Parcel* output) const override;
+    status_t readFromParcel(const Parcel* input) override;
+};
+
+}; // namespace android::gui
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index f720619..885b4ae 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -29,7 +29,9 @@
 #include <android/gui/DropInputMode.h>
 #include <android/gui/FocusRequest.h>
 
+#include <gui/DisplayCaptureArgs.h>
 #include <gui/ISurfaceComposer.h>
+#include <gui/LayerCaptureArgs.h>
 #include <gui/LayerMetadata.h>
 #include <gui/SpHash.h>
 #include <gui/SurfaceControl.h>
@@ -128,8 +130,13 @@
         // Queue up BufferStateLayer buffers instead of dropping the oldest buffer when this flag is
         // set. This blocks the client until all the buffers have been presented. If the buffers
         // have presentation timestamps, then we may drop buffers.
-        eEnableBackpressure = 0x100, // ENABLE_BACKPRESSURE
-        eLayerIsDisplayDecoration = 0x200,  // DISPLAY_DECORATION
+        eEnableBackpressure = 0x100,       // ENABLE_BACKPRESSURE
+        eLayerIsDisplayDecoration = 0x200, // DISPLAY_DECORATION
+        // Ignore any destination frame set on the layer. This is used when the buffer scaling mode
+        // is freeze and the destination frame is applied asynchronously with the buffer submission.
+        // This is needed to maintain compatibility for SurfaceView scaling behavior.
+        // See SurfaceView scaling behavior for more details.
+        eIgnoreDestinationFrame = 0x400,
     };
 
     enum {
@@ -370,56 +377,6 @@
 bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy,
                        const char* functionName, bool privileged = false);
 
-struct CaptureArgs {
-    const static int32_t UNSET_UID = -1;
-    virtual ~CaptureArgs() = default;
-
-    ui::PixelFormat pixelFormat{ui::PixelFormat::RGBA_8888};
-    Rect sourceCrop;
-    float frameScaleX{1};
-    float frameScaleY{1};
-    bool captureSecureLayers{false};
-    int32_t uid{UNSET_UID};
-    // Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured
-    // result will be in the display's colorspace.
-    // The display may use non-RGB dataspace (ex. displayP3) that could cause pixel data could be
-    // different from SRGB (byte per color), and failed when checking colors in tests.
-    // NOTE: In normal cases, we want the screen to be captured in display's colorspace.
-    ui::Dataspace dataspace = ui::Dataspace::UNKNOWN;
-
-    // The receiver of the capture can handle protected buffer. A protected buffer has
-    // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour.
-    // Any read/write access from unprotected context will result in undefined behaviour.
-    // Protected contents are typically DRM contents. This has no direct implication to the
-    // secure property of the surface, which is specified by the application explicitly to avoid
-    // the contents being accessed/captured by screenshot or unsecure display.
-    bool allowProtected = false;
-
-    bool grayscale = false;
-
-    virtual status_t write(Parcel& output) const;
-    virtual status_t read(const Parcel& input);
-};
-
-struct DisplayCaptureArgs : CaptureArgs {
-    sp<IBinder> displayToken;
-    uint32_t width{0};
-    uint32_t height{0};
-    bool useIdentityTransform{false};
-
-    status_t write(Parcel& output) const override;
-    status_t read(const Parcel& input) override;
-};
-
-struct LayerCaptureArgs : CaptureArgs {
-    sp<IBinder> layerHandle;
-    std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles;
-    bool childrenOnly{false};
-
-    status_t write(Parcel& output) const override;
-    status_t read(const Parcel& input) override;
-};
-
 }; // namespace android
 
 #endif // ANDROID_SF_LAYER_STATE_H
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 40d096e..ba9ee6c 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -35,6 +35,10 @@
 
 namespace android {
 
+namespace gui {
+class ISurfaceComposer;
+} // namespace gui
+
 class ISurfaceComposer;
 
 /* This is the same as ProducerListener except that onBuffersDiscarded is
@@ -196,6 +200,7 @@
 
     // Virtual for testing.
     virtual sp<ISurfaceComposer> composerService() const;
+    virtual sp<gui::ISurfaceComposer> composerServiceAIDL() const;
     virtual nsecs_t now() const;
 
 private:
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 25637ef..6c79b5b 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -57,7 +57,9 @@
 class ITunnelModeEnabledListener;
 class Region;
 
+using gui::DisplayCaptureArgs;
 using gui::IRegionSamplingListener;
+using gui::LayerCaptureArgs;
 
 struct SurfaceControlStats {
     SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime,
diff --git a/libs/gui/include/gui/VsyncEventData.h b/libs/gui/include/gui/VsyncEventData.h
index abac61c..8e99539 100644
--- a/libs/gui/include/gui/VsyncEventData.h
+++ b/libs/gui/include/gui/VsyncEventData.h
@@ -21,52 +21,44 @@
 #include <array>
 
 namespace android::gui {
-struct VsyncEventData : public Parcelable {
+// Plain Old Data (POD) vsync data structure. For example, it can be easily used in the
+// DisplayEventReceiver::Event union.
+struct VsyncEventData {
     // 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;
+    int64_t frameInterval;
 
-    struct FrameTimeline : public Parcelable {
-        FrameTimeline() = default;
-        FrameTimeline(int64_t id, int64_t deadlineTimestamp, int64_t expectedPresentTime)
-              : id(id),
-                deadlineTimestamp(deadlineTimestamp),
-                expectedPresentTime(expectedPresentTime) {}
+    // Index into the frameTimelines that represents the platform's preferred frame timeline.
+    uint32_t preferredFrameTimelineIndex;
 
+    struct alignas(8) 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;
+        int64_t vsyncId;
 
-        // 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 deadline in CLOCK_MONOTONIC in nanos that the app needs to complete its
+        // frame by (both on the CPU and the GPU).
+        int64_t deadlineTimestamp;
 
-        // The anticipated Vsync present time.
-        int64_t expectedPresentTime = 0;
+        // The anticipated Vsync presentation time in nanos.
+        int64_t expectedPresentationTime;
+    } frameTimelines[kFrameTimelinesLength]; // Sorted possible frame timelines.
 
-        status_t readFromParcel(const Parcel*) override;
-        status_t writeToParcel(Parcel*) const override;
-    };
+    // Gets the preferred frame timeline's vsync ID.
+    int64_t preferredVsyncId() const;
 
-    // Sorted possible frame timelines.
-    std::array<FrameTimeline, kFrameTimelinesLength> frameTimelines;
+    // Gets the preferred frame timeline's deadline timestamp.
+    int64_t preferredDeadlineTimestamp() const;
 
-    // Index into the frameTimelines that represents the platform's preferred frame timeline.
-    size_t preferredFrameTimelineIndex = std::numeric_limits<size_t>::max();
+    // Gets the preferred frame timeline's expected vsync timestamp.
+    int64_t preferredExpectedPresentationTime() const;
+};
+
+struct ParcelableVsyncEventData : public Parcelable {
+    VsyncEventData vsync;
 
     status_t readFromParcel(const Parcel*) override;
     status_t writeToParcel(Parcel*) const override;
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index eb64ac9..b9bffaa 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -151,6 +151,33 @@
         // clang-format on
     };
 
+    // Flags used to determine configuration of this input window.
+    // Input windows can be configured with two sets of flags: InputFeature (WindowInfo::Feature
+    // defined above), and InputConfig. When adding a new configuration for an input window:
+    //   - If you are adding a new flag that's visible and accessible to apps, it should be added
+    //   as an InputFeature.
+    //   - If you are adding an internal behaviour that is used within the system or shell and is
+    //   not exposed to apps, it should be added as an InputConfig.
+    enum class InputConfig : uint32_t {
+        // clang-format off
+        NONE                         = 0,
+        NOT_VISIBLE                  = 1 << 0,
+        NOT_FOCUSABLE                = 1 << 1,
+        NOT_TOUCHABLE                = 1 << 2,
+        PREVENT_SPLITTING            = 1 << 3,
+        DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 4,
+        IS_WALLPAPER                 = 1 << 5,
+        PAUSE_DISPATCHING            = 1 << 6,
+        // This flag is set when the window is of a trusted type that is allowed to silently
+        // overlay other windows for the purpose of implementing the secure views feature.
+        // Trusted overlays, such as IME windows, can partly obscure other windows without causing
+        // motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
+        TRUSTED_OVERLAY              = 1 << 7,
+        WATCH_OUTSIDE_TOUCH          = 1 << 8,
+        SLIPPERY                     = 1 << 9,
+        // clang-format on
+    };
+
     /* These values are filled in by the WM and passed through SurfaceFlinger
      * unless specified otherwise.
      */
@@ -164,8 +191,6 @@
     // This uniquely identifies the input window.
     int32_t id = -1;
     std::string name;
-    Flags<Flag> flags;
-    Type type = Type::UNKNOWN;
     std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5);
 
     /* These values are filled in by SurfaceFlinger. */
@@ -198,26 +223,24 @@
      * to absolute coordinates by SurfaceFlinger once the frame is computed.
      */
     Region touchableRegion;
-    bool visible = false;
-    bool focusable = false;
-    bool hasWallpaper = false;
-    bool paused = false;
-    /* This flag is set when the window is of a trusted type that is allowed to silently
-     * overlay other windows for the purpose of implementing the secure views feature.
-     * Trusted overlays, such as IME windows, can partly obscure other windows without causing
-     * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
-     */
-    bool trustedOverlay = false;
+
     TouchOcclusionMode touchOcclusionMode = TouchOcclusionMode::BLOCK_UNTRUSTED;
     int32_t ownerPid = -1;
     int32_t ownerUid = -1;
     std::string packageName;
     Flags<Feature> inputFeatures;
+    Flags<InputConfig> inputConfig;
     int32_t displayId = ADISPLAY_ID_NONE;
     InputApplicationInfo applicationInfo;
     bool replaceTouchableRegionWithCrop = false;
     wp<IBinder> touchableRegionCropHandle;
 
+    // The window's layout params flags and type set by WM.
+    Type layoutParamsType = Type::UNKNOWN;
+    Flags<Flag> layoutParamsFlags;
+
+    void setInputConfig(Flags<InputConfig> config, bool value);
+
     void addTouchableRegion(const Rect& region);
 
     bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
diff --git a/libs/gui/include/private/gui/ComposerService.h b/libs/gui/include/private/gui/ComposerService.h
index fa1071a..05ed0a0 100644
--- a/libs/gui/include/private/gui/ComposerService.h
+++ b/libs/gui/include/private/gui/ComposerService.h
@@ -37,7 +37,7 @@
 // Users of this class should not retain the value from
 // getComposerService() for an extended period.
 //
-// (It's not clear that using Singleton is useful here anymore.)
+// (TODO: b/219785927, It's not clear that using Singleton is useful here anymore.)
 class ComposerService : public Singleton<ComposerService>
 {
     sp<ISurfaceComposer> mComposerService;
diff --git a/libs/gui/include/private/gui/ComposerServiceAIDL.h b/libs/gui/include/private/gui/ComposerServiceAIDL.h
new file mode 100644
index 0000000..9a96976
--- /dev/null
+++ b/libs/gui/include/private/gui/ComposerServiceAIDL.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <android/gui/ISurfaceComposer.h>
+
+#include <utils/Singleton.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+
+// This holds our connection to the composer service (i.e. SurfaceFlinger).
+// If the remote side goes away, we will re-establish the connection.
+// Users of this class should not retain the value from
+// getComposerService() for an extended period.
+//
+// (TODO: b/219785927, It's not clear that using Singleton is useful here anymore.)
+class ComposerServiceAIDL : public Singleton<ComposerServiceAIDL> {
+    sp<gui::ISurfaceComposer> mComposerService;
+    sp<IBinder::DeathRecipient> mDeathObserver;
+    mutable std::mutex mMutex;
+
+    ComposerServiceAIDL();
+    bool connectLocked();
+    void composerServiceDied();
+    friend class Singleton<ComposerServiceAIDL>;
+
+public:
+    // Get a connection to the Composer Service.  This will block until
+    // a connection is established. Returns null if permission is denied.
+    static sp<gui::ISurfaceComposer> getComposerService();
+
+    // the following two methods are moved from ISurfaceComposer.h
+    // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+    std::optional<PhysicalDisplayId> getInternalDisplayId() const {
+        std::vector<int64_t> displayIds;
+        binder::Status status = mComposerService->getPhysicalDisplayIds(&displayIds);
+        return (!status.isOk() || displayIds.empty())
+                ? std::nullopt
+                : DisplayId::fromValue<PhysicalDisplayId>(
+                          static_cast<uint64_t>(displayIds.front()));
+    }
+
+    // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+    sp<IBinder> getInternalDisplayToken() const {
+        const auto displayId = getInternalDisplayId();
+        if (!displayId) return nullptr;
+        sp<IBinder> display;
+        binder::Status status =
+                mComposerService->getPhysicalDisplayToken(static_cast<int64_t>(displayId->value),
+                                                          &display);
+        return status.isOk() ? display : nullptr;
+    }
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 42a32f3..179bdd7 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -29,6 +29,7 @@
 #include <gui/SyncScreenCaptureListener.h>
 #include <gui/test/CallbackUtils.h>
 #include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 #include <ui/DisplayMode.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/GraphicTypes.h>
@@ -283,13 +284,13 @@
 
     static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
                                    ScreenCaptureResults& captureResults) {
-        const auto sf = ComposerService::getComposerService();
+        const auto sf = ComposerServiceAIDL::getComposerService();
         SurfaceComposerClient::Transaction().apply(true);
 
         const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
-        status_t status = sf->captureDisplay(captureArgs, captureListener);
-        if (status != NO_ERROR) {
-            return status;
+        binder::Status status = sf->captureDisplay(captureArgs, captureListener);
+        if (status.transactionError() != NO_ERROR) {
+            return status.transactionError();
         }
         captureResults = captureListener->waitForResults();
         return captureResults.result;
diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp
index bcd39db..da88463 100644
--- a/libs/gui/tests/DisplayEventStructLayout_test.cpp
+++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp
@@ -20,9 +20,10 @@
 namespace android::test {
 
 #define CHECK_OFFSET(type, member, expected_offset) \
-    static_assert((offsetof(type, member) == (expected_offset)), "")
+    static_assert((offsetof(type, member) == (expected_offset)))
 
 TEST(DisplayEventStructLayoutTest, TestEventAlignment) {
+    static_assert(std::is_pod<DisplayEventReceiver::Event::VSync>::value);
     CHECK_OFFSET(DisplayEventReceiver::Event, vsync, 24);
     CHECK_OFFSET(DisplayEventReceiver::Event, hotplug, 24);
     CHECK_OFFSET(DisplayEventReceiver::Event, modeChange, 24);
@@ -32,10 +33,29 @@
     CHECK_OFFSET(DisplayEventReceiver::Event::Header, timestamp, 16);
 
     CHECK_OFFSET(DisplayEventReceiver::Event::VSync, count, 0);
-    CHECK_OFFSET(DisplayEventReceiver::Event::VSync, expectedVSyncTimestamp, 8);
-    CHECK_OFFSET(DisplayEventReceiver::Event::VSync, deadlineTimestamp, 16);
-    CHECK_OFFSET(DisplayEventReceiver::Event::VSync, frameInterval, 24);
-    CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncId, 32);
+    CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameInterval, 8);
+    CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.preferredFrameTimelineIndex, 16);
+    CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines, 24);
+    CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines[0].vsyncId, 24);
+    CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines[0].deadlineTimestamp,
+                 32);
+    CHECK_OFFSET(DisplayEventReceiver::Event::VSync,
+                 vsyncData.frameTimelines[0].expectedPresentationTime, 40);
+    // Also test the offsets of the last frame timeline. A loop is not used because the non-const
+    // index cannot be used in static_assert.
+    const int lastFrameTimelineOffset = /* Start of array */ 24 +
+            (VsyncEventData::kFrameTimelinesLength - 1) * /* Size of FrameTimeline */ 24;
+    CHECK_OFFSET(DisplayEventReceiver::Event::VSync,
+                 vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1].vsyncId,
+                 lastFrameTimelineOffset);
+    CHECK_OFFSET(DisplayEventReceiver::Event::VSync,
+                 vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1]
+                         .deadlineTimestamp,
+                 lastFrameTimelineOffset + 8);
+    CHECK_OFFSET(DisplayEventReceiver::Event::VSync,
+                 vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1]
+                         .expectedPresentationTime,
+                 lastFrameTimelineOffset + 16);
 
     CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connected, 0);
 
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 06a0aca..fcfe21b 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -266,14 +266,8 @@
     void populateInputInfo(int width, int height) {
         mInputInfo.token = mClientChannel->getConnectionToken();
         mInputInfo.name = "Test info";
-        mInputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL;
-        mInputInfo.type = WindowInfo::Type::BASE_APPLICATION;
         mInputInfo.dispatchingTimeout = 5s;
         mInputInfo.globalScaleFactor = 1.0;
-        mInputInfo.focusable = true;
-        mInputInfo.hasWallpaper = false;
-        mInputInfo.paused = false;
-
         mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height));
 
         InputApplicationInfo aInfo;
@@ -750,7 +744,7 @@
     // Add non touchable window to fully cover touchable window. Window behind gets touch, but
     // with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED
     std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
-    nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+    nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
     nonTouchableSurface->mInputInfo.ownerUid = 22222;
     // Overriding occlusion mode otherwise the touch would be discarded at InputDispatcher by
     // the default obscured/untrusted touch filter introduced in S.
@@ -770,8 +764,8 @@
     // AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED
     std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
     std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
-    nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
-    parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+    nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
+    parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
     nonTouchableSurface->mInputInfo.ownerUid = 22222;
     parentSurface->mInputInfo.ownerUid = 22222;
     nonTouchableSurface->showAt(0, 0);
@@ -794,8 +788,8 @@
     // the touchable window. Window behind gets touch with no obscured flags.
     std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
     std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
-    nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
-    parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+    nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
+    parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
     nonTouchableSurface->mInputInfo.ownerUid = 22222;
     parentSurface->mInputInfo.ownerUid = 22222;
     nonTouchableSurface->showAt(0, 0);
@@ -815,7 +809,7 @@
 
     std::unique_ptr<InputSurface> bufferSurface =
             InputSurface::makeBufferInputSurface(mComposerClient, 0, 0);
-    bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+    bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
     bufferSurface->mInputInfo.ownerUid = 22222;
 
     surface->showAt(10, 10);
@@ -830,7 +824,7 @@
 
     std::unique_ptr<BlastInputSurface> bufferSurface =
             BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0);
-    bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+    bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
     bufferSurface->mInputInfo.ownerUid = 22222;
 
     surface->showAt(10, 10);
@@ -883,7 +877,7 @@
             [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
     surface->showAt(100, 100);
     std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
-    obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+    obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
     obscuringSurface->mInputInfo.ownerUid = 22222;
     obscuringSurface->showAt(100, 100);
     injectTap(101, 101);
@@ -902,7 +896,7 @@
             [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
     surface->showAt(100, 100);
     std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
-    obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+    obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
     obscuringSurface->mInputInfo.ownerUid = 22222;
     obscuringSurface->showAt(190, 190);
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 6056280..e0b86e0 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -20,6 +20,7 @@
 
 #include <SurfaceFlingerProperties.h>
 #include <android/gui/IDisplayEventConnection.h>
+#include <android/gui/ISurfaceComposer.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <binder/ProcessState.h>
 #include <configstore/Utils.h>
@@ -31,6 +32,7 @@
 #include <gui/SyncScreenCaptureListener.h>
 #include <inttypes.h>
 #include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 #include <sys/types.h>
 #include <ui/BufferQueueDefs.h>
 #include <ui/DisplayMode.h>
@@ -205,13 +207,13 @@
 
     static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
                                    ScreenCaptureResults& captureResults) {
-        const auto sf = ComposerService::getComposerService();
+        const auto sf = ComposerServiceAIDL::getComposerService();
         SurfaceComposerClient::Transaction().apply(true);
 
         const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
-        status_t status = sf->captureDisplay(captureArgs, captureListener);
-        if (status != NO_ERROR) {
-            return status;
+        binder::Status status = sf->captureDisplay(captureArgs, captureListener);
+        if (status.transactionError() != NO_ERROR) {
+            return status.transactionError();
         }
         captureResults = captureListener->waitForResults();
         return captureResults.result;
@@ -259,9 +261,7 @@
     sp<ANativeWindow> anw(mSurface);
 
     // Verify the screenshot works with no protected buffers.
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-
-    const sp<IBinder> display = sf->getInternalDisplayToken();
+    const sp<IBinder> display = ComposerServiceAIDL::getInstance().getInternalDisplayToken();
     ASSERT_FALSE(display == nullptr);
 
     DisplayCaptureArgs captureArgs;
@@ -695,12 +695,6 @@
             ISurfaceComposer::VsyncSource, ISurfaceComposer::EventRegistrationFlags) override {
         return nullptr;
     }
-    sp<IBinder> createDisplay(const String8& /*displayName*/,
-            bool /*secure*/) override { return nullptr; }
-    void destroyDisplay(const sp<IBinder>& /*display */) override {}
-    std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
-    status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override { return NO_ERROR; }
-    sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
     status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/,
                                  const Vector<ComposerState>& /*state*/,
                                  const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
@@ -739,7 +733,6 @@
         return NO_ERROR;
     }
 
-    void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
     status_t getStaticDisplayInfo(const sp<IBinder>& /*display*/, ui::StaticDisplayInfo*) override {
         return NO_ERROR;
     }
@@ -747,34 +740,15 @@
                                    ui::DynamicDisplayInfo*) override {
         return NO_ERROR;
     }
-    status_t getDisplayState(const sp<IBinder>& /*display*/, ui::DisplayState*) override {
-        return NO_ERROR;
-    }
-    status_t getDisplayStats(const sp<IBinder>& /*display*/,
-            DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
     status_t getDisplayNativePrimaries(const sp<IBinder>& /*display*/,
             ui::DisplayPrimaries& /*primaries*/) override {
         return NO_ERROR;
     }
     status_t setActiveColorMode(const sp<IBinder>& /*display*/,
         ColorMode /*colorMode*/) override { return NO_ERROR; }
-    status_t getBootDisplayModeSupport(bool* /*outSupport*/) const override { return NO_ERROR; }
     status_t setBootDisplayMode(const sp<IBinder>& /*display*/, ui::DisplayModeId /*id*/) override {
         return NO_ERROR;
     }
-    status_t clearBootDisplayMode(const sp<IBinder>& /*display*/) override { return NO_ERROR; }
-    void setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {}
-    void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {}
-
-    status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&) override {
-        return NO_ERROR;
-    }
-    status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) override {
-        return NO_ERROR;
-    }
-    status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) override {
-        return NO_ERROR;
-    }
 
     status_t clearAnimationFrameStats() override { return NO_ERROR; }
     status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
@@ -821,26 +795,6 @@
     status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
     status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
 
-    status_t isWideColorDisplay(const sp<IBinder>&, bool*) const override { return NO_ERROR; }
-    status_t getDisplayBrightnessSupport(const sp<IBinder>& /*displayToken*/,
-                                         bool* /*outSupport*/) const override {
-        return NO_ERROR;
-    }
-    status_t setDisplayBrightness(const sp<IBinder>& /*displayToken*/,
-                                  const gui::DisplayBrightness& /*brightness*/) override {
-        return NO_ERROR;
-    }
-
-    status_t addHdrLayerInfoListener(const sp<IBinder>&,
-                                     const sp<gui::IHdrLayerInfoListener>&) override {
-        return NO_ERROR;
-    }
-
-    status_t removeHdrLayerInfoListener(const sp<IBinder>&,
-                                        const sp<gui::IHdrLayerInfoListener>&) override {
-        return NO_ERROR;
-    }
-
     status_t addRegionSamplingListener(const Rect& /*samplingArea*/,
                                        const sp<IBinder>& /*stopLayerHandle*/,
                                        const sp<IRegionSamplingListener>& /*listener*/) override {
@@ -882,7 +836,6 @@
                                         float* /*outAppRequestRefreshRateMax*/) override {
         return NO_ERROR;
     };
-    status_t notifyPowerBoost(int32_t /*boostId*/) override { return NO_ERROR; }
 
     status_t setGlobalShadowSettings(const half4& /*ambientColor*/, const half4& /*spotColor*/,
                                      float /*lightPosY*/, float /*lightPosZ*/,
@@ -934,6 +887,114 @@
     bool mSupportsPresent{true};
 };
 
+class FakeSurfaceComposerAIDL : public gui::ISurfaceComposer {
+public:
+    ~FakeSurfaceComposerAIDL() override {}
+
+    void setSupportsPresent(bool supportsPresent) { mSupportsPresent = supportsPresent; }
+
+    binder::Status createDisplay(const std::string& /*displayName*/, bool /*secure*/,
+                                 sp<IBinder>* /*outDisplay*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status destroyDisplay(const sp<IBinder>& /*display*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getPhysicalDisplayIds(std::vector<int64_t>* /*outDisplayIds*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getPrimaryPhysicalDisplayId(int64_t* /*outDisplayId*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getPhysicalDisplayToken(int64_t /*displayId*/,
+                                           sp<IBinder>* /*outDisplay*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getDisplayStats(const sp<IBinder>& /*display*/,
+                                   gui::DisplayStatInfo* /*outStatInfo*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getDisplayState(const sp<IBinder>& /*display*/,
+                                   gui::DisplayState* /*outState*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status clearBootDisplayMode(const sp<IBinder>& /*display*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getBootDisplayModeSupport(bool* /*outMode*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status captureDisplay(const DisplayCaptureArgs&,
+                                  const sp<IScreenCaptureListener>&) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status captureLayers(const LayerCaptureArgs&,
+                                 const sp<IScreenCaptureListener>&) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status isWideColorDisplay(const sp<IBinder>& /*token*/,
+                                      bool* /*outIsWideColorDisplay*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getDisplayBrightnessSupport(const sp<IBinder>& /*displayToken*/,
+                                               bool* /*outSupport*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status setDisplayBrightness(const sp<IBinder>& /*displayToken*/,
+                                        const gui::DisplayBrightness& /*brightness*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status addHdrLayerInfoListener(
+            const sp<IBinder>& /*displayToken*/,
+            const sp<gui::IHdrLayerInfoListener>& /*listener*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status removeHdrLayerInfoListener(
+            const sp<IBinder>& /*displayToken*/,
+            const sp<gui::IHdrLayerInfoListener>& /*listener*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status notifyPowerBoost(int /*boostId*/) override { return binder::Status::ok(); }
+
+protected:
+    IBinder* onAsBinder() override { return nullptr; }
+
+private:
+    bool mSupportsPresent{true};
+};
+
 class FakeProducerFrameEventHistory : public ProducerFrameEventHistory {
 public:
     explicit FakeProducerFrameEventHistory(FenceToFenceTimeMap* fenceMap) : mFenceMap(fenceMap) {}
diff --git a/libs/gui/tests/VsyncEventData_test.cpp b/libs/gui/tests/VsyncEventData_test.cpp
index a670d42..f114522 100644
--- a/libs/gui/tests/VsyncEventData_test.cpp
+++ b/libs/gui/tests/VsyncEventData_test.cpp
@@ -22,54 +22,37 @@
 
 namespace android {
 
+using gui::ParcelableVsyncEventData;
 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;
+TEST(ParcelableVsyncEventData, Parcelling) {
+    ParcelableVsyncEventData data;
+    data.vsync.frameInterval = 789;
+    data.vsync.preferredFrameTimelineIndex = 1;
+    FrameTimeline timeline0 = FrameTimeline{1, 2, 3};
+    FrameTimeline timeline1 = FrameTimeline{4, 5, 6};
+    data.vsync.frameTimelines[0] = timeline0;
+    data.vsync.frameTimelines[1] = timeline1;
 
     Parcel p;
     data.writeToParcel(&p);
     p.setDataPosition(0);
 
-    VsyncEventData data2;
+    ParcelableVsyncEventData 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);
+    ASSERT_EQ(data.vsync.frameInterval, data2.vsync.frameInterval);
+    ASSERT_EQ(data.vsync.preferredFrameTimelineIndex, data2.vsync.preferredFrameTimelineIndex);
+    for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+        ASSERT_EQ(data.vsync.frameTimelines[i].vsyncId, data2.vsync.frameTimelines[i].vsyncId);
+        ASSERT_EQ(data.vsync.frameTimelines[i].deadlineTimestamp,
+                  data2.vsync.frameTimelines[i].deadlineTimestamp);
+        ASSERT_EQ(data.vsync.frameTimelines[i].expectedPresentationTime,
+                  data2.vsync.frameTimelines[i].expectedPresentationTime);
     }
 }
 
-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/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index ff3ba2a..ff9bae2 100644
--- a/libs/gui/tests/WindowInfo_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -49,8 +49,8 @@
     i.windowToken = new BBinder();
     i.id = 1;
     i.name = "Foobar";
-    i.flags = WindowInfo::Flag::SLIPPERY;
-    i.type = WindowInfo::Type::INPUT_METHOD;
+    i.layoutParamsFlags = WindowInfo::Flag::SLIPPERY;
+    i.layoutParamsType = WindowInfo::Type::INPUT_METHOD;
     i.dispatchingTimeout = 12s;
     i.frameLeft = 93;
     i.frameTop = 34;
@@ -60,15 +60,12 @@
     i.globalScaleFactor = 0.3;
     i.alpha = 0.7;
     i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1});
-    i.visible = false;
-    i.focusable = false;
-    i.hasWallpaper = false;
-    i.paused = false;
     i.touchOcclusionMode = TouchOcclusionMode::ALLOW;
     i.ownerPid = 19;
     i.ownerUid = 24;
     i.packageName = "com.example.package";
     i.inputFeatures = WindowInfo::Feature::DISABLE_USER_ACTIVITY;
+    i.inputConfig = WindowInfo::InputConfig::NOT_FOCUSABLE;
     i.displayId = 34;
     i.replaceTouchableRegionWithCrop = true;
     i.touchableRegionCropHandle = touchableRegionCropHandle;
@@ -85,8 +82,8 @@
     ASSERT_EQ(i.windowToken, i2.windowToken);
     ASSERT_EQ(i.id, i2.id);
     ASSERT_EQ(i.name, i2.name);
-    ASSERT_EQ(i.flags, i2.flags);
-    ASSERT_EQ(i.type, i2.type);
+    ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags);
+    ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType);
     ASSERT_EQ(i.dispatchingTimeout, i2.dispatchingTimeout);
     ASSERT_EQ(i.frameLeft, i2.frameLeft);
     ASSERT_EQ(i.frameTop, i2.frameTop);
@@ -96,15 +93,12 @@
     ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor);
     ASSERT_EQ(i.alpha, i2.alpha);
     ASSERT_EQ(i.transform, i2.transform);
-    ASSERT_EQ(i.visible, i2.visible);
-    ASSERT_EQ(i.focusable, i2.focusable);
-    ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper);
-    ASSERT_EQ(i.paused, i2.paused);
     ASSERT_EQ(i.touchOcclusionMode, i2.touchOcclusionMode);
     ASSERT_EQ(i.ownerPid, i2.ownerPid);
     ASSERT_EQ(i.ownerUid, i2.ownerUid);
     ASSERT_EQ(i.packageName, i2.packageName);
     ASSERT_EQ(i.inputFeatures, i2.inputFeatures);
+    ASSERT_EQ(i.inputConfig, i2.inputConfig);
     ASSERT_EQ(i.displayId, i2.displayId);
     ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop);
     ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle);
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 3073d94..fe1754c 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -846,6 +846,7 @@
     return calculateTransformedXYUnchecked(source, transform, xy);
 }
 
+// Keep in sync with calculateTransformedCoords.
 float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source,
                                                  const ui::Transform& transform,
                                                  const PointerCoords& coords) {
@@ -874,6 +875,34 @@
     return coords.getAxisValue(axis);
 }
 
+// Keep in sync with calculateTransformedAxisValue. This is an optimization of
+// calculateTransformedAxisValue for all PointerCoords axes.
+PointerCoords MotionEvent::calculateTransformedCoords(uint32_t source,
+                                                      const ui::Transform& transform,
+                                                      const PointerCoords& coords) {
+    if (shouldDisregardTransformation(source)) {
+        return coords;
+    }
+    PointerCoords out = coords;
+
+    const vec2 xy = calculateTransformedXYUnchecked(source, transform, coords.getXYValue());
+    out.setAxisValue(AMOTION_EVENT_AXIS_X, xy.x);
+    out.setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y);
+
+    const vec2 relativeXy =
+            transformWithoutTranslation(transform,
+                                        {coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
+                                         coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)});
+    out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, relativeXy.x);
+    out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, relativeXy.y);
+
+    out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
+                     transformAngle(transform,
+                                    coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)));
+
+    return out;
+}
+
 // --- FocusEvent ---
 
 void FocusEvent::initialize(int32_t id, bool hasFocus) {
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index b182a4a..a3eebdd 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -78,7 +78,7 @@
 struct FrameCallback {
     AChoreographer_frameCallback callback;
     AChoreographer_frameCallback64 callback64;
-    AChoreographer_extendedFrameCallback extendedCallback;
+    AChoreographer_vsyncCallback vsyncCallback;
     void* data;
     nsecs_t dueTime;
 
@@ -103,9 +103,7 @@
 struct ChoreographerFrameCallbackDataImpl {
     int64_t frameTimeNanos{0};
 
-    std::array<VsyncEventData::FrameTimeline, VsyncEventData::kFrameTimelinesLength> frameTimelines;
-
-    size_t preferredFrameTimelineIndex;
+    VsyncEventData vsyncEventData;
 
     const Choreographer* choreographer;
 };
@@ -123,7 +121,7 @@
     explicit Choreographer(const sp<Looper>& looper) EXCLUDES(gChoreographers.lock);
     void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
                                   AChoreographer_frameCallback64 cb64,
-                                  AChoreographer_extendedFrameCallback extendedCallback, void* data,
+                                  AChoreographer_vsyncCallback vsyncCallback, void* data,
                                   nsecs_t delay);
     void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data)
             EXCLUDES(gChoreographers.lock);
@@ -232,10 +230,10 @@
 
 void Choreographer::postFrameCallbackDelayed(AChoreographer_frameCallback cb,
                                              AChoreographer_frameCallback64 cb64,
-                                             AChoreographer_extendedFrameCallback extendedCallback,
-                                             void* data, nsecs_t delay) {
+                                             AChoreographer_vsyncCallback vsyncCallback, void* data,
+                                             nsecs_t delay) {
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    FrameCallback callback{cb, cb64, extendedCallback, data, now + delay};
+    FrameCallback callback{cb, cb64, vsyncCallback, data, now + delay};
     {
         std::lock_guard<std::mutex> _l{mLock};
         mFrameCallbacks.push(callback);
@@ -391,13 +389,13 @@
     }
     mLastVsyncEventData = vsyncEventData;
     for (const auto& cb : callbacks) {
-        if (cb.extendedCallback != nullptr) {
+        if (cb.vsyncCallback != nullptr) {
             const ChoreographerFrameCallbackDataImpl frameCallbackData =
                     createFrameCallbackData(timestamp);
             mInCallback = true;
-            cb.extendedCallback(reinterpret_cast<const AChoreographerFrameCallbackData*>(
-                                        &frameCallbackData),
-                                cb.data);
+            cb.vsyncCallback(reinterpret_cast<const AChoreographerFrameCallbackData*>(
+                                     &frameCallbackData),
+                             cb.data);
             mInCallback = false;
         } else if (cb.callback64 != nullptr) {
             cb.callback64(timestamp, cb.data);
@@ -450,8 +448,7 @@
 
 ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const {
     return {.frameTimeNanos = timestamp,
-            .preferredFrameTimelineIndex = mLastVsyncEventData.preferredFrameTimelineIndex,
-            .frameTimelines = mLastVsyncEventData.frameTimelines,
+            .vsyncEventData = mLastVsyncEventData,
             .choreographer = this};
 }
 
@@ -525,10 +522,9 @@
                                                     void* data, uint32_t delayMillis) {
     return AChoreographer_postFrameCallbackDelayed64(choreographer, callback, data, delayMillis);
 }
-void AChoreographer_routePostExtendedFrameCallback(AChoreographer* choreographer,
-                                                   AChoreographer_extendedFrameCallback callback,
-                                                   void* data) {
-    return AChoreographer_postExtendedFrameCallback(choreographer, callback, data);
+void AChoreographer_routePostVsyncCallback(AChoreographer* choreographer,
+                                           AChoreographer_vsyncCallback callback, void* data) {
+    return AChoreographer_postVsyncCallback(choreographer, callback, data);
 }
 void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
                                                      AChoreographer_refreshRateCallback callback,
@@ -556,9 +552,10 @@
         const AChoreographerFrameCallbackData* data, size_t index) {
     return AChoreographerFrameCallbackData_getFrameTimelineVsyncId(data, index);
 }
-int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTimeNanos(
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentationTimeNanos(
         const AChoreographerFrameCallbackData* data, size_t index) {
-    return AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos(data, index);
+    return AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(data,
+                                                                                         index);
 }
 int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadlineNanos(
         const AChoreographerFrameCallbackData* data, size_t index) {
@@ -592,9 +589,8 @@
     AChoreographer_to_Choreographer(choreographer)
             ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, ms2ns(delayMillis));
 }
-void AChoreographer_postExtendedFrameCallback(AChoreographer* choreographer,
-                                              AChoreographer_extendedFrameCallback callback,
-                                              void* data) {
+void AChoreographer_postVsyncCallback(AChoreographer* choreographer,
+                                      AChoreographer_vsyncCallback callback, void* data) {
     AChoreographer_to_Choreographer(choreographer)
             ->postFrameCallbackDelayed(nullptr, nullptr, callback, data, 0);
 }
@@ -634,7 +630,7 @@
             AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
     LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
                         "Data is only valid in callback");
-    return frameCallbackData->frameTimelines.size();
+    return VsyncEventData::kFrameTimelinesLength;
 }
 size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
         const AChoreographerFrameCallbackData* data) {
@@ -642,7 +638,7 @@
             AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
     LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
                         "Data is only valid in callback");
-    return frameCallbackData->preferredFrameTimelineIndex;
+    return frameCallbackData->vsyncEventData.preferredFrameTimelineIndex;
 }
 AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
         const AChoreographerFrameCallbackData* data, size_t index) {
@@ -650,17 +646,17 @@
             AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
     LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
                         "Data is only valid in callback");
-    LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
-    return frameCallbackData->frameTimelines[index].id;
+    LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds");
+    return frameCallbackData->vsyncEventData.frameTimelines[index].vsyncId;
 }
-int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos(
+int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(
         const AChoreographerFrameCallbackData* data, size_t index) {
     const ChoreographerFrameCallbackDataImpl* frameCallbackData =
             AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
     LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
                         "Data is only valid in callback");
-    LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
-    return frameCallbackData->frameTimelines[index].expectedPresentTime;
+    LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds");
+    return frameCallbackData->vsyncEventData.frameTimelines[index].expectedPresentationTime;
 }
 int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(
         const AChoreographerFrameCallbackData* data, size_t index) {
@@ -668,8 +664,8 @@
             AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
     LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
                         "Data is only valid in callback");
-    LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
-    return frameCallbackData->frameTimelines[index].deadlineTimestamp;
+    LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds");
+    return frameCallbackData->vsyncEventData.frameTimelines[index].deadlineTimestamp;
 }
 
 AChoreographer* AChoreographer_create() {
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
index d650c26..19be5bd 100644
--- a/libs/nativedisplay/include-private/private/android/choreographer.h
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -50,9 +50,8 @@
 void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer,
                                                     AChoreographer_frameCallback64 callback,
                                                     void* data, uint32_t delayMillis);
-void AChoreographer_routePostExtendedFrameCallback(AChoreographer* choreographer,
-                                                   AChoreographer_extendedFrameCallback callback,
-                                                   void* data);
+void AChoreographer_routePostVsyncCallback(AChoreographer* choreographer,
+                                           AChoreographer_vsyncCallback callback, void* data);
 void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
                                                      AChoreographer_refreshRateCallback callback,
                                                      void* data);
@@ -67,7 +66,7 @@
         const AChoreographerFrameCallbackData* data);
 AVsyncId AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId(
         const AChoreographerFrameCallbackData* data, size_t index);
-int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTimeNanos(
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentationTimeNanos(
         const AChoreographerFrameCallbackData* data, size_t index);
 int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadlineNanos(
         const AChoreographerFrameCallbackData* data, size_t index);
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 6579313..2da10cd 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -7,12 +7,12 @@
     AChoreographer_postFrameCallbackDelayed64; # apex # introduced=30
     AChoreographer_registerRefreshRateCallback; # apex # introduced=30
     AChoreographer_unregisterRefreshRateCallback; # apex # introduced=30
-    AChoreographer_postExtendedFrameCallback; # apex # introduced=33
+    AChoreographer_postVsyncCallback; # apex # introduced=33
     AChoreographerFrameCallbackData_getFrameTimeNanos; # apex # introduced=33
     AChoreographerFrameCallbackData_getFrameTimelinesLength; # apex # introduced=33
     AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex; # apex # introduced=33
     AChoreographerFrameCallbackData_getFrameTimelineVsyncId; # apex # introduced=33
-    AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos; # apex # introduced=33
+    AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos; # apex # introduced=33
     AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos; # apex # introduced=33
     AChoreographer_create; # apex # introduced=30
     AChoreographer_destroy; # apex # introduced=30
@@ -35,12 +35,12 @@
       android::AChoreographer_routePostFrameCallbackDelayed64*;
       android::AChoreographer_routeRegisterRefreshRateCallback*;
       android::AChoreographer_routeUnregisterRefreshRateCallback*;
-      android::AChoreographer_routePostExtendedFrameCallback*;
+      android::AChoreographer_routePostVsyncCallback*;
       android::AChoreographerFrameCallbackData_routeGetFrameTimeNanos*;
       android::AChoreographerFrameCallbackData_routeGetFrameTimelinesLength*;
       android::AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex*;
       android::AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId*;
-      android::AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTimeNanos*;
+      android::AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentationTimeNanos*;
       android::AChoreographerFrameCallbackData_routeGetFrameTimelineDeadlineNanos*;
       android::AChoreographer_signalRefreshRateCallbacks*;
       android::AChoreographer_getFrameInterval*;
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 2578ee8..576941f 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -353,12 +353,12 @@
         return INVALID_OPERATION;
     }
 
-    GraphicBuffer* gBuffer = new GraphicBuffer();
+    sp<GraphicBuffer> gBuffer(new GraphicBuffer());
     status_t err = gBuffer->unflatten(data, dataLen, fdData, fdCount);
     if (err != NO_ERROR) {
         return err;
     }
-    *outBuffer = AHardwareBuffer_from_GraphicBuffer(gBuffer);
+    *outBuffer = AHardwareBuffer_from_GraphicBuffer(gBuffer.get());
     // Ensure the buffer has a positive ref-count.
     AHardwareBuffer_acquire(*outBuffer);
 
@@ -584,6 +584,8 @@
             "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_YCBCR_422_I == AHARDWAREBUFFER_FORMAT_YCbCr_422_I,
             "HAL and AHardwareBuffer pixel format don't match");
+    static_assert(HAL_PIXEL_FORMAT_YCBCR_P010 == AHARDWAREBUFFER_FORMAT_YCbCr_P010,
+            "HAL and AHardwareBuffer pixel format don't match");
     static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_8) ==
                           AHARDWAREBUFFER_FORMAT_R8_UNORM,
             "HAL and AHardwareBuffer pixel format don't match");
@@ -617,6 +619,7 @@
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
         case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
+        case AHARDWAREBUFFER_FORMAT_YCbCr_P010:
             return true;
 
         default:
@@ -633,6 +636,7 @@
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
         case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
+        case AHARDWAREBUFFER_FORMAT_YCbCr_P010:
             return true;
         default:
             return false;
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 6f1f04d..c35507b 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -160,6 +160,14 @@
     AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420             = 0x23,
 
     /**
+     * YUV P010 format.
+     * Must have an even width and height. Can be accessed in OpenGL
+     * shaders through an external sampler. Does not support mip-maps
+     * cube-maps or multi-layered textures.
+     */
+    AHARDWAREBUFFER_FORMAT_YCbCr_P010               = 0x36,
+
+    /**
      * Corresponding formats:
      *   Vulkan: VK_FORMAT_R8_UNORM
      *   OpenGL ES: GR_GL_R8
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index 2c51ccd..40ba5ad 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -54,6 +54,10 @@
     // dataspace, in non-linear space.
     mat4 colorTransform = mat4();
 
+    // If true, and colorTransform is non-identity, most client draw calls can
+    // ignore it. Some draws (e.g. screen decorations) may need it, though.
+    bool deviceHandlesColorTransform = false;
+
     // An additional orientation flag to be applied after clipping the output.
     // By way of example, this may be used for supporting fullscreen screenshot
     // capture of a device in landscape while the buffer is in portrait
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 763b82d..b467b35 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -792,7 +792,7 @@
 
     // setup color filter if necessary
     sk_sp<SkColorFilter> displayColorTransform;
-    if (display.colorTransform != mat4()) {
+    if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
         displayColorTransform = SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform));
     }
     const bool ctModifiesAlpha =
@@ -1107,11 +1107,37 @@
 
             if (imageTextureRef->colorType() == kAlpha_8_SkColorType) {
                 LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with A8");
-                float matrix[] = { 0, 0, 0, 0, 0,
-                                   0, 0, 0, 0, 0,
-                                   0, 0, 0, 0, 0,
-                                   0, 0, 0, -1, 1 };
-                paint.setColorFilter(SkColorFilters::Matrix(matrix));
+
+                // SysUI creates the alpha layer as a coverage layer, which is
+                // appropriate for the DPU. Use a color matrix to convert it to
+                // a mask.
+                // TODO (b/219525258): Handle input as a mask.
+                //
+                // The color matrix will convert A8 pixels with no alpha to
+                // black, as described by this vector. If the display handles
+                // the color transform, we need to invert it to find the color
+                // that will result in black after the DPU applies the transform.
+                SkV4 black{0.0f, 0.0f, 0.0f, 1.0f}; // r, g, b, a
+                if (display.colorTransform != mat4() && display.deviceHandlesColorTransform) {
+                    SkM44 colorSpaceMatrix = getSkM44(display.colorTransform);
+                    if (colorSpaceMatrix.invert(&colorSpaceMatrix)) {
+                        black = colorSpaceMatrix * black;
+                    } else {
+                        // We'll just have to use 0,0,0 as black, which should
+                        // be close to correct.
+                        ALOGI("Could not invert colorTransform!");
+                    }
+                }
+                SkColorMatrix colorMatrix(0, 0, 0, 0, black[0],
+                                          0, 0, 0, 0, black[1],
+                                          0, 0, 0, 0, black[2],
+                                          0, 0, 0, -1, 1);
+                if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
+                    // On the other hand, if the device doesn't handle it, we
+                    // have to apply it ourselves.
+                    colorMatrix.postConcat(toSkColorMatrix(display.colorTransform));
+                }
+                paint.setColorFilter(SkColorFilters::Matrix(colorMatrix));
             }
         } else {
             ATRACE_NAME("DrawColor");
@@ -1134,8 +1160,8 @@
             paint.setBlendMode(SkBlendMode::kSrc);
         }
 
-        // A color filter will have been set for an A8 buffer. Do not replace
-        // it with the displayColorTransform, which shouldn't affect A8.
+        // An A8 buffer will already have the proper color filter attached to
+        // its paint, including the displayColorTransform as needed.
         if (!paint.getColorFilter()) {
             paint.setColorFilter(displayColorTransform);
         }
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index e197150..add7a94 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -2627,6 +2627,7 @@
 
     const auto r8Buffer = allocateR8Buffer(2, 1);
     if (!r8Buffer) {
+        GTEST_SKIP() << "Test is only necessary on devices that support r8";
         return;
     }
     {
@@ -2677,6 +2678,144 @@
     expectBufferColor(Rect(0, 0, 1, 1), 0,   0, 0, 255);
     expectBufferColor(Rect(1, 0, 2, 1), 0, 255, 0, 255);
 }
+
+TEST_P(RenderEngineTest, r8_respects_color_transform) {
+    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+        return;
+    }
+
+    initializeRenderEngine();
+
+    const auto r8Buffer = allocateR8Buffer(2, 1);
+    if (!r8Buffer) {
+        GTEST_SKIP() << "Test is only necessary on devices that support r8";
+        return;
+    }
+    {
+        uint8_t* pixels;
+        r8Buffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                    reinterpret_cast<void**>(&pixels));
+        pixels[0] = 0;
+        pixels[1] = 255;
+        r8Buffer->getBuffer()->unlock();
+    }
+
+    const auto rect = Rect(0, 0, 2, 1);
+    const renderengine::DisplaySettings display{
+            .physicalDisplay = rect,
+            .clip = rect,
+            .outputDataspace = ui::Dataspace::SRGB,
+            // Verify that the R8 layer respects the color transform when
+            // deviceHandlesColorTransform is false. This transform converts
+            // pure red to pure green. That will occur when the R8 buffer is
+            // 255. When the R8 buffer is 0, it will still change to black, as
+            // with r8_behaves_as_mask.
+            .colorTransform = mat4(0, 1, 0, 0,
+                                   0, 0, 0, 0,
+                                   0, 0, 1, 0,
+                                   0, 0, 0, 1),
+            .deviceHandlesColorTransform = false,
+    };
+
+    const auto redBuffer = allocateAndFillSourceBuffer(2, 1, ubyte4(255, 0, 0, 255));
+    const renderengine::LayerSettings redLayer{
+            .geometry.boundaries = rect.toFloatRect(),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = redBuffer,
+                                    },
+                    },
+            .alpha = 1.0f,
+    };
+    const renderengine::LayerSettings r8Layer{
+            .geometry.boundaries = rect.toFloatRect(),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = r8Buffer,
+                                    },
+                    },
+            .alpha = 1.0f,
+    };
+
+    std::vector<renderengine::LayerSettings> layers{redLayer, r8Layer};
+    invokeDraw(display, layers);
+
+    expectBufferColor(Rect(0, 0, 1, 1), 0,   0, 0, 255);
+    expectBufferColor(Rect(1, 0, 2, 1), 0, 255, 0, 255);
+}
+
+TEST_P(RenderEngineTest, r8_respects_color_transform_when_device_handles) {
+    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+        return;
+    }
+
+    initializeRenderEngine();
+
+    const auto r8Buffer = allocateR8Buffer(2, 1);
+    if (!r8Buffer) {
+        GTEST_SKIP() << "Test is only necessary on devices that support r8";
+        return;
+    }
+    {
+        uint8_t* pixels;
+        r8Buffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                    reinterpret_cast<void**>(&pixels));
+        pixels[0] = 0;
+        pixels[1] = 255;
+        r8Buffer->getBuffer()->unlock();
+    }
+
+    const auto rect = Rect(0, 0, 2, 1);
+    const renderengine::DisplaySettings display{
+            .physicalDisplay = rect,
+            .clip = rect,
+            .outputDataspace = ui::Dataspace::SRGB,
+            // If deviceHandlesColorTransform is true, pixels where the A8
+            // buffer is opaque are unaffected. If the colorTransform is
+            // invertible, pixels where the A8 buffer are transparent have the
+            // inverse applied to them so that the DPU will convert them back to
+            // black. Test with an arbitrary, invertible matrix.
+            .colorTransform = mat4(1, 0, 0, 2,
+                                   3, 1, 2, 5,
+                                   0, 5, 3, 0,
+                                   0, 1, 0, 2),
+            .deviceHandlesColorTransform = true,
+    };
+
+    const auto redBuffer = allocateAndFillSourceBuffer(2, 1, ubyte4(255, 0, 0, 255));
+    const renderengine::LayerSettings redLayer{
+            .geometry.boundaries = rect.toFloatRect(),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = redBuffer,
+                                    },
+                    },
+            .alpha = 1.0f,
+    };
+    const renderengine::LayerSettings r8Layer{
+            .geometry.boundaries = rect.toFloatRect(),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = r8Buffer,
+                                    },
+                    },
+            .alpha = 1.0f,
+    };
+
+    std::vector<renderengine::LayerSettings> layers{redLayer, r8Layer};
+    invokeDraw(display, layers);
+
+    expectBufferColor(Rect(1, 0, 2, 1), 255, 0, 0, 255); // Still red.
+    expectBufferColor(Rect(0, 0, 1, 1), 0,  70, 0, 255);
+}
 } // namespace renderengine
 } // namespace android
 
diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp
index ef3ceda..2be98e7 100644
--- a/libs/sensorprivacy/SensorPrivacyManager.cpp
+++ b/libs/sensorprivacy/SensorPrivacyManager.cpp
@@ -55,12 +55,12 @@
     return service;
 }
 
-bool SensorPrivacyManager::supportsSensorToggle(int sensor) {
+bool SensorPrivacyManager::supportsSensorToggle(int toggleType, int sensor) {
     if (mSupportedCache.find(sensor) == mSupportedCache.end()) {
         sp<hardware::ISensorPrivacyManager> service = getService();
         if (service != nullptr) {
             bool result;
-            service->supportsSensorToggle(sensor, &result);
+            service->supportsSensorToggle(toggleType, sensor, &result);
             mSupportedCache[sensor] = result;
             return result;
         }
@@ -80,12 +80,12 @@
     }
 }
 
-status_t SensorPrivacyManager::addIndividualSensorPrivacyListener(int userId, int sensor,
+status_t SensorPrivacyManager::addToggleSensorPrivacyListener(
         const sp<hardware::ISensorPrivacyListener>& listener)
 {
     sp<hardware::ISensorPrivacyManager> service = getService();
     if (service != nullptr) {
-        return service->addIndividualSensorPrivacyListener(userId, sensor, listener)
+        return service->addToggleSensorPrivacyListener(listener)
                 .transactionError();
     }
     return UNEXPECTED_NULL;
@@ -100,12 +100,12 @@
     }
 }
 
-void SensorPrivacyManager::removeIndividualSensorPrivacyListener(int sensor,
+void SensorPrivacyManager::removeToggleSensorPrivacyListener(
         const sp<hardware::ISensorPrivacyListener>& listener)
 {
     sp<hardware::ISensorPrivacyManager> service = getService();
     if (service != nullptr) {
-        service->removeIndividualSensorPrivacyListener(sensor, listener);
+        service->removeToggleSensorPrivacyListener(listener);
     }
 }
 
@@ -121,24 +121,36 @@
     return false;
 }
 
-bool SensorPrivacyManager::isIndividualSensorPrivacyEnabled(int userId, int sensor)
+bool SensorPrivacyManager::isToggleSensorPrivacyEnabled(int sensor)
 {
-    sp<hardware::ISensorPrivacyManager> service = getService();
+	sp<hardware::ISensorPrivacyManager> service = getService();
     if (service != nullptr) {
         bool result;
-        service->isIndividualSensorPrivacyEnabled(userId, sensor, &result);
+        service->isCombinedToggleSensorPrivacyEnabled(sensor, &result);
         return result;
     }
     // if the SensorPrivacyManager is not available then assume sensor privacy is disabled
     return false;
 }
 
-status_t SensorPrivacyManager::isIndividualSensorPrivacyEnabled(int userId, int sensor,
+bool SensorPrivacyManager::isToggleSensorPrivacyEnabled(int toggleType, int sensor)
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        bool result;
+        service->isToggleSensorPrivacyEnabled(toggleType, sensor, &result);
+        return result;
+    }
+    // if the SensorPrivacyManager is not available then assume sensor privacy is disabled
+    return false;
+}
+
+status_t SensorPrivacyManager::isToggleSensorPrivacyEnabled(int toggleType, int sensor,
         bool &returnVal)
 {
     sp<hardware::ISensorPrivacyManager> service = getService();
     if (service != nullptr) {
-        binder::Status res = service->isIndividualSensorPrivacyEnabled(userId, sensor, &returnVal);
+        binder::Status res = service->isToggleSensorPrivacyEnabled(toggleType, sensor, &returnVal);
         return res.transactionError();
     }
     // if the SensorPrivacyManager is not available then assume sensor privacy is disabled
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
index 58177d8..eccd54c 100644
--- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
@@ -20,5 +20,5 @@
  * @hide
  */
 oneway interface ISensorPrivacyListener {
-    void onSensorPrivacyChanged(boolean enabled);
+    void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled);
 }
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
index 9564cba..49a1e1e 100644
--- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
@@ -20,23 +20,25 @@
 
 /** @hide */
 interface ISensorPrivacyManager {
-    boolean supportsSensorToggle(int sensor);
+    boolean supportsSensorToggle(int toggleType, int sensor);
 
     void addSensorPrivacyListener(in ISensorPrivacyListener listener);
 
-    void addIndividualSensorPrivacyListener(int userId, int sensor, in ISensorPrivacyListener listener);
+    void addToggleSensorPrivacyListener(in ISensorPrivacyListener listener);
 
     void removeSensorPrivacyListener(in ISensorPrivacyListener listener);
 
-    void removeIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
+    void removeToggleSensorPrivacyListener(in ISensorPrivacyListener listener);
 
     boolean isSensorPrivacyEnabled();
 
-    boolean isIndividualSensorPrivacyEnabled(int userId, int sensor);
+    boolean isCombinedToggleSensorPrivacyEnabled(int sensor);
+
+    boolean isToggleSensorPrivacyEnabled(int toggleType, int sensor);
 
     void setSensorPrivacy(boolean enable);
 
-    void setIndividualSensorPrivacy(int userId, int source, int sensor, boolean enable);
+    void setToggleSensorPrivacy(int userId, int source, int sensor, boolean enable);
 
-    void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
+    void setToggleSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
 }
diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
index af699d0..fc5fdf7 100644
--- a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
+++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
@@ -31,22 +31,26 @@
 {
 public:
     enum {
-        INDIVIDUAL_SENSOR_MICROPHONE = 1,
-        INDIVIDUAL_SENSOR_CAMERA = 2
+        TOGGLE_SENSOR_MICROPHONE = 1,
+        TOGGLE_SENSOR_CAMERA = 2
+    };
+
+    enum {
+        TOGGLE_TYPE_SOFTWARE = 1,
+        TOGGLE_TYPE_HARDWARE = 2
     };
 
     SensorPrivacyManager();
 
-    bool supportsSensorToggle(int sensor);
+    bool supportsSensorToggle(int toggleType, int sensor);
     void addSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
-    status_t addIndividualSensorPrivacyListener(int userId, int sensor,
-            const sp<hardware::ISensorPrivacyListener>& listener);
+    status_t addToggleSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
     void removeSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
-    void removeIndividualSensorPrivacyListener(int sensor,
-            const sp<hardware::ISensorPrivacyListener>& listener);
+    void removeToggleSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
     bool isSensorPrivacyEnabled();
-    bool isIndividualSensorPrivacyEnabled(int userId, int sensor);
-    status_t isIndividualSensorPrivacyEnabled(int userId, int sensor, bool &result);
+    bool isToggleSensorPrivacyEnabled(int sensor);
+    bool isToggleSensorPrivacyEnabled(int toggleType, int sensor);
+    status_t isToggleSensorPrivacyEnabled(int toggleType, int sensor, bool &result);
 
     status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
     status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 41e9ce2..9691ad8 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -61,18 +61,13 @@
         ALOGE("There is no focused window for %s", applicationHandle->getName().c_str());
     }
 
-    void notifyWindowUnresponsive(const sp<IBinder>& connectionToken,
+    void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, std::optional<int32_t> pid,
                                   const std::string& reason) override {
         ALOGE("Window is not responding: %s", reason.c_str());
     }
 
-    void notifyWindowResponsive(const sp<IBinder>& connectionToken) override {}
-
-    void notifyMonitorUnresponsive(int32_t pid, const std::string& reason) override {
-        ALOGE("Monitor is not responding: %s", reason.c_str());
-    }
-
-    void notifyMonitorResponsive(int32_t pid) override {}
+    void notifyWindowResponsive(const sp<IBinder>& connectionToken,
+                                std::optional<int32_t> pid) override {}
 
     void notifyInputChannelBroken(const sp<IBinder>&) override {}
 
@@ -193,7 +188,6 @@
     void updateInfo() {
         mInfo.token = mClientChannel->getConnectionToken();
         mInfo.name = "FakeWindowHandle";
-        mInfo.type = WindowInfo::Type::APPLICATION;
         mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
         mInfo.frameLeft = mFrame.left;
         mInfo.frameTop = mFrame.top;
@@ -202,10 +196,6 @@
         mInfo.globalScaleFactor = 1.0;
         mInfo.touchableRegion.clear();
         mInfo.addTouchableRegion(mFrame);
-        mInfo.visible = true;
-        mInfo.focusable = true;
-        mInfo.hasWallpaper = false;
-        mInfo.paused = false;
         mInfo.ownerPid = INJECTOR_PID;
         mInfo.ownerUid = INJECTOR_UID;
         mInfo.displayId = ADISPLAY_ID_DEFAULT;
diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp
index 600f02b..a02b3e8 100644
--- a/services/inputflinger/dispatcher/FocusResolver.cpp
+++ b/services/inputflinger/dispatcher/FocusResolver.cpp
@@ -148,11 +148,11 @@
             continue;
         }
         windowFound = true;
-        if (window->getInfo()->visible) {
+        if (!window->getInfo()->inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE)) {
             // Check if at least a single window is visible.
             visibleWindowFound = true;
         }
-        if (!window->getInfo()->focusable) {
+        if (window->getInfo()->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE)) {
             // Check if all windows with the window token are focusable.
             allWindowsAreFocusable = false;
             break;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 7062aef..99d23af 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -118,10 +118,7 @@
 // when an application takes too long to respond and the user has pressed an app switch key.
 constexpr nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec
 
-// Amount of time to allow for an event to be dispatched (measured since its eventTime)
-// before considering it stale and dropping it.
-const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL // 10sec
-        * HwTimeoutMultiplier();
+const std::chrono::duration STALE_EVENT_TIMEOUT = std::chrono::seconds(10) * HwTimeoutMultiplier();
 
 // Log a warning when an event takes longer than this to process, even if an ANR does not occur.
 constexpr nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec
@@ -322,10 +319,6 @@
             first->applicationInfo.token == second->applicationInfo.token;
 }
 
-bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
-    return currentTime - entry.eventTime >= STALE_EVENT_TIMEOUT;
-}
-
 std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
                                                    std::shared_ptr<EventEntry> eventEntry,
                                                    int32_t inputTargetFlags) {
@@ -500,17 +493,16 @@
 // Returns true if the given window can accept pointer events at the given display location.
 bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y,
                           bool isStylus) {
-    if (windowInfo.displayId != displayId || !windowInfo.visible) {
+    const auto inputConfig = windowInfo.inputConfig;
+    if (windowInfo.displayId != displayId ||
+        inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
         return false;
     }
-    const auto flags = windowInfo.flags;
     const bool windowCanInterceptTouch = isStylus && windowInfo.interceptsStylus();
-    if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE) && !windowCanInterceptTouch) {
+    if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) {
         return false;
     }
-    const bool isModalWindow = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) &&
-            !flags.test(WindowInfo::Flag::NOT_TOUCH_MODAL);
-    if (!isModalWindow && !windowInfo.touchableRegionContainsPoint(x, y)) {
+    if (!windowInfo.touchableRegionContainsPoint(x, y)) {
         return false;
     }
     return true;
@@ -527,6 +519,10 @@
 // --- InputDispatcher ---
 
 InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
+      : InputDispatcher(policy, STALE_EVENT_TIMEOUT) {}
+
+InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy,
+                                 std::chrono::nanoseconds staleEventTimeout)
       : mPolicy(policy),
         mPendingEvent(nullptr),
         mLastDropReason(DropReason::NOT_DROPPED),
@@ -545,6 +541,7 @@
         mMaximumObscuringOpacityForTouch(1.0f),
         mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
         mWindowTokenWithPointerCapture(nullptr),
+        mStaleEventTimeout(staleEventTimeout),
         mLatencyAggregator(),
         mLatencyTracker(&mLatencyAggregator) {
     mLooper = new Looper(false);
@@ -902,6 +899,10 @@
     }
 }
 
+bool InputDispatcher::isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
+    return std::chrono::nanoseconds(currentTime - entry.eventTime) >= mStaleEventTimeout;
+}
+
 /**
  * Return true if the events preceding this incoming motion event should be dropped
  * Return false otherwise (the default behaviour)
@@ -1047,7 +1048,8 @@
             return windowHandle;
         }
 
-        if (addOutsideTargets && info.flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
+        if (addOutsideTargets &&
+            info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) {
             touchState->addOrUpdateWindow(windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE,
                                           BitSet32(0));
         }
@@ -1900,7 +1902,8 @@
         return InputEventInjectionResult::PERMISSION_DENIED;
     }
 
-    if (focusedWindowHandle->getInfo()->paused) {
+    if (focusedWindowHandle->getInfo()->inputConfig.test(
+                WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
         ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str());
         return InputEventInjectionResult::PENDING;
     }
@@ -2101,7 +2104,7 @@
         for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
             const WindowInfo& info = *windowHandle->getInfo();
 
-            if (info.paused) {
+            if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
                 ALOGI("Not sending touch event to %s because it is paused",
                       windowHandle->getName().c_str());
                 continue;
@@ -2324,13 +2327,16 @@
     if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
         sp<WindowInfoHandle> foregroundWindowHandle =
                 tempTouchState.getFirstForegroundWindowHandle();
-        if (foregroundWindowHandle && foregroundWindowHandle->getInfo()->hasWallpaper) {
+        if (foregroundWindowHandle &&
+            foregroundWindowHandle->getInfo()->inputConfig.test(
+                    WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
             const std::vector<sp<WindowInfoHandle>>& windowHandles =
                     getWindowHandlesLocked(displayId);
             for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
                 const WindowInfo* info = windowHandle->getInfo();
                 if (info->displayId == displayId &&
-                    windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) {
+                    windowHandle->getInfo()->inputConfig.test(
+                            WindowInfo::InputConfig::IS_WALLPAPER)) {
                     tempTouchState
                             .addOrUpdateWindow(windowHandle,
                                                InputTarget::FLAG_WINDOW_IS_OBSCURED |
@@ -2599,9 +2605,10 @@
     }
     auto info = windowHandle->getInfo();
     auto otherInfo = otherHandle->getInfo();
-    if (!otherInfo->visible) {
+    if (otherInfo->inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
         return false;
-    } else if (otherInfo->alpha == 0 && otherInfo->flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {
+    } else if (otherInfo->alpha == 0 &&
+               otherInfo->inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE)) {
         // Those act as if they were invisible, so we don't need to flag them.
         // We do want to potentially flag touchable windows even if they have 0
         // opacity, since they can consume touches and alter the effects of the
@@ -2613,7 +2620,7 @@
         // If ownerUid is the same we don't generate occlusion events as there
         // is no security boundary within an uid.
         return false;
-    } else if (otherInfo->trustedOverlay) {
+    } else if (otherInfo->inputConfig.test(gui::WindowInfo::InputConfig::TRUSTED_OVERLAY)) {
         return false;
     } else if (otherInfo->displayId != info->displayId) {
         return false;
@@ -2694,17 +2701,17 @@
 std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info,
                                                          bool isTouchedWindow) const {
     return StringPrintf(INDENT2
-                        "* %stype=%s, package=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, "
+                        "* %spackage=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, "
                         "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32
-                        "], touchableRegion=%s, window={%s}, flags={%s}, inputFeatures={%s}, "
+                        "], touchableRegion=%s, window={%s}, inputConfig={%s}, inputFeatures={%s}, "
                         "hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n",
-                        isTouchedWindow ? "[TOUCHED] " : "", ftl::enum_string(info->type).c_str(),
-                        info->packageName.c_str(), info->ownerUid, info->id,
-                        toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft,
-                        info->frameTop, info->frameRight, info->frameBottom,
-                        dumpRegion(info->touchableRegion).c_str(), info->name.c_str(),
-                        info->flags.string().c_str(), info->inputFeatures.string().c_str(),
-                        toString(info->token != nullptr), info->applicationInfo.name.c_str(),
+                        isTouchedWindow ? "[TOUCHED] " : "", info->packageName.c_str(),
+                        info->ownerUid, info->id, toString(info->touchOcclusionMode).c_str(),
+                        info->alpha, info->frameLeft, info->frameTop, info->frameRight,
+                        info->frameBottom, dumpRegion(info->touchableRegion).c_str(),
+                        info->name.c_str(), info->inputConfig.string().c_str(),
+                        info->inputFeatures.string().c_str(), toString(info->token != nullptr),
+                        info->applicationInfo.name.c_str(),
                         toString(info->applicationInfo.token).c_str());
 }
 
@@ -4421,19 +4428,9 @@
     const auto& transformToDisplay = it->second.transform.inverse() * injectedTransform;
 
     for (uint32_t i = 0; i < entry.pointerCount; i++) {
-        PointerCoords& pc = entry.pointerCoords[i];
-        // Make a copy of the injected coords. We cannot change them in place because some of them
-        // are interdependent (for example, X coordinate might depend on the Y coordinate).
-        PointerCoords injectedCoords = entry.pointerCoords[i];
-
-        BitSet64 bits(injectedCoords.bits);
-        while (!bits.isEmpty()) {
-            const auto axis = static_cast<int32_t>(bits.clearFirstMarkedBit());
-            const float value =
-                    MotionEvent::calculateTransformedAxisValue(axis, entry.source,
-                                                               transformToDisplay, injectedCoords);
-            pc.setAxisValue(axis, value);
-        }
+        entry.pointerCoords[i] =
+                MotionEvent::calculateTransformedCoords(entry.source, transformToDisplay,
+                                                        entry.pointerCoords[i]);
     }
 }
 
@@ -4572,8 +4569,9 @@
         if (getInputChannelLocked(handle->getToken()) == nullptr) {
             const bool noInputChannel =
                     info->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL);
-            const bool canReceiveInput = !info->flags.test(WindowInfo::Flag::NOT_TOUCHABLE) ||
-                    !info->flags.test(WindowInfo::Flag::NOT_FOCUSABLE);
+            const bool canReceiveInput =
+                    !info->inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) ||
+                    !info->inputConfig.test(WindowInfo::InputConfig::NOT_FOCUSABLE);
             if (canReceiveInput && !noInputChannel) {
                 ALOGV("Window handle %s has no registered input channel",
                       handle->getName().c_str());
@@ -4644,12 +4642,16 @@
         }
 
         // Ensure all spy windows are trusted overlays
-        LOG_ALWAYS_FATAL_IF(info.isSpy() && !info.trustedOverlay,
+        LOG_ALWAYS_FATAL_IF(info.isSpy() &&
+                                    !info.inputConfig.test(
+                                            WindowInfo::InputConfig::TRUSTED_OVERLAY),
                             "%s has feature SPY, but is not a trusted overlay.",
                             window->getName().c_str());
 
         // Ensure all stylus interceptors are trusted overlays
-        LOG_ALWAYS_FATAL_IF(info.interceptsStylus() && !info.trustedOverlay,
+        LOG_ALWAYS_FATAL_IF(info.interceptsStylus() &&
+                                    !info.inputConfig.test(
+                                            WindowInfo::InputConfig::TRUSTED_OVERLAY),
                             "%s has feature INTERCEPTS_STYLUS, but is not a trusted overlay.",
                             window->getName().c_str());
     }
@@ -4699,7 +4701,8 @@
                     // Since we are about to drop the touch, cancel the events for the wallpaper as
                     // well.
                     if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND &&
-                        touchedWindow.windowHandle->getInfo()->hasWallpaper) {
+                        touchedWindow.windowHandle->getInfo()->inputConfig.test(
+                                gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
                         sp<WindowInfoHandle> wallpaper = state.getWallpaperWindow();
                         if (wallpaper != nullptr) {
                             sp<Connection> wallpaperConnection =
@@ -5194,34 +5197,27 @@
                     const WindowInfo* windowInfo = windowHandle->getInfo();
 
                     dump += StringPrintf(INDENT3 "%zu: name='%s', id=%" PRId32 ", displayId=%d, "
-                                                 "paused=%s, focusable=%s, "
-                                                 "hasWallpaper=%s, visible=%s, alpha=%.2f, "
-                                                 "flags=%s, type=%s, "
+                                                 "inputConfig=%s, alpha=%.2f, "
                                                  "frame=[%d,%d][%d,%d], globalScale=%f, "
                                                  "applicationInfo.name=%s, "
                                                  "applicationInfo.token=%s, "
                                                  "touchableRegion=",
                                          i, windowInfo->name.c_str(), windowInfo->id,
-                                         windowInfo->displayId, toString(windowInfo->paused),
-                                         toString(windowInfo->focusable),
-                                         toString(windowInfo->hasWallpaper),
-                                         toString(windowInfo->visible), windowInfo->alpha,
-                                         windowInfo->flags.string().c_str(),
-                                         ftl::enum_string(windowInfo->type).c_str(),
-                                         windowInfo->frameLeft, windowInfo->frameTop,
-                                         windowInfo->frameRight, windowInfo->frameBottom,
-                                         windowInfo->globalScaleFactor,
+                                         windowInfo->displayId,
+                                         windowInfo->inputConfig.string().c_str(),
+                                         windowInfo->alpha, windowInfo->frameLeft,
+                                         windowInfo->frameTop, windowInfo->frameRight,
+                                         windowInfo->frameBottom, windowInfo->globalScaleFactor,
                                          windowInfo->applicationInfo.name.c_str(),
                                          toString(windowInfo->applicationInfo.token).c_str());
                     dump += dumpRegion(windowInfo->touchableRegion);
                     dump += StringPrintf(", inputFeatures=%s",
                                          windowInfo->inputFeatures.string().c_str());
                     dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64
-                                         "ms, trustedOverlay=%s, hasToken=%s, "
+                                         "ms, hasToken=%s, "
                                          "touchOcclusionMode=%s\n",
                                          windowInfo->ownerPid, windowInfo->ownerUid,
                                          millis(windowInfo->dispatchingTimeout),
-                                         toString(windowInfo->trustedOverlay),
                                          toString(windowInfo->token != nullptr),
                                          toString(windowInfo->touchOcclusionMode).c_str());
                     windowInfo->transform.dump(dump, "transform", INDENT4);
@@ -5812,35 +5808,21 @@
     }
 }
 
-void InputDispatcher::sendMonitorUnresponsiveCommandLocked(int32_t pid, std::string reason) {
-    auto command = [this, pid, reason = std::move(reason)]() REQUIRES(mLock) {
-        scoped_unlock unlock(mLock);
-        mPolicy->notifyMonitorUnresponsive(pid, reason);
-    };
-    postCommandLocked(std::move(command));
-}
-
 void InputDispatcher::sendWindowUnresponsiveCommandLocked(const sp<IBinder>& token,
+                                                          std::optional<int32_t> pid,
                                                           std::string reason) {
-    auto command = [this, token, reason = std::move(reason)]() REQUIRES(mLock) {
+    auto command = [this, token, pid, reason = std::move(reason)]() REQUIRES(mLock) {
         scoped_unlock unlock(mLock);
-        mPolicy->notifyWindowUnresponsive(token, reason);
+        mPolicy->notifyWindowUnresponsive(token, pid, reason);
     };
     postCommandLocked(std::move(command));
 }
 
-void InputDispatcher::sendMonitorResponsiveCommandLocked(int32_t pid) {
-    auto command = [this, pid]() REQUIRES(mLock) {
+void InputDispatcher::sendWindowResponsiveCommandLocked(const sp<IBinder>& token,
+                                                        std::optional<int32_t> pid) {
+    auto command = [this, token, pid]() REQUIRES(mLock) {
         scoped_unlock unlock(mLock);
-        mPolicy->notifyMonitorResponsive(pid);
-    };
-    postCommandLocked(std::move(command));
-}
-
-void InputDispatcher::sendWindowResponsiveCommandLocked(const sp<IBinder>& connectionToken) {
-    auto command = [this, connectionToken]() REQUIRES(mLock) {
-        scoped_unlock unlock(mLock);
-        mPolicy->notifyWindowResponsive(connectionToken);
+        mPolicy->notifyWindowResponsive(token, pid);
     };
     postCommandLocked(std::move(command));
 }
@@ -5853,22 +5835,21 @@
 void InputDispatcher::processConnectionUnresponsiveLocked(const Connection& connection,
                                                           std::string reason) {
     const sp<IBinder>& connectionToken = connection.inputChannel->getConnectionToken();
+    std::optional<int32_t> pid;
     if (connection.monitor) {
         ALOGW("Monitor %s is unresponsive: %s", connection.inputChannel->getName().c_str(),
               reason.c_str());
-        std::optional<int32_t> pid = findMonitorPidByTokenLocked(connectionToken);
-        if (!pid.has_value()) {
-            ALOGE("Could not find unresponsive monitor for connection %s",
-                  connection.inputChannel->getName().c_str());
-            return;
+        pid = findMonitorPidByTokenLocked(connectionToken);
+    } else {
+        // The connection is a window
+        ALOGW("Window %s is unresponsive: %s", connection.inputChannel->getName().c_str(),
+              reason.c_str());
+        const sp<WindowInfoHandle> handle = getWindowHandleLocked(connectionToken);
+        if (handle != nullptr) {
+            pid = handle->getInfo()->ownerPid;
         }
-        sendMonitorUnresponsiveCommandLocked(pid.value(), std::move(reason));
-        return;
     }
-    // If not a monitor, must be a window
-    ALOGW("Window %s is unresponsive: %s", connection.inputChannel->getName().c_str(),
-          reason.c_str());
-    sendWindowUnresponsiveCommandLocked(connectionToken, std::move(reason));
+    sendWindowUnresponsiveCommandLocked(connectionToken, pid, std::move(reason));
 }
 
 /**
@@ -5876,18 +5857,17 @@
  */
 void InputDispatcher::processConnectionResponsiveLocked(const Connection& connection) {
     const sp<IBinder>& connectionToken = connection.inputChannel->getConnectionToken();
+    std::optional<int32_t> pid;
     if (connection.monitor) {
-        std::optional<int32_t> pid = findMonitorPidByTokenLocked(connectionToken);
-        if (!pid.has_value()) {
-            ALOGE("Could not find responsive monitor for connection %s",
-                  connection.inputChannel->getName().c_str());
-            return;
+        pid = findMonitorPidByTokenLocked(connectionToken);
+    } else {
+        // The connection is a window
+        const sp<WindowInfoHandle> handle = getWindowHandleLocked(connectionToken);
+        if (handle != nullptr) {
+            pid = handle->getInfo()->ownerPid;
         }
-        sendMonitorResponsiveCommandLocked(pid.value());
-        return;
     }
-    // If not a monitor, must be a window
-    sendWindowResponsiveCommandLocked(connectionToken);
+    sendWindowResponsiveCommandLocked(connectionToken, pid);
 }
 
 bool InputDispatcher::afterKeyEventLockedInterruptable(const sp<Connection>& connection,
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index e162c78..3c79c98 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -84,6 +84,8 @@
     static constexpr bool kDefaultInTouchMode = true;
 
     explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
+    explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy,
+                             std::chrono::nanoseconds staleEventTimeout);
     ~InputDispatcher() override;
 
     void dump(std::string& dump) override;
@@ -471,6 +473,11 @@
      */
     std::optional<nsecs_t> mNoFocusedWindowTimeoutTime GUARDED_BY(mLock);
 
+    // Amount of time to allow for an event to be dispatched (measured since its eventTime)
+    // before considering it stale and dropping it.
+    const std::chrono::nanoseconds mStaleEventTimeout;
+    bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry);
+
     bool shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) REQUIRES(mLock);
 
     /**
@@ -503,11 +510,11 @@
      */
     void processConnectionResponsiveLocked(const Connection& connection) REQUIRES(mLock);
 
-    void sendMonitorUnresponsiveCommandLocked(int32_t pid, std::string reason) REQUIRES(mLock);
-    void sendWindowUnresponsiveCommandLocked(const sp<IBinder>& connectionToken, std::string reason)
+    void sendWindowUnresponsiveCommandLocked(const sp<IBinder>& connectionToken,
+                                             std::optional<int32_t> pid, std::string reason)
             REQUIRES(mLock);
-    void sendMonitorResponsiveCommandLocked(int32_t pid) REQUIRES(mLock);
-    void sendWindowResponsiveCommandLocked(const sp<IBinder>& connectionToken) REQUIRES(mLock);
+    void sendWindowResponsiveCommandLocked(const sp<IBinder>& connectionToken,
+                                           std::optional<int32_t> pid) REQUIRES(mLock);
 
     // Optimization: AnrTracker is used to quickly find which connection is due for a timeout next.
     // AnrTracker must be kept in-sync with all responsive connection.waitQueues.
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index b63fe10..61e78cc 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -100,7 +100,8 @@
     for (const TouchedWindow& window : windows) {
         if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
             if (haveSlipperyForegroundWindow ||
-                !window.windowHandle->getInfo()->flags.test(WindowInfo::Flag::SLIPPERY)) {
+                !window.windowHandle->getInfo()->inputConfig.test(
+                        WindowInfo::InputConfig::SLIPPERY)) {
                 return false;
             }
             haveSlipperyForegroundWindow = true;
@@ -112,7 +113,8 @@
 sp<WindowInfoHandle> TouchState::getWallpaperWindow() const {
     for (size_t i = 0; i < windows.size(); i++) {
         const TouchedWindow& window = windows[i];
-        if (window.windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) {
+        if (window.windowHandle->getInfo()->inputConfig.test(
+                    gui::WindowInfo::InputConfig::IS_WALLPAPER)) {
             return window.windowHandle;
         }
     }
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 3c1e637..de0b6da 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -51,30 +51,19 @@
             const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) = 0;
 
     /* Notifies the system that a window just became unresponsive. This indicates that ANR
-     * should be raised for this window. The window is identified via token.
-     * The string reason contains information about the input event that we haven't received
-     * a response for.
+     * should be raised for this window. The window can be identified via its input token and the
+     * pid of the owner. The string reason contains information about the input event that we
+     * haven't received a response for.
      */
-    virtual void notifyWindowUnresponsive(const sp<IBinder>& token, const std::string& reason) = 0;
-    /* Notifies the system that a monitor just became unresponsive. This indicates that ANR
-     * should be raised for this monitor. The monitor is identified via its pid.
-     * The string reason contains information about the input event that we haven't received
-     * a response for.
-     */
-    virtual void notifyMonitorUnresponsive(int32_t pid, const std::string& reason) = 0;
+    virtual void notifyWindowUnresponsive(const sp<IBinder>& token, std::optional<int32_t> pid,
+                                          const std::string& reason) = 0;
 
     /* Notifies the system that a window just became responsive. This is only called after the
      * window was first marked "unresponsive". This indicates that ANR dialog (if any) should
      * no longer should be shown to the user. The window is eligible to cause a new ANR in the
      * future.
      */
-    virtual void notifyWindowResponsive(const sp<IBinder>& token) = 0;
-    /* Notifies the system that a monitor just became responsive. This is only called after the
-     * monitor was first marked "unresponsive". This indicates that ANR dialog (if any) should
-     * no longer should be shown to the user. The monitor is eligible to cause a new ANR in the
-     * future.
-     */
-    virtual void notifyMonitorResponsive(int32_t pid) = 0;
+    virtual void notifyWindowResponsive(const sp<IBinder>& token, std::optional<int32_t> pid) = 0;
 
     /* Notifies the system that an input channel is unrecoverably broken. */
     virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
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/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index a8e9bae..7d30d0c 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -335,12 +335,15 @@
     // button will likely wake the device.
     // TODO: Use the input device configuration to control this behavior more finely.
     uint32_t policyFlags = 0;
+    int32_t displayId = ADISPLAY_ID_NONE;
+    if (getDeviceContext().getAssociatedViewport()) {
+        displayId = getDeviceContext().getAssociatedViewport()->displayId;
+    }
 
     NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(),
-                          AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags,
-                          AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
-                          MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
-                          &pointerProperties, &pointerCoords, 0, 0,
+                          AINPUT_SOURCE_JOYSTICK, displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE,
+                          0, 0, metaState, buttonState, MotionClassification::NONE,
+                          AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0,
                           AMOTION_EVENT_INVALID_CURSOR_POSITION,
                           AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
     getListener().notifyMotion(&args);
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index ff3a592..8f5dc9b 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 ---
@@ -29,23 +31,15 @@
 
 MultiTouchMotionAccumulator::MultiTouchMotionAccumulator()
       : mCurrentSlot(-1),
-        mSlots(nullptr),
-        mSlotCount(0),
         mUsingSlotsProtocol(false),
         mHaveStylus(false) {}
 
-MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() {
-    delete[] mSlots;
-}
-
 void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount,
                                             bool usingSlotsProtocol) {
-    mSlotCount = slotCount;
     mUsingSlotsProtocol = usingSlotsProtocol;
     mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE);
 
-    delete[] mSlots;
-    mSlots = new Slot[slotCount];
+    mSlots = std::vector<Slot>(slotCount);
 }
 
 void MultiTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) {
@@ -74,10 +68,8 @@
 }
 
 void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) {
-    if (mSlots) {
-        for (size_t i = 0; i < mSlotCount; i++) {
-            mSlots[i].clear();
-        }
+    for (Slot& slot : mSlots) {
+        slot.clear();
     }
     mCurrentSlot = initialSlot;
 }
@@ -94,68 +86,68 @@
             mCurrentSlot = 0;
         }
 
-        if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
+        if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) {
             if (DEBUG_POINTERS) {
                 if (newSlot) {
                     ALOGW("MultiTouch device emitted invalid slot index %d but it "
                           "should be between 0 and %zd; ignoring this slot.",
-                          mCurrentSlot, mSlotCount - 1);
+                          mCurrentSlot, mSlots.size() - 1);
                 }
             }
         } else {
-            Slot* slot = &mSlots[mCurrentSlot];
+            Slot& slot = mSlots[mCurrentSlot];
             // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of
             // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while
             // updating the slot.
             if (!mUsingSlotsProtocol) {
-                slot->mInUse = true;
+                slot.mInUse = true;
             }
 
             switch (rawEvent->code) {
                 case ABS_MT_POSITION_X:
-                    slot->mAbsMTPositionX = rawEvent->value;
-                    warnIfNotInUse(*rawEvent, *slot);
+                    slot.mAbsMTPositionX = rawEvent->value;
+                    warnIfNotInUse(*rawEvent, slot);
                     break;
                 case ABS_MT_POSITION_Y:
-                    slot->mAbsMTPositionY = rawEvent->value;
-                    warnIfNotInUse(*rawEvent, *slot);
+                    slot.mAbsMTPositionY = rawEvent->value;
+                    warnIfNotInUse(*rawEvent, slot);
                     break;
                 case ABS_MT_TOUCH_MAJOR:
-                    slot->mAbsMTTouchMajor = rawEvent->value;
+                    slot.mAbsMTTouchMajor = rawEvent->value;
                     break;
                 case ABS_MT_TOUCH_MINOR:
-                    slot->mAbsMTTouchMinor = rawEvent->value;
-                    slot->mHaveAbsMTTouchMinor = true;
+                    slot.mAbsMTTouchMinor = rawEvent->value;
+                    slot.mHaveAbsMTTouchMinor = true;
                     break;
                 case ABS_MT_WIDTH_MAJOR:
-                    slot->mAbsMTWidthMajor = rawEvent->value;
+                    slot.mAbsMTWidthMajor = rawEvent->value;
                     break;
                 case ABS_MT_WIDTH_MINOR:
-                    slot->mAbsMTWidthMinor = rawEvent->value;
-                    slot->mHaveAbsMTWidthMinor = true;
+                    slot.mAbsMTWidthMinor = rawEvent->value;
+                    slot.mHaveAbsMTWidthMinor = true;
                     break;
                 case ABS_MT_ORIENTATION:
-                    slot->mAbsMTOrientation = rawEvent->value;
+                    slot.mAbsMTOrientation = rawEvent->value;
                     break;
                 case ABS_MT_TRACKING_ID:
                     if (mUsingSlotsProtocol && rawEvent->value < 0) {
                         // The slot is no longer in use but it retains its previous contents,
                         // which may be reused for subsequent touches.
-                        slot->mInUse = false;
+                        slot.mInUse = false;
                     } else {
-                        slot->mInUse = true;
-                        slot->mAbsMTTrackingId = rawEvent->value;
+                        slot.mInUse = true;
+                        slot.mAbsMTTrackingId = rawEvent->value;
                     }
                     break;
                 case ABS_MT_PRESSURE:
-                    slot->mAbsMTPressure = rawEvent->value;
+                    slot.mAbsMTPressure = rawEvent->value;
                     break;
                 case ABS_MT_DISTANCE:
-                    slot->mAbsMTDistance = rawEvent->value;
+                    slot.mAbsMTDistance = rawEvent->value;
                     break;
                 case ABS_MT_TOOL_TYPE:
-                    slot->mAbsMTToolType = rawEvent->value;
-                    slot->mHaveAbsMTToolType = true;
+                    slot.mAbsMTToolType = rawEvent->value;
+                    slot.mHaveAbsMTToolType = true;
                     break;
             }
         }
@@ -184,28 +176,6 @@
 
 // --- MultiTouchMotionAccumulator::Slot ---
 
-MultiTouchMotionAccumulator::Slot::Slot() {
-    clear();
-}
-
-void MultiTouchMotionAccumulator::Slot::clear() {
-    mInUse = false;
-    mHaveAbsMTTouchMinor = false;
-    mHaveAbsMTWidthMinor = false;
-    mHaveAbsMTToolType = false;
-    mAbsMTPositionX = 0;
-    mAbsMTPositionY = 0;
-    mAbsMTTouchMajor = 0;
-    mAbsMTTouchMinor = 0;
-    mAbsMTWidthMajor = 0;
-    mAbsMTWidthMinor = 0;
-    mAbsMTOrientation = 0;
-    mAbsMTTrackingId = -1;
-    mAbsMTPressure = 0;
-    mAbsMTDistance = 0;
-    mAbsMTToolType = 0;
-}
-
 int32_t MultiTouchMotionAccumulator::Slot::getToolType() const {
     if (mHaveAbsMTToolType) {
         switch (mAbsMTToolType) {
@@ -262,14 +232,14 @@
     mHavePointerIds = true;
 
     for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
-        const MultiTouchMotionAccumulator::Slot* inSlot =
+        const MultiTouchMotionAccumulator::Slot& inSlot =
                 mMultiTouchMotionAccumulator.getSlot(inIndex);
-        if (!inSlot->isInUse()) {
+        if (!inSlot.isInUse()) {
             continue;
         }
 
-        if (inSlot->getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) {
-            std::optional<int32_t> id = getActiveBitId(*inSlot);
+        if (inSlot.getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) {
+            std::optional<int32_t> id = getActiveBitId(inSlot);
             if (id) {
                 outState->rawPointerData.canceledIdBits.markBit(id.value());
             }
@@ -290,34 +260,38 @@
         }
 
         RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];
-        outPointer.x = inSlot->getX();
-        outPointer.y = inSlot->getY();
-        outPointer.pressure = inSlot->getPressure();
-        outPointer.touchMajor = inSlot->getTouchMajor();
-        outPointer.touchMinor = inSlot->getTouchMinor();
-        outPointer.toolMajor = inSlot->getToolMajor();
-        outPointer.toolMinor = inSlot->getToolMinor();
-        outPointer.orientation = inSlot->getOrientation();
-        outPointer.distance = inSlot->getDistance();
+        outPointer.x = inSlot.getX();
+        outPointer.y = inSlot.getY();
+        outPointer.pressure = inSlot.getPressure();
+        outPointer.touchMajor = inSlot.getTouchMajor();
+        outPointer.touchMinor = inSlot.getTouchMinor();
+        outPointer.toolMajor = inSlot.getToolMajor();
+        outPointer.toolMinor = inSlot.getToolMinor();
+        outPointer.orientation = inSlot.getOrientation();
+        outPointer.distance = inSlot.getDistance();
         outPointer.tiltX = 0;
         outPointer.tiltY = 0;
 
-        outPointer.toolType = inSlot->getToolType();
+        outPointer.toolType = inSlot.getToolType();
         if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
             outPointer.toolType = mTouchButtonAccumulator.getToolType();
             if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
                 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() ||
-                 (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0));
+                 (mRawPointerAxes.pressure.valid && inSlot.getPressure() <= 0));
         outPointer.isHovering = isHovering;
 
         // Assign pointer id using tracking id if available.
         if (mHavePointerIds) {
-            int32_t trackingId = inSlot->getTrackingId();
+            int32_t trackingId = inSlot.getTrackingId();
             int32_t id = -1;
             if (trackingId >= 0) {
                 for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) {
@@ -385,7 +359,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..fe8af5d 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -46,29 +46,27 @@
     private:
         friend class MultiTouchMotionAccumulator;
 
-        bool mInUse;
-        bool mHaveAbsMTTouchMinor;
-        bool mHaveAbsMTWidthMinor;
-        bool mHaveAbsMTToolType;
+        bool mInUse = false;
+        bool mHaveAbsMTTouchMinor = false;
+        bool mHaveAbsMTWidthMinor = false;
+        bool mHaveAbsMTToolType = false;
 
-        int32_t mAbsMTPositionX;
-        int32_t mAbsMTPositionY;
-        int32_t mAbsMTTouchMajor;
-        int32_t mAbsMTTouchMinor;
-        int32_t mAbsMTWidthMajor;
-        int32_t mAbsMTWidthMinor;
-        int32_t mAbsMTOrientation;
-        int32_t mAbsMTTrackingId;
-        int32_t mAbsMTPressure;
-        int32_t mAbsMTDistance;
-        int32_t mAbsMTToolType;
+        int32_t mAbsMTPositionX = 0;
+        int32_t mAbsMTPositionY = 0;
+        int32_t mAbsMTTouchMajor = 0;
+        int32_t mAbsMTTouchMinor = 0;
+        int32_t mAbsMTWidthMajor = 0;
+        int32_t mAbsMTWidthMinor = 0;
+        int32_t mAbsMTOrientation = 0;
+        int32_t mAbsMTTrackingId = -1;
+        int32_t mAbsMTPressure = 0;
+        int32_t mAbsMTDistance = 0;
+        int32_t mAbsMTToolType = 0;
 
-        Slot();
-        void clear();
+        void clear() { *this = Slot(); }
     };
 
     MultiTouchMotionAccumulator();
-    ~MultiTouchMotionAccumulator();
 
     void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol);
     void reset(InputDeviceContext& deviceContext);
@@ -76,13 +74,15 @@
     void finishSync();
     bool hasStylus() const;
 
-    inline size_t getSlotCount() const { return mSlotCount; }
-    inline const Slot* getSlot(size_t index) const { return &mSlots[index]; }
+    inline size_t getSlotCount() const { return mSlots.size(); }
+    inline const Slot& getSlot(size_t index) const {
+        LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index);
+        return mSlots[index];
+    }
 
 private:
     int32_t mCurrentSlot;
-    Slot* mSlots;
-    size_t mSlotCount;
+    std::vector<Slot> mSlots;
     bool mUsingSlotsProtocol;
     bool mHaveStylus;
 
@@ -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/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index f729ba9..c1934ff 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -550,18 +550,15 @@
 
 /**
  * Determine which DisplayViewport to use.
- * 1. If display port is specified, return the matching viewport. If matching viewport not
- * found, then return.
+ * 1. If a device has associated display, get the matching viewport.
  * 2. Always use the suggested viewport from WindowManagerService for pointers.
- * 3. If a device has associated display, get the matching viewport by either unique id or by
- * the display type (internal or external).
+ * 3. Get the matching viewport by either unique id in idc file or by the display type
+ * (internal or external).
  * 4. Otherwise, use a non-display viewport.
  */
 std::optional<DisplayViewport> TouchInputMapper::findViewport() {
     if (mParameters.hasAssociatedDisplay && mDeviceMode != DeviceMode::UNSCALED) {
-        const std::optional<uint8_t> displayPort = getDeviceContext().getAssociatedDisplayPort();
-        if (displayPort) {
-            // Find the viewport that contains the same port
+        if (getDeviceContext().getAssociatedViewport()) {
             return getDeviceContext().getAssociatedViewport();
         }
 
diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp
index 662be80..91be4a3 100644
--- a/services/inputflinger/tests/FocusResolver_test.cpp
+++ b/services/inputflinger/tests/FocusResolver_test.cpp
@@ -37,12 +37,16 @@
                      bool visible) {
         mInfo.token = token;
         mInfo.name = name;
-        mInfo.visible = visible;
-        mInfo.focusable = focusable;
+        setFocusable(focusable);
+        setVisible(visible);
     }
 
-    void setFocusable(bool focusable) { mInfo.focusable = focusable; }
-    void setVisible(bool visible) { mInfo.visible = visible; }
+    void setFocusable(bool focusable) {
+        mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable);
+    }
+    void setVisible(bool visible) {
+        mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible);
+    }
 };
 
 TEST(FocusResolverTest, SetFocusedWindow) {
@@ -80,6 +84,30 @@
     ASSERT_FALSE(changes);
 }
 
+TEST(FocusResolverTest, RemoveFocusFromFocusedWindow) {
+    sp<IBinder> focusableWindowToken = new BBinder();
+    std::vector<sp<WindowInfoHandle>> windows;
+    windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */,
+                                           true /* visible */));
+
+    FocusRequest request;
+    request.displayId = 42;
+    request.token = focusableWindowToken;
+    FocusResolver focusResolver;
+    // Focusable window gets focus.
+    request.token = focusableWindowToken;
+    std::optional<FocusResolver::FocusChanges> changes =
+            focusResolver.setFocusedWindow(request, windows);
+    ASSERT_FOCUS_CHANGE(changes, nullptr, focusableWindowToken);
+
+    // Window token of a request is null, focus should be revoked.
+    request.token = NULL;
+    changes = focusResolver.setFocusedWindow(request, windows);
+    ASSERT_EQ(focusableWindowToken, changes->oldFocus);
+    ASSERT_EQ(nullptr, changes->newFocus);
+    ASSERT_FOCUS_CHANGE(changes, focusableWindowToken, nullptr);
+}
+
 TEST(FocusResolverTest, SetFocusedMirroredWindow) {
     sp<IBinder> focusableWindowToken = new BBinder();
     sp<IBinder> invisibleWindowToken = new BBinder();
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 813acd8..3fb406c 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -60,6 +60,8 @@
 // An arbitrary pid of the gesture monitor window
 static constexpr int32_t MONITOR_PID = 2001;
 
+static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
+
 struct PointF {
     float x;
     float y;
@@ -88,6 +90,8 @@
 class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
     InputDispatcherConfiguration mConfig;
 
+    using AnrResult = std::pair<sp<IBinder>, int32_t /*pid*/>;
+
 protected:
     virtual ~FakeInputDispatcherPolicy() {}
 
@@ -161,122 +165,71 @@
     void assertNotifyNoFocusedWindowAnrWasCalled(
             std::chrono::nanoseconds timeout,
             const std::shared_ptr<InputApplicationHandle>& expectedApplication) {
+        std::unique_lock lock(mLock);
+        android::base::ScopedLockAssertion assumeLocked(mLock);
         std::shared_ptr<InputApplicationHandle> application;
-        { // acquire lock
-            std::unique_lock lock(mLock);
-            android::base::ScopedLockAssertion assumeLocked(mLock);
-            ASSERT_NO_FATAL_FAILURE(
-                    application = getAnrTokenLockedInterruptible(timeout, mAnrApplications, lock));
-        } // release lock
+        ASSERT_NO_FATAL_FAILURE(
+                application = getAnrTokenLockedInterruptible(timeout, mAnrApplications, lock));
         ASSERT_EQ(expectedApplication, application);
     }
 
     void assertNotifyWindowUnresponsiveWasCalled(std::chrono::nanoseconds timeout,
-                                                 const sp<IBinder>& expectedConnectionToken) {
-        sp<IBinder> connectionToken = getUnresponsiveWindowToken(timeout);
-        ASSERT_EQ(expectedConnectionToken, connectionToken);
+                                                 const sp<WindowInfoHandle>& window) {
+        LOG_ALWAYS_FATAL_IF(window == nullptr, "window should not be null");
+        assertNotifyWindowUnresponsiveWasCalled(timeout, window->getToken(),
+                                                window->getInfo()->ownerPid);
     }
 
-    void assertNotifyWindowResponsiveWasCalled(const sp<IBinder>& expectedConnectionToken) {
-        sp<IBinder> connectionToken = getResponsiveWindowToken();
-        ASSERT_EQ(expectedConnectionToken, connectionToken);
+    void assertNotifyWindowUnresponsiveWasCalled(std::chrono::nanoseconds timeout,
+                                                 const sp<IBinder>& expectedToken,
+                                                 int32_t expectedPid) {
+        std::unique_lock lock(mLock);
+        android::base::ScopedLockAssertion assumeLocked(mLock);
+        AnrResult result;
+        ASSERT_NO_FATAL_FAILURE(result =
+                                        getAnrTokenLockedInterruptible(timeout, mAnrWindows, lock));
+        const auto& [token, pid] = result;
+        ASSERT_EQ(expectedToken, token);
+        ASSERT_EQ(expectedPid, pid);
     }
 
-    void assertNotifyMonitorUnresponsiveWasCalled(std::chrono::nanoseconds timeout) {
-        int32_t pid = getUnresponsiveMonitorPid(timeout);
-        ASSERT_EQ(MONITOR_PID, pid);
-    }
-
-    void assertNotifyMonitorResponsiveWasCalled() {
-        int32_t pid = getResponsiveMonitorPid();
-        ASSERT_EQ(MONITOR_PID, pid);
-    }
-
+    /** Wrap call with ASSERT_NO_FATAL_FAILURE() to ensure the return value is valid. */
     sp<IBinder> getUnresponsiveWindowToken(std::chrono::nanoseconds timeout) {
         std::unique_lock lock(mLock);
         android::base::ScopedLockAssertion assumeLocked(mLock);
-        return getAnrTokenLockedInterruptible(timeout, mAnrWindowTokens, lock);
+        AnrResult result = getAnrTokenLockedInterruptible(timeout, mAnrWindows, lock);
+        const auto& [token, _] = result;
+        return token;
     }
 
+    void assertNotifyWindowResponsiveWasCalled(const sp<IBinder>& expectedToken,
+                                               int32_t expectedPid) {
+        std::unique_lock lock(mLock);
+        android::base::ScopedLockAssertion assumeLocked(mLock);
+        AnrResult result;
+        ASSERT_NO_FATAL_FAILURE(
+                result = getAnrTokenLockedInterruptible(0s, mResponsiveWindows, lock));
+        const auto& [token, pid] = result;
+        ASSERT_EQ(expectedToken, token);
+        ASSERT_EQ(expectedPid, pid);
+    }
+
+    /** Wrap call with ASSERT_NO_FATAL_FAILURE() to ensure the return value is valid. */
     sp<IBinder> getResponsiveWindowToken() {
         std::unique_lock lock(mLock);
         android::base::ScopedLockAssertion assumeLocked(mLock);
-        return getAnrTokenLockedInterruptible(0s, mResponsiveWindowTokens, lock);
-    }
-
-    int32_t getUnresponsiveMonitorPid(std::chrono::nanoseconds timeout) {
-        std::unique_lock lock(mLock);
-        android::base::ScopedLockAssertion assumeLocked(mLock);
-        return getAnrTokenLockedInterruptible(timeout, mAnrMonitorPids, lock);
-    }
-
-    int32_t getResponsiveMonitorPid() {
-        std::unique_lock lock(mLock);
-        android::base::ScopedLockAssertion assumeLocked(mLock);
-        return getAnrTokenLockedInterruptible(0s, mResponsiveMonitorPids, lock);
-    }
-
-    // All three ANR-related callbacks behave the same way, so we use this generic function to wait
-    // for a specific container to become non-empty. When the container is non-empty, return the
-    // first entry from the container and erase it.
-    template <class T>
-    T getAnrTokenLockedInterruptible(std::chrono::nanoseconds timeout, std::queue<T>& storage,
-                                     std::unique_lock<std::mutex>& lock) REQUIRES(mLock) {
-        // If there is an ANR, Dispatcher won't be idle because there are still events
-        // in the waitQueue that we need to check on. So we can't wait for dispatcher to be idle
-        // before checking if ANR was called.
-        // Since dispatcher is not guaranteed to call notifyNoFocusedWindowAnr right away, we need
-        // to provide it some time to act. 100ms seems reasonable.
-        std::chrono::duration timeToWait = timeout + 100ms; // provide some slack
-        const std::chrono::time_point start = std::chrono::steady_clock::now();
-        std::optional<T> token =
-                getItemFromStorageLockedInterruptible(timeToWait, storage, lock, mNotifyAnr);
-        if (!token.has_value()) {
-            ADD_FAILURE() << "Did not receive the ANR callback";
-            return {};
-        }
-
-        const std::chrono::duration waited = std::chrono::steady_clock::now() - start;
-        // Ensure that the ANR didn't get raised too early. We can't be too strict here because
-        // the dispatcher started counting before this function was called
-        if (std::chrono::abs(timeout - waited) > 100ms) {
-            ADD_FAILURE() << "ANR was raised too early or too late. Expected "
-                          << std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()
-                          << "ms, but waited "
-                          << std::chrono::duration_cast<std::chrono::milliseconds>(waited).count()
-                          << "ms instead";
-        }
-        return *token;
-    }
-
-    template <class T>
-    std::optional<T> getItemFromStorageLockedInterruptible(std::chrono::nanoseconds timeout,
-                                                           std::queue<T>& storage,
-                                                           std::unique_lock<std::mutex>& lock,
-                                                           std::condition_variable& condition)
-            REQUIRES(mLock) {
-        condition.wait_for(lock, timeout,
-                           [&storage]() REQUIRES(mLock) { return !storage.empty(); });
-        if (storage.empty()) {
-            ADD_FAILURE() << "Did not receive the expected callback";
-            return std::nullopt;
-        }
-        T item = storage.front();
-        storage.pop();
-        return std::make_optional(item);
+        AnrResult result = getAnrTokenLockedInterruptible(0s, mResponsiveWindows, lock);
+        const auto& [token, _] = result;
+        return token;
     }
 
     void assertNotifyAnrWasNotCalled() {
         std::scoped_lock lock(mLock);
         ASSERT_TRUE(mAnrApplications.empty());
-        ASSERT_TRUE(mAnrWindowTokens.empty());
-        ASSERT_TRUE(mAnrMonitorPids.empty());
-        ASSERT_TRUE(mResponsiveWindowTokens.empty())
+        ASSERT_TRUE(mAnrWindows.empty());
+        ASSERT_TRUE(mResponsiveWindows.empty())
                 << "ANR was not called, but please also consume the 'connection is responsive' "
                    "signal";
-        ASSERT_TRUE(mResponsiveMonitorPids.empty())
-                << "Monitor ANR was not called, but please also consume the 'monitor is responsive'"
-                   " signal";
     }
 
     void setKeyRepeatConfiguration(nsecs_t timeout, nsecs_t delay) {
@@ -344,10 +297,8 @@
 
     // ANR handling
     std::queue<std::shared_ptr<InputApplicationHandle>> mAnrApplications GUARDED_BY(mLock);
-    std::queue<sp<IBinder>> mAnrWindowTokens GUARDED_BY(mLock);
-    std::queue<sp<IBinder>> mResponsiveWindowTokens GUARDED_BY(mLock);
-    std::queue<int32_t> mAnrMonitorPids GUARDED_BY(mLock);
-    std::queue<int32_t> mResponsiveMonitorPids GUARDED_BY(mLock);
+    std::queue<AnrResult> mAnrWindows GUARDED_BY(mLock);
+    std::queue<AnrResult> mResponsiveWindows GUARDED_BY(mLock);
     std::condition_variable mNotifyAnr;
     std::queue<sp<IBinder>> mBrokenInputChannels GUARDED_BY(mLock);
     std::condition_variable mNotifyInputChannelBroken;
@@ -355,32 +306,74 @@
     sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock);
     bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false;
 
+    // All three ANR-related callbacks behave the same way, so we use this generic function to wait
+    // for a specific container to become non-empty. When the container is non-empty, return the
+    // first entry from the container and erase it.
+    template <class T>
+    T getAnrTokenLockedInterruptible(std::chrono::nanoseconds timeout, std::queue<T>& storage,
+                                     std::unique_lock<std::mutex>& lock) REQUIRES(mLock) {
+        // If there is an ANR, Dispatcher won't be idle because there are still events
+        // in the waitQueue that we need to check on. So we can't wait for dispatcher to be idle
+        // before checking if ANR was called.
+        // Since dispatcher is not guaranteed to call notifyNoFocusedWindowAnr right away, we need
+        // to provide it some time to act. 100ms seems reasonable.
+        std::chrono::duration timeToWait = timeout + 100ms; // provide some slack
+        const std::chrono::time_point start = std::chrono::steady_clock::now();
+        std::optional<T> token =
+                getItemFromStorageLockedInterruptible(timeToWait, storage, lock, mNotifyAnr);
+        if (!token.has_value()) {
+            ADD_FAILURE() << "Did not receive the ANR callback";
+            return {};
+        }
+
+        const std::chrono::duration waited = std::chrono::steady_clock::now() - start;
+        // Ensure that the ANR didn't get raised too early. We can't be too strict here because
+        // the dispatcher started counting before this function was called
+        if (std::chrono::abs(timeout - waited) > 100ms) {
+            ADD_FAILURE() << "ANR was raised too early or too late. Expected "
+                          << std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()
+                          << "ms, but waited "
+                          << std::chrono::duration_cast<std::chrono::milliseconds>(waited).count()
+                          << "ms instead";
+        }
+        return *token;
+    }
+
+    template <class T>
+    std::optional<T> getItemFromStorageLockedInterruptible(std::chrono::nanoseconds timeout,
+                                                           std::queue<T>& storage,
+                                                           std::unique_lock<std::mutex>& lock,
+                                                           std::condition_variable& condition)
+            REQUIRES(mLock) {
+        condition.wait_for(lock, timeout,
+                           [&storage]() REQUIRES(mLock) { return !storage.empty(); });
+        if (storage.empty()) {
+            ADD_FAILURE() << "Did not receive the expected callback";
+            return std::nullopt;
+        }
+        T item = storage.front();
+        storage.pop();
+        return std::make_optional(item);
+    }
+
     void notifyConfigurationChanged(nsecs_t when) override {
         std::scoped_lock lock(mLock);
         mConfigurationChangedTime = when;
     }
 
-    void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, const std::string&) override {
+    void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, std::optional<int32_t> pid,
+                                  const std::string&) override {
         std::scoped_lock lock(mLock);
-        mAnrWindowTokens.push(connectionToken);
+        ASSERT_TRUE(pid.has_value());
+        mAnrWindows.push({connectionToken, *pid});
         mNotifyAnr.notify_all();
     }
 
-    void notifyMonitorUnresponsive(int32_t pid, const std::string&) override {
+    void notifyWindowResponsive(const sp<IBinder>& connectionToken,
+                                std::optional<int32_t> pid) override {
         std::scoped_lock lock(mLock);
-        mAnrMonitorPids.push(pid);
-        mNotifyAnr.notify_all();
-    }
-
-    void notifyWindowResponsive(const sp<IBinder>& connectionToken) override {
-        std::scoped_lock lock(mLock);
-        mResponsiveWindowTokens.push(connectionToken);
-        mNotifyAnr.notify_all();
-    }
-
-    void notifyMonitorResponsive(int32_t pid) override {
-        std::scoped_lock lock(mLock);
-        mResponsiveMonitorPids.push(pid);
+        ASSERT_TRUE(pid.has_value());
+        mResponsiveWindows.push({connectionToken, *pid});
         mNotifyAnr.notify_all();
     }
 
@@ -493,7 +486,7 @@
 
     void SetUp() override {
         mFakePolicy = new FakeInputDispatcherPolicy();
-        mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy);
+        mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy, STALE_EVENT_TIMEOUT);
         mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
         // Start InputDispatcher thread
         ASSERT_EQ(OK, mDispatcher->start());
@@ -987,7 +980,6 @@
         mInfo.token = *token;
         mInfo.id = sId++;
         mInfo.name = name;
-        mInfo.type = WindowInfo::Type::APPLICATION;
         mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
         mInfo.alpha = 1.0;
         mInfo.frameLeft = 0;
@@ -998,14 +990,10 @@
         mInfo.globalScaleFactor = 1.0;
         mInfo.touchableRegion.clear();
         mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
-        mInfo.visible = true;
-        mInfo.focusable = false;
-        mInfo.hasWallpaper = false;
-        mInfo.paused = false;
         mInfo.ownerPid = INJECTOR_PID;
         mInfo.ownerUid = INJECTOR_UID;
         mInfo.displayId = displayId;
-        mInfo.trustedOverlay = false;
+        mInfo.inputConfig = WindowInfo::InputConfig::NONE;
     }
 
     sp<FakeWindowHandle> clone(
@@ -1017,15 +1005,37 @@
         return handle;
     }
 
-    void setFocusable(bool focusable) { mInfo.focusable = focusable; }
+    void setTouchable(bool touchable) {
+        mInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, !touchable);
+    }
 
-    void setVisible(bool visible) { mInfo.visible = visible; }
+    void setFocusable(bool focusable) {
+        mInfo.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable);
+    }
+
+    void setVisible(bool visible) {
+        mInfo.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible);
+    }
 
     void setDispatchingTimeout(std::chrono::nanoseconds timeout) {
         mInfo.dispatchingTimeout = timeout;
     }
 
-    void setPaused(bool paused) { mInfo.paused = paused; }
+    void setPaused(bool paused) {
+        mInfo.setInputConfig(WindowInfo::InputConfig::PAUSE_DISPATCHING, paused);
+    }
+
+    void setPreventSplitting(bool preventSplitting) {
+        mInfo.setInputConfig(WindowInfo::InputConfig::PREVENT_SPLITTING, preventSplitting);
+    }
+
+    void setSlippery(bool slippery) {
+        mInfo.setInputConfig(WindowInfo::InputConfig::SLIPPERY, slippery);
+    }
+
+    void setWatchOutsideTouch(bool watchOutside) {
+        mInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, watchOutside);
+    }
 
     void setAlpha(float alpha) { mInfo.alpha = alpha; }
 
@@ -1049,17 +1059,19 @@
 
     void setTouchableRegion(const Region& region) { mInfo.touchableRegion = region; }
 
-    void setType(WindowInfo::Type type) { mInfo.type = type; }
+    void setIsWallpaper(bool isWallpaper) {
+        mInfo.setInputConfig(WindowInfo::InputConfig::IS_WALLPAPER, isWallpaper);
+    }
 
-    void setHasWallpaper(bool hasWallpaper) { mInfo.hasWallpaper = hasWallpaper; }
-
-    void addFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags |= flags; }
-
-    void setFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags = flags; }
+    void setDupTouchToWallpaper(bool hasWallpaper) {
+        mInfo.setInputConfig(WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER, hasWallpaper);
+    }
 
     void setInputFeatures(Flags<WindowInfo::Feature> features) { mInfo.inputFeatures = features; }
 
-    void setTrustedOverlay(bool trustedOverlay) { mInfo.trustedOverlay = trustedOverlay; }
+    void setTrustedOverlay(bool trustedOverlay) {
+        mInfo.setInputConfig(WindowInfo::InputConfig::TRUSTED_OVERLAY, trustedOverlay);
+    }
 
     void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) {
         mInfo.transform.set(dsdx, dtdx, dtdy, dsdy);
@@ -1226,6 +1238,8 @@
         mInfo.ownerUid = ownerUid;
     }
 
+    int32_t getPid() const { return mInfo.ownerPid; }
+
     void destroyReceiver() { mInputReceiver = nullptr; }
 
     int getChannelFd() { return mInputReceiver->getChannelFd(); }
@@ -1540,19 +1554,15 @@
 }
 
 /**
- * Calling setInputWindows once with FLAG_NOT_TOUCH_MODAL should not cause any issues.
- * To ensure that window receives only events that were directly inside of it, add
- * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input
- * when finding touched windows.
+ * Calling setInputWindows once should not cause any issues.
  * This test serves as a sanity check for the next test, where setInputWindows is
  * called twice.
  */
-TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) {
+TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
             new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
     window->setFrame(Rect(0, 0, 100, 100));
-    window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1566,16 +1576,12 @@
 
 /**
  * Calling setInputWindows twice, with the same info, should not cause any issues.
- * To ensure that window receives only events that were directly inside of it, add
- * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input
- * when finding touched windows.
  */
 TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
             new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
     window->setFrame(Rect(0, 0, 100, 100));
-    window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -1610,17 +1616,17 @@
  * Two windows: A top window, and a wallpaper behind the window.
  * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window
  * gets ACTION_CANCEL.
- * 1. foregroundWindow <-- has wallpaper (hasWallpaper=true)
- * 2. wallpaperWindow <-- is wallpaper (type=InputWindowInfo::Type::WALLPAPER)
+ * 1. foregroundWindow <-- dup touch to wallpaper
+ * 2. wallpaperWindow <-- is wallpaper
  */
 TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> foregroundWindow =
             new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
-    foregroundWindow->setHasWallpaper(true);
+    foregroundWindow->setDupTouchToWallpaper(true);
     sp<FakeWindowHandle> wallpaperWindow =
             new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
-    wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+    wallpaperWindow->setIsWallpaper(true);
     constexpr int expectedWallpaperFlags =
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
 
@@ -1661,10 +1667,10 @@
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> foregroundWindow =
             new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
-    foregroundWindow->setHasWallpaper(true);
+    foregroundWindow->setDupTouchToWallpaper(true);
     sp<FakeWindowHandle> wallpaperWindow =
             new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
-    wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+    wallpaperWindow->setIsWallpaper(true);
     constexpr int expectedWallpaperFlags =
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
 
@@ -1705,11 +1711,11 @@
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
             new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
-    window->setHasWallpaper(true);
+    window->setDupTouchToWallpaper(true);
 
     sp<FakeWindowHandle> wallpaperWindow =
             new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
-    wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+    wallpaperWindow->setIsWallpaper(true);
     constexpr int expectedWallpaperFlags =
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
 
@@ -1763,19 +1769,17 @@
     sp<FakeWindowHandle> leftWindow =
             new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
     leftWindow->setFrame(Rect(0, 0, 200, 200));
-    leftWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL);
-    leftWindow->setHasWallpaper(true);
+    leftWindow->setDupTouchToWallpaper(true);
 
     sp<FakeWindowHandle> rightWindow =
             new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
     rightWindow->setFrame(Rect(200, 0, 400, 200));
-    rightWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL);
-    rightWindow->setHasWallpaper(true);
+    rightWindow->setDupTouchToWallpaper(true);
 
     sp<FakeWindowHandle> wallpaperWindow =
             new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
     wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
-    wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+    wallpaperWindow->setIsWallpaper(true);
     constexpr int expectedWallpaperFlags =
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
 
@@ -1849,11 +1853,9 @@
     sp<FakeWindowHandle> windowLeft =
             new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
     windowLeft->setFrame(Rect(0, 0, 600, 800));
-    windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
     sp<FakeWindowHandle> windowRight =
             new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
     windowRight->setFrame(Rect(600, 0, 1200, 800));
-    windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
@@ -1960,7 +1962,6 @@
     sp<FakeWindowHandle> window =
             new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
     window->setFrame(Rect(0, 0, 1200, 800));
-    window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
@@ -2042,11 +2043,9 @@
     sp<FakeWindowHandle> windowLeft =
             new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
     windowLeft->setFrame(Rect(0, 0, 600, 800));
-    windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
     sp<FakeWindowHandle> windowRight =
             new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
     windowRight->setFrame(Rect(600, 0, 1200, 800));
-    windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
@@ -2152,14 +2151,12 @@
         // Add two windows to the display. Their frames are represented in the display space.
         sp<FakeWindowHandle> firstWindow =
                 new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
-        firstWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
         firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
         addWindow(firstWindow);
 
         sp<FakeWindowHandle> secondWindow =
                 new FakeWindowHandle(application, mDispatcher, "Second Window",
                                      ADISPLAY_ID_DEFAULT);
-        secondWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
         secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
         addWindow(secondWindow);
         return {std::move(firstWindow), std::move(secondWindow)};
@@ -2302,8 +2299,10 @@
     // Create a couple of windows
     sp<FakeWindowHandle> firstWindow =
             new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+    firstWindow->setPreventSplitting(true);
     sp<FakeWindowHandle> secondWindow =
             new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+    secondWindow->setPreventSplitting(true);
 
     // Add the windows to the dispatcher
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2376,17 +2375,13 @@
 TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
-    // Create a non touch modal window that supports split touch
     sp<FakeWindowHandle> firstWindow =
             new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
     firstWindow->setFrame(Rect(0, 0, 600, 400));
-    firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
 
-    // Create a non touch modal window that supports split touch
     sp<FakeWindowHandle> secondWindow =
             new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
     secondWindow->setFrame(Rect(0, 400, 600, 800));
-    secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
 
     // Add the windows to the dispatcher
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2448,17 +2443,13 @@
 TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
-    // Create a non touch modal window that supports split touch
     sp<FakeWindowHandle> firstWindow =
             new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
     firstWindow->setFrame(Rect(0, 0, 600, 400));
-    firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
 
-    // Create a non touch modal window that supports split touch
     sp<FakeWindowHandle> secondWindow =
             new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
     secondWindow->setFrame(Rect(0, 400, 600, 800));
-    secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
 
     // Add the windows to the dispatcher
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2523,26 +2514,21 @@
     sp<FakeWindowHandle> firstWindowInPrimary =
             new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
     firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
-    firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
     sp<FakeWindowHandle> secondWindowInPrimary =
             new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
     secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
-    secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
     sp<FakeWindowHandle> mirrorWindowInPrimary =
             firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT);
     mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
-    mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
     sp<FakeWindowHandle> firstWindowInSecondary =
             firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
     firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
-    firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
     sp<FakeWindowHandle> secondWindowInSecondary =
             secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
     secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
-    secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
     // Update window info, let it find window handle of second display first.
     mDispatcher->setInputWindows(
@@ -2587,26 +2573,21 @@
     sp<FakeWindowHandle> firstWindowInPrimary =
             new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
     firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
-    firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
     sp<FakeWindowHandle> secondWindowInPrimary =
             new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
     secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
-    secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
     sp<FakeWindowHandle> mirrorWindowInPrimary =
             firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT);
     mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200));
-    mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
     sp<FakeWindowHandle> firstWindowInSecondary =
             firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
     firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100));
-    firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
     sp<FakeWindowHandle> secondWindowInSecondary =
             secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID);
     secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
-    secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
     // Update window info, let it find window handle of second display first.
     mDispatcher->setInputWindows(
@@ -2700,17 +2681,13 @@
 TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
-    // Create first non touch modal window that supports split touch
     sp<FakeWindowHandle> firstWindow =
             new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
     firstWindow->setFrame(Rect(0, 0, 600, 400));
-    firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
 
-    // Create second non touch modal window that supports split touch
     sp<FakeWindowHandle> secondWindow =
             new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
     secondWindow->setFrame(Rect(0, 400, 600, 800));
-    secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
 
     // Add the windows to the dispatcher
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -3230,9 +3207,9 @@
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
             new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+    window->setFocusable(false);
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
-    // Window is not focusable.
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     setFocusedWindow(window);
 
@@ -3240,7 +3217,7 @@
     ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher))
             << "Inject key event should return InputEventInjectionResult::TIMED_OUT";
 
-    // window is invalid, so it should not receive any input event.
+    // window is not focusable, so it should not receive any input event.
     window->assertNoEvents();
 }
 
@@ -3377,7 +3354,7 @@
 
     sp<FakeWindowHandle> slipperyExitWindow =
             new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
-    slipperyExitWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SLIPPERY);
+    slipperyExitWindow->setSlippery(true);
     // Make sure this one overlaps the bottom window
     slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
     // Change the owner uid/pid of the window so that it is considered to be occluding the bottom
@@ -3983,14 +3960,10 @@
         mUnfocusedWindow =
                 new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
         mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
-        // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
-        // window.
-        mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
         mFocusedWindow =
                 new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
         mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
-        mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
         // Set focused application.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -4097,14 +4070,10 @@
                 std::make_shared<FakeApplicationHandle>();
         mWindow1 = new FakeWindowHandle(application, mDispatcher, "Fake Window 1",
                                         ADISPLAY_ID_DEFAULT);
-        // Adding FLAG_NOT_TOUCH_MODAL otherwise all taps will go to the top most window.
-        // We also need FLAG_SPLIT_TOUCH or we won't be able to get touches for both windows.
-        mWindow1->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
         mWindow1->setFrame(Rect(0, 0, 100, 100));
 
         mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2",
                                         ADISPLAY_ID_DEFAULT, mWindow1->getToken());
-        mWindow2->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
         mWindow2->setFrame(Rect(100, 100, 200, 200));
 
         mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}});
@@ -4301,9 +4270,6 @@
         mWindow->setFrame(Rect(0, 0, 30, 30));
         mWindow->setDispatchingTimeout(30ms);
         mWindow->setFocusable(true);
-        // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
-        // window.
-        mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
         // Set focused application.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
@@ -4393,13 +4359,13 @@
     std::optional<uint32_t> sequenceNum = mWindow->receiveEvent(); // ACTION_DOWN
     ASSERT_TRUE(sequenceNum);
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
 
     mWindow->finishEvent(*sequenceNum);
     mWindow->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL,
                           ADISPLAY_ID_DEFAULT, 0 /*flags*/);
     ASSERT_TRUE(mDispatcher->waitForIdle());
-    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
 }
 
 // Send a key to the app and have the app not respond right away.
@@ -4409,7 +4375,7 @@
     std::optional<uint32_t> sequenceNum = mWindow->receiveEvent();
     ASSERT_TRUE(sequenceNum);
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
     ASSERT_TRUE(mDispatcher->waitForIdle());
 }
 
@@ -4439,6 +4405,38 @@
     ASSERT_TRUE(mDispatcher->waitForIdle());
 }
 
+/**
+ * Make sure the stale key is dropped before causing an ANR. So even if there's no focused window,
+ * there will not be an ANR.
+ */
+TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) {
+    mWindow->setFocusable(false);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
+    mWindow->consumeFocusEvent(false);
+
+    KeyEvent event;
+    const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
+            std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
+
+    // Define a valid key down event that is stale (too old).
+    event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
+                     INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /* flags */ 0, AKEYCODE_A, KEY_A,
+                     AMETA_NONE, 1 /*repeatCount*/, eventTime, eventTime);
+
+    const int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
+
+    InputEventInjectionResult result =
+            mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+                                          InputEventInjectionSync::WAIT_FOR_RESULT,
+                                          INJECT_EVENT_TIMEOUT, policyFlags);
+    ASSERT_EQ(InputEventInjectionResult::FAILED, result)
+            << "Injection should fail because the event is stale";
+
+    ASSERT_TRUE(mDispatcher->waitForIdle());
+    mFakePolicy->assertNotifyAnrWasNotCalled();
+    mWindow->assertNoEvents();
+}
+
 // We have a focused application, but no focused window
 // Make sure that we don't notify policy twice about the same ANR.
 TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) {
@@ -4514,7 +4512,7 @@
     // We have now sent down and up. Let's consume first event and then ANR on the second.
     mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
 }
 
 // A spy window can receive an ANR
@@ -4529,13 +4527,13 @@
     std::optional<uint32_t> sequenceNum = spy->receiveEvent(); // ACTION_DOWN
     ASSERT_TRUE(sequenceNum);
     const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
 
     spy->finishEvent(*sequenceNum);
     spy->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, ADISPLAY_ID_DEFAULT,
                       0 /*flags*/);
     ASSERT_TRUE(mDispatcher->waitForIdle());
-    mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken(), mWindow->getPid());
 }
 
 // If an app is not responding to a key event, spy windows should continue to receive
@@ -4550,7 +4548,7 @@
 
     // Stuck on the ACTION_UP
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
 
     // New tap will go to the spy window, but not to the window
     tapOnWindow();
@@ -4559,7 +4557,7 @@
 
     mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion
     mDispatcher->waitForIdle();
-    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
     mWindow->assertNoEvents();
     spy->assertNoEvents();
 }
@@ -4576,7 +4574,7 @@
     mWindow->consumeMotionDown();
     // Stuck on the ACTION_UP
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
 
     // New tap will go to the spy window, but not to the window
     tapOnWindow();
@@ -4585,7 +4583,7 @@
 
     mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion
     mDispatcher->waitForIdle();
-    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
     mWindow->assertNoEvents();
     spy->assertNoEvents();
 }
@@ -4603,13 +4601,13 @@
     const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
     ASSERT_TRUE(consumeSeq);
 
-    mFakePolicy->assertNotifyMonitorUnresponsiveWasCalled(30ms);
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(30ms, monitor.getToken(), MONITOR_PID);
 
     monitor.finishEvent(*consumeSeq);
     monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
 
     ASSERT_TRUE(mDispatcher->waitForIdle());
-    mFakePolicy->assertNotifyMonitorResponsiveWasCalled();
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(monitor.getToken(), MONITOR_PID);
 }
 
 // If a window is unresponsive, then you get anr. if the window later catches up and starts to
@@ -4624,19 +4622,19 @@
     mWindow->consumeMotionDown();
     // Block on ACTION_UP
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
     mWindow->consumeMotionUp(); // Now the connection should be healthy again
     mDispatcher->waitForIdle();
-    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
     mWindow->assertNoEvents();
 
     tapOnWindow();
     mWindow->consumeMotionDown();
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
     mWindow->consumeMotionUp();
 
     mDispatcher->waitForIdle();
-    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
     mFakePolicy->assertNotifyAnrWasNotCalled();
     mWindow->assertNoEvents();
 }
@@ -4649,7 +4647,7 @@
                                WINDOW_LOCATION));
 
     const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(windowTimeout, mWindow);
     std::this_thread::sleep_for(windowTimeout);
     // 'notifyConnectionUnresponsive' should only be called once per connection
     mFakePolicy->assertNotifyAnrWasNotCalled();
@@ -4659,7 +4657,7 @@
                           ADISPLAY_ID_DEFAULT, 0 /*flags*/);
     mWindow->assertNoEvents();
     mDispatcher->waitForIdle();
-    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken(), mWindow->getPid());
     mFakePolicy->assertNotifyAnrWasNotCalled();
 }
 
@@ -4751,18 +4749,13 @@
         mUnfocusedWindow =
                 new FakeWindowHandle(mApplication, mDispatcher, "Unfocused", ADISPLAY_ID_DEFAULT);
         mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
-        // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
-        // window.
         // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
-        mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL |
-                                   WindowInfo::Flag::WATCH_OUTSIDE_TOUCH |
-                                   WindowInfo::Flag::SPLIT_TOUCH);
+        mUnfocusedWindow->setWatchOutsideTouch(true);
 
         mFocusedWindow =
                 new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT);
         mFocusedWindow->setDispatchingTimeout(30ms);
         mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
-        mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
 
         // Set focused application.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
@@ -4826,7 +4819,7 @@
 
     const std::chrono::duration timeout =
             mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
     // Because we injected two DOWN events in a row, CANCEL is enqueued for the first event
     // sequence to make it consistent
     mFocusedWindow->consumeMotionCancel();
@@ -4837,7 +4830,8 @@
     mFocusedWindow->assertNoEvents();
     mUnfocusedWindow->assertNoEvents();
     ASSERT_TRUE(mDispatcher->waitForIdle());
-    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
+                                                       mFocusedWindow->getPid());
     mFakePolicy->assertNotifyAnrWasNotCalled();
 }
 
@@ -4851,8 +4845,9 @@
 
     tapOnFocusedWindow();
     // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window
-    sp<IBinder> anrConnectionToken1 = mFakePolicy->getUnresponsiveWindowToken(10ms);
-    sp<IBinder> anrConnectionToken2 = mFakePolicy->getUnresponsiveWindowToken(0ms);
+    sp<IBinder> anrConnectionToken1, anrConnectionToken2;
+    ASSERT_NO_FATAL_FAILURE(anrConnectionToken1 = mFakePolicy->getUnresponsiveWindowToken(10ms));
+    ASSERT_NO_FATAL_FAILURE(anrConnectionToken2 = mFakePolicy->getUnresponsiveWindowToken(0ms));
 
     // We don't know which window will ANR first. But both of them should happen eventually.
     ASSERT_TRUE(mFocusedWindow->getToken() == anrConnectionToken1 ||
@@ -4867,8 +4862,9 @@
     mFocusedWindow->consumeMotionUp();
     mUnfocusedWindow->consumeMotionOutside();
 
-    sp<IBinder> responsiveToken1 = mFakePolicy->getResponsiveWindowToken();
-    sp<IBinder> responsiveToken2 = mFakePolicy->getResponsiveWindowToken();
+    sp<IBinder> responsiveToken1, responsiveToken2;
+    ASSERT_NO_FATAL_FAILURE(responsiveToken1 = mFakePolicy->getResponsiveWindowToken());
+    ASSERT_NO_FATAL_FAILURE(responsiveToken2 = mFakePolicy->getResponsiveWindowToken());
 
     // Both applications should be marked as responsive, in any order
     ASSERT_TRUE(mFocusedWindow->getToken() == responsiveToken1 ||
@@ -4892,7 +4888,7 @@
     ASSERT_TRUE(upEventSequenceNum);
     const std::chrono::duration timeout =
             mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
 
     // Tap once again
     // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success
@@ -4913,7 +4909,8 @@
     // The second tap did not go to the focused window
     mFocusedWindow->assertNoEvents();
     // Since all events are finished, connection should be deemed healthy again
-    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
+                                                       mFocusedWindow->getPid());
     mFakePolicy->assertNotifyAnrWasNotCalled();
 }
 
@@ -5025,7 +5022,7 @@
 
     const std::chrono::duration timeout =
             mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow->getToken());
+    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow);
 
     mUnfocusedWindow->consumeMotionDown();
     mFocusedWindow->consumeMotionDown();
@@ -5044,7 +5041,8 @@
         ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction());
     }
     ASSERT_TRUE(mDispatcher->waitForIdle());
-    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken());
+    mFakePolicy->assertNotifyWindowResponsiveWasCalled(mFocusedWindow->getToken(),
+                                                       mFocusedWindow->getPid());
 
     mUnfocusedWindow->assertNoEvents();
     mFocusedWindow->assertNoEvents();
@@ -5496,7 +5494,7 @@
     sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name, TouchOcclusionMode mode,
                                             float alpha = 1.0f) {
         sp<FakeWindowHandle> window = getWindow(uid, name);
-        window->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
+        window->setTouchable(false);
         window->setTouchOcclusionMode(mode);
         window->setAlpha(alpha);
         return window;
@@ -5610,7 +5608,7 @@
        WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
     const sp<FakeWindowHandle>& w =
             getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
-    w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+    w->setWatchOutsideTouch(true);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
 
     touch();
@@ -5621,7 +5619,7 @@
 TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
     const sp<FakeWindowHandle>& w =
             getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
-    w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+    w->setWatchOutsideTouch(true);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
 
     touch();
@@ -5871,11 +5869,9 @@
         mApp = std::make_shared<FakeApplicationHandle>();
         mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
         mWindow->setFrame(Rect(0, 0, 100, 100));
-        mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
         mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
         mSecondWindow->setFrame(Rect(100, 0, 200, 100));
-        mSecondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
 
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
         mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
@@ -6130,7 +6126,7 @@
                                  ADISPLAY_ID_DEFAULT);
     obscuringWindow->setFrame(Rect(0, 0, 50, 50));
     obscuringWindow->setOwnerInfo(111, 111);
-    obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
+    obscuringWindow->setTouchable(false);
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
             new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
@@ -6176,7 +6172,7 @@
                                  ADISPLAY_ID_DEFAULT);
     obscuringWindow->setFrame(Rect(0, 0, 50, 50));
     obscuringWindow->setOwnerInfo(111, 111);
-    obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
+    obscuringWindow->setTouchable(false);
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
             new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
@@ -6282,7 +6278,7 @@
 
 class InputDispatcherSpyWindowTest : public InputDispatcherTest {
 public:
-    sp<FakeWindowHandle> createSpy(const Flags<WindowInfo::Flag> flags) {
+    sp<FakeWindowHandle> createSpy() {
         std::shared_ptr<FakeApplicationHandle> application =
                 std::make_shared<FakeApplicationHandle>();
         std::string name = "Fake Spy ";
@@ -6291,7 +6287,6 @@
                 new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT);
         spy->setInputFeatures(WindowInfo::Feature::SPY);
         spy->setTrustedOverlay(true);
-        spy->addFlags(flags);
         return spy;
     }
 
@@ -6300,7 +6295,6 @@
                 std::make_shared<FakeApplicationHandle>();
         sp<FakeWindowHandle> window =
                 new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
-        window->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
         window->setFocusable(true);
         return window;
     }
@@ -6316,7 +6310,7 @@
 TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
     ScopedSilentDeath _silentDeath;
 
-    auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+    auto spy = createSpy();
     spy->setTrustedOverlay(false);
     ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}),
                  ".* not a trusted overlay");
@@ -6326,7 +6320,7 @@
  * Input injection into a display with a spy window but no foreground windows should succeed.
  */
 TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
-    auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+    auto spy = createSpy();
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}});
 
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6349,9 +6343,9 @@
  */
 TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) {
     auto window = createForeground();
-    auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
-    auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
-    auto spy3 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+    auto spy1 = createSpy();
+    auto spy2 = createSpy();
+    auto spy3 = createSpy();
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window, spy3}}});
     const std::vector<sp<FakeWindowHandle>> channels{spy1, spy2, window, spy3};
     const size_t numChannels = channels.size();
@@ -6402,7 +6396,8 @@
  */
 TEST_F(InputDispatcherSpyWindowTest, NotTouchable) {
     auto window = createForeground();
-    auto spy = createSpy(WindowInfo::Flag::NOT_TOUCHABLE);
+    auto spy = createSpy();
+    spy->setTouchable(false);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
 
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6419,7 +6414,7 @@
  */
 TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) {
     auto window = createForeground();
-    auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+    auto spy = createSpy();
     spy->setTouchableRegion(Region{{0, 0, 20, 20}});
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
 
@@ -6445,32 +6440,14 @@
 }
 
 /**
- * A spy window that is a modal window will receive gestures outside of its frame and touchable
- * region.
- */
-TEST_F(InputDispatcherSpyWindowTest, ModalWindow) {
-    auto window = createForeground();
-    auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
-    // This spy window does not have the NOT_TOUCH_MODAL flag set.
-    spy->setFrame(Rect{0, 0, 20, 20});
-    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
-
-    // Inject an event outside the spy window's frame and touchable region.
-    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
-            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
-    window->consumeMotionDown();
-    spy->consumeMotionDown();
-}
-
-/**
  * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
  * flag, but it will get zero-ed out coordinates if the foreground has a different owner.
  */
 TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
     auto window = createForeground();
     window->setOwnerInfo(12, 34);
-    auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+    auto spy = createSpy();
+    spy->setWatchOutsideTouch(true);
     spy->setOwnerInfo(56, 78);
     spy->setFrame(Rect{0, 0, 20, 20});
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
@@ -6490,8 +6467,8 @@
  */
 TEST_F(InputDispatcherSpyWindowTest, PilferPointers) {
     auto window = createForeground();
-    auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
-    auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+    auto spy1 = createSpy();
+    auto spy2 = createSpy();
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window}}});
 
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6523,7 +6500,7 @@
  */
 TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) {
     auto window = createForeground();
-    auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+    auto spy = createSpy();
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
 
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6547,9 +6524,8 @@
  * the spy, but not to any other windows.
  */
 TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) {
-    auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+    auto spy = createSpy();
     auto window = createForeground();
-    window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
 
@@ -6615,7 +6591,7 @@
     windowLeft->setFrame({0, 0, 100, 200});
     auto windowRight = createForeground();
     windowRight->setFrame({100, 0, 200, 200});
-    auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+    auto spy = createSpy();
     spy->setFrame({0, 0, 200, 200});
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, windowLeft, windowRight}}});
 
@@ -6650,7 +6626,7 @@
 TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
     auto window = createForeground();
     window->setFrame({0, 0, 200, 200});
-    auto spyRight = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+    auto spyRight = createSpy();
     spyRight->setFrame({100, 0, 200, 200});
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyRight, window}}});
 
@@ -6683,15 +6659,13 @@
  * windows should be allowed to control split touch.
  */
 TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
-    // Create a touch modal spy that spies on the entire display.
-    // This spy window does not set the SPLIT_TOUCH flag. However, we still expect to split touches
+    // This spy window prevents touch splitting. However, we still expect to split touches
     // because a foreground window has not disabled splitting.
-    auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
+    auto spy = createSpy();
+    spy->setPreventSplitting(true);
 
-    // Create a non touch modal window that supports split touch.
     auto window = createForeground();
     window->setFrame(Rect(0, 0, 100, 100));
-    window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
 
@@ -6729,7 +6703,7 @@
  * do not receive key events.
  */
 TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
-    auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
+    auto spy = createSpy();
     spy->setFocusable(false);
 
     auto window = createForeground();
@@ -6758,7 +6732,7 @@
                                      ADISPLAY_ID_DEFAULT);
         overlay->setFocusable(false);
         overlay->setOwnerInfo(111, 111);
-        overlay->setFlags(WindowInfo::Flag::NOT_TOUCHABLE | WindowInfo::Flag::SPLIT_TOUCH);
+        overlay->setTouchable(false);
         overlay->setInputFeatures(WindowInfo::Feature::INTERCEPTS_STYLUS);
         overlay->setTrustedOverlay(true);
 
@@ -6769,7 +6743,6 @@
                                      ADISPLAY_ID_DEFAULT);
         window->setFocusable(true);
         window->setOwnerInfo(222, 222);
-        window->setFlags(WindowInfo::Flag::SPLIT_TOUCH);
 
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
         mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}});
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 54cf15d..9f33d23 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -20,6 +20,7 @@
 #include <InputReader.h>
 #include <InputReaderBase.h>
 #include <InputReaderFactory.h>
+#include <JoystickInputMapper.h>
 #include <KeyboardInputMapper.h>
 #include <MultiTouchInputMapper.h>
 #include <PeripheralController.h>
@@ -8251,6 +8252,25 @@
     ASSERT_EQ(DISPLAY_ID, args.displayId);
 }
 
+TEST_F(MultiTouchInputMapperTest, Configure_AssignsDisplayUniqueId) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareAxes(POSITION);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, VIRTUAL_DISPLAY_UNIQUE_ID);
+
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareVirtualDisplay(DISPLAY_ORIENTATION_0);
+
+    // Send a touch event
+    processPosition(mapper, 100, 100);
+    processSync(mapper);
+
+    NotifyMotionArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(VIRTUAL_DISPLAY_ID, args.displayId);
+}
+
 TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) {
     // Setup for second display.
     std::shared_ptr<FakePointerController> fakePointerController =
@@ -9260,6 +9280,67 @@
     ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
 }
 
+// --- JoystickInputMapperTest ---
+
+class JoystickInputMapperTest : public InputMapperTest {
+protected:
+    static const int32_t RAW_X_MIN;
+    static const int32_t RAW_X_MAX;
+    static const int32_t RAW_Y_MIN;
+    static const int32_t RAW_Y_MAX;
+
+    void SetUp() override {
+        InputMapperTest::SetUp(InputDeviceClass::JOYSTICK | InputDeviceClass::EXTERNAL);
+    }
+    void prepareAxes() {
+        mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_X, RAW_X_MIN, RAW_X_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0);
+    }
+
+    void processAxis(JoystickInputMapper& mapper, int32_t axis, int32_t value) {
+        process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, axis, value);
+    }
+
+    void processSync(JoystickInputMapper& mapper) {
+        process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+    }
+
+    void prepareVirtualDisplay(int32_t orientation) {
+        setDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH,
+                                     VIRTUAL_DISPLAY_HEIGHT, orientation, VIRTUAL_DISPLAY_UNIQUE_ID,
+                                     NO_PORT, ViewportType::VIRTUAL);
+    }
+};
+
+const int32_t JoystickInputMapperTest::RAW_X_MIN = -32767;
+const int32_t JoystickInputMapperTest::RAW_X_MAX = 32767;
+const int32_t JoystickInputMapperTest::RAW_Y_MIN = -32767;
+const int32_t JoystickInputMapperTest::RAW_Y_MAX = 32767;
+
+TEST_F(JoystickInputMapperTest, Configure_AssignsDisplayUniqueId) {
+    prepareAxes();
+    JoystickInputMapper& mapper = addMapperAndConfigure<JoystickInputMapper>();
+
+    mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, VIRTUAL_DISPLAY_UNIQUE_ID);
+
+    prepareVirtualDisplay(DISPLAY_ORIENTATION_0);
+
+    // Send an axis event
+    processAxis(mapper, ABS_X, 100);
+    processSync(mapper);
+
+    NotifyMotionArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(VIRTUAL_DISPLAY_ID, args.displayId);
+
+    // Send another axis event
+    processAxis(mapper, ABS_Y, 100);
+    processSync(mapper);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(VIRTUAL_DISPLAY_ID, args.displayId);
+}
+
 // --- PeripheralControllerTest ---
 
 class PeripheralControllerTest : public testing::Test {
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 971491d..3c164aa 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -134,6 +134,7 @@
       mWakeLockAcquired(false), mLastReportedProxIsActive(false) {
     mUidPolicy = new UidPolicy(this);
     mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
+    mMicSensorPrivacyPolicy = new MicrophonePrivacyPolicy(this);
 }
 
 bool SensorService::initializeHmacKey() {
@@ -369,6 +370,9 @@
 
             // Start watching sensor privacy changes
             mSensorPrivacyPolicy->registerSelf();
+
+            // Start watching mic sensor privacy changes
+            mMicSensorPrivacyPolicy->registerSelf();
         }
     }
 }
@@ -439,9 +443,7 @@
     }
     mUidPolicy->unregisterSelf();
     mSensorPrivacyPolicy->unregisterSelf();
-    for (auto const& [userId, policy] : mMicSensorPrivacyPolicies) {
-        policy->unregisterSelf();
-    }
+    mMicSensorPrivacyPolicy->unregisterSelf();
 }
 
 status_t SensorService::dump(int fd, const Vector<String16>& args) {
@@ -773,33 +775,25 @@
     checkAndReportProxStateChangeLocked();
 }
 
-void SensorService::capRates(userid_t userId) {
+void SensorService::capRates() {
     ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
     for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
-        if (conn->getUserId() == userId) {
-            conn->onMicSensorAccessChanged(true);
-        }
+        conn->onMicSensorAccessChanged(true);
     }
 
     for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
-        if (conn->getUserId() == userId) {
-            conn->onMicSensorAccessChanged(true);
-        }
+        conn->onMicSensorAccessChanged(true);
     }
 }
 
-void SensorService::uncapRates(userid_t userId) {
+void SensorService::uncapRates() {
     ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
     for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
-        if (conn->getUserId() == userId) {
-            conn->onMicSensorAccessChanged(false);
-        }
+        conn->onMicSensorAccessChanged(false);
     }
 
     for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
-        if (conn->getUserId() == userId) {
-            conn->onMicSensorAccessChanged(false);
-        }
+        conn->onMicSensorAccessChanged(false);
     }
 }
 
@@ -2243,7 +2237,6 @@
 
 status_t SensorService::adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* requestedPeriodNs,
         const String16& opPackageName) {
-    uid_t uid = IPCThreadState::self()->getCallingUid();
     if (*requestedPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
         return OK;
     }
@@ -2255,7 +2248,7 @@
         }
         return OK;
     }
-    if (isMicSensorPrivacyEnabledForUid(uid)) {
+    if (mMicSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
         *requestedPeriodNs = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
         return OK;
     }
@@ -2264,7 +2257,6 @@
 
 status_t SensorService::adjustRateLevelBasedOnMicAndPermission(int* requestedRateLevel,
         const String16& opPackageName) {
-    uid_t uid = IPCThreadState::self()->getCallingUid();
     if (*requestedRateLevel <= SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) {
         return OK;
     }
@@ -2276,7 +2268,7 @@
         }
         return OK;
     }
-    if (isMicSensorPrivacyEnabledForUid(uid)) {
+    if (mMicSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
         *requestedRateLevel = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
         return OK;
     }
@@ -2293,69 +2285,63 @@
 void SensorService::SensorPrivacyPolicy::unregisterSelf() {
     AutoCallerClear acc;
     SensorPrivacyManager spm;
-    if (mIsIndividualMic) {
-        spm.removeIndividualSensorPrivacyListener(
-                SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE, this);
-    } else {
-        spm.removeSensorPrivacyListener(this);
-    }
+    spm.removeSensorPrivacyListener(this);
 }
 
 bool SensorService::SensorPrivacyPolicy::isSensorPrivacyEnabled() {
     return mSensorPrivacyEnabled;
 }
 
-binder::Status SensorService::SensorPrivacyPolicy::onSensorPrivacyChanged(bool enabled) {
+binder::Status SensorService::SensorPrivacyPolicy::onSensorPrivacyChanged(int toggleType __unused,
+        int sensor __unused, bool enabled) {
     mSensorPrivacyEnabled = enabled;
     sp<SensorService> service = mService.promote();
 
     if (service != nullptr) {
-        if (mIsIndividualMic) {
-            if (enabled) {
-                service->capRates(mUserId);
-            } else {
-                service->uncapRates(mUserId);
-            }
+        if (enabled) {
+            service->disableAllSensors();
         } else {
-            if (enabled) {
-                service->disableAllSensors();
-            } else {
-                service->enableAllSensors();
-            }
+            service->enableAllSensors();
         }
     }
     return binder::Status::ok();
 }
 
-status_t SensorService::SensorPrivacyPolicy::registerSelfForIndividual(int userId) {
-    Mutex::Autolock _l(mSensorPrivacyLock);
+void SensorService::MicrophonePrivacyPolicy::registerSelf() {
     AutoCallerClear acc;
     SensorPrivacyManager spm;
-    status_t err = spm.addIndividualSensorPrivacyListener(userId,
-            SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE, this);
-
-    if (err != OK) {
-        ALOGE("Cannot register a mic listener.");
-        return err;
-    }
-    mSensorPrivacyEnabled = spm.isIndividualSensorPrivacyEnabled(userId,
-                SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE);
-
-    mIsIndividualMic = true;
-    mUserId = userId;
-    return OK;
+    mSensorPrivacyEnabled =
+            spm.isToggleSensorPrivacyEnabled(
+                    SensorPrivacyManager::TOGGLE_TYPE_SOFTWARE,
+            SensorPrivacyManager::TOGGLE_SENSOR_MICROPHONE)
+                    || spm.isToggleSensorPrivacyEnabled(
+                            SensorPrivacyManager::TOGGLE_TYPE_HARDWARE,
+                            SensorPrivacyManager::TOGGLE_SENSOR_MICROPHONE);
+    spm.addToggleSensorPrivacyListener(this);
 }
 
-bool SensorService::isMicSensorPrivacyEnabledForUid(uid_t uid) {
-    userid_t userId = multiuser_get_user_id(uid);
-    if (mMicSensorPrivacyPolicies.find(userId) == mMicSensorPrivacyPolicies.end()) {
-        sp<SensorPrivacyPolicy> userPolicy = new SensorPrivacyPolicy(this);
-        if (userPolicy->registerSelfForIndividual(userId) != OK) {
-            return false;
-        }
-        mMicSensorPrivacyPolicies[userId] = userPolicy;
+void SensorService::MicrophonePrivacyPolicy::unregisterSelf() {
+    AutoCallerClear acc;
+    SensorPrivacyManager spm;
+    spm.removeToggleSensorPrivacyListener(this);
+}
+
+binder::Status SensorService::MicrophonePrivacyPolicy::onSensorPrivacyChanged(int toggleType __unused,
+        int sensor, bool enabled) {
+    if (sensor != SensorPrivacyManager::TOGGLE_SENSOR_MICROPHONE) {
+        return binder::Status::ok();
     }
-    return mMicSensorPrivacyPolicies[userId]->isSensorPrivacyEnabled();
+    mSensorPrivacyEnabled = enabled;
+    sp<SensorService> service = mService.promote();
+
+    if (service != nullptr) {
+        if (enabled) {
+            service->capRates();
+        } else {
+            service->uncapRates();
+        }
+    }
+    return binder::Status::ok();
 }
 
 SensorService::ConnectionSafeAutolock::ConnectionSafeAutolock(
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index b009829..7194db3 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -289,22 +289,32 @@
     class SensorPrivacyPolicy : public hardware::BnSensorPrivacyListener {
         public:
             explicit SensorPrivacyPolicy(wp<SensorService> service)
-                    : mService(service), mIsIndividualMic(false), mUserId(0) {}
+                    : mService(service) {}
             void registerSelf();
             void unregisterSelf();
 
-            status_t registerSelfForIndividual(int userId);
-
             bool isSensorPrivacyEnabled();
 
-            binder::Status onSensorPrivacyChanged(bool enabled);
+            binder::Status onSensorPrivacyChanged(int toggleType, int sensor,
+                                                  bool enabled);
+
+        protected:
+            std::atomic_bool mSensorPrivacyEnabled;
+            wp<SensorService> mService;
 
         private:
-            wp<SensorService> mService;
             Mutex mSensorPrivacyLock;
-            std::atomic_bool mSensorPrivacyEnabled;
-            bool mIsIndividualMic;
-            userid_t mUserId;
+    };
+
+    class MicrophonePrivacyPolicy : public SensorPrivacyPolicy {
+        public:
+            explicit MicrophonePrivacyPolicy(wp<SensorService> service)
+                    : SensorPrivacyPolicy(service) {}
+            void registerSelf();
+            void unregisterSelf();
+
+            binder::Status onSensorPrivacyChanged(int toggleType, int sensor,
+                                                  bool enabled);
     };
 
     // A class automatically clearing and restoring binder caller identity inside
@@ -444,9 +454,9 @@
     void enableAllSensorsLocked(ConnectionSafeAutolock* connLock);
 
     // Caps active direct connections (when the mic toggle is flipped to on)
-    void capRates(userid_t userId);
+    void capRates();
     // Removes the capped rate on active direct connections (when the mic toggle is flipped to off)
-    void uncapRates(userid_t userId);
+    void uncapRates();
 
     static inline bool isAudioServerOrSystemServerUid(uid_t uid) {
         return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
@@ -497,10 +507,7 @@
     static Mutex sPackageTargetVersionLock;
     static String16 sSensorInterfaceDescriptorPrefix;
 
-    // Map from user to SensorPrivacyPolicy
-    std::map<userid_t, sp<SensorPrivacyPolicy>> mMicSensorPrivacyPolicies;
-    // Checks if the mic sensor privacy is enabled for the uid
-    bool isMicSensorPrivacyEnabledForUid(uid_t uid);
+    sp<MicrophonePrivacyPolicy> mMicSensorPrivacyPolicy;
 
     // Keeps track of the handles of all proximity sensors in the system.
     std::vector<int32_t> mProxSensorHandles;
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index d9958f3..000a2cb 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -76,6 +76,7 @@
         "libaidlcommonsupport",
         "libcompositionengine",
         "libframetimeline",
+        "libgui_aidl_static",
         "libperfetto_client_experimental",
         "librenderengine",
         "libscheduler",
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 02e444d..e6a76e8 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -271,7 +271,8 @@
 // Translate destination frame into scale and position. If a destination frame is not set, use the
 // provided scale and position
 bool BufferStateLayer::updateGeometry() {
-    if (mDrawingState.destinationFrame.isEmpty()) {
+    if ((mDrawingState.flags & layer_state_t::eIgnoreDestinationFrame) ||
+        mDrawingState.destinationFrame.isEmpty()) {
         // If destination frame is not set, use the requested transform set via
         // BufferStateLayer::setPosition and BufferStateLayer::setMatrix.
         return assignTransform(&mDrawingState.transform, mRequestedTransform);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 6c7ba22..58d2530 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -78,7 +78,7 @@
     virtual void applyChangedTypesToLayers(const ChangedTypes&);
     virtual void applyDisplayRequests(const DisplayRequests&);
     virtual void applyLayerRequestsToLayers(const LayerRequests&);
-    virtual void applyClientTargetRequests(const ClientTargetProperty&, float whitePointNits);
+    virtual void applyClientTargetRequests(const ClientTargetProperty&, float brightness);
 
     // Internal
     virtual void setConfiguration(const compositionengine::DisplayCreationArgs&);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
index 7521324..196af70 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <cstdint>
+#include <optional>
 #include <string>
 #include <type_traits>
 
@@ -63,4 +64,13 @@
 void dumpVal(std::string& out, const char* name, const mat4&);
 void dumpVal(std::string& out, const char* name, const StretchEffect&);
 
+template <typename T>
+void dumpVal(std::string& out, const char* name, std::optional<T> value) {
+    if (value.has_value()) {
+        return dumpVal(out, name, *value);
+    } else {
+        return dumpVal(out, name, "nullopt");
+    }
+}
+
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index cc7c257..66dd825 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -130,8 +130,8 @@
     // SDR white point
     float sdrWhitePointNits{-1.f};
 
-    // White point of the client target
-    float clientTargetWhitePointNits{-1.f};
+    // Brightness of the client target, normalized to display brightness
+    float clientTargetBrightness{1.f};
 
     // Display brightness that will take effect this frame.
     // This is slightly distinct from nits, in that nits cannot be passed to hw composer.
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 b9d7983..6a75283 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -266,8 +266,7 @@
         applyChangedTypesToLayers(changes->changedTypes);
         applyDisplayRequests(changes->displayRequests);
         applyLayerRequestsToLayers(changes->layerRequests);
-        applyClientTargetRequests(changes->clientTargetProperty,
-                                  changes->clientTargetWhitePointNits);
+        applyClientTargetRequests(changes->clientTargetProperty, changes->clientTargetBrightness);
     }
 
     // Determine what type of composition we are doing from the final state
@@ -343,13 +342,13 @@
 }
 
 void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty,
-                                        float whitePointNits) {
+                                        float brightness) {
     if (clientTargetProperty.dataspace == ui::Dataspace::UNKNOWN) {
         return;
     }
 
     editState().dataspace = clientTargetProperty.dataspace;
-    editState().clientTargetWhitePointNits = whitePointNits;
+    editState().clientTargetBrightness = brightness;
     getRenderSurface()->setBufferDataspace(clientTargetProperty.dataspace);
     getRenderSurface()->setBufferPixelFormat(clientTargetProperty.pixelFormat);
 }
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 65f9731..ff332eb 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1076,12 +1076,13 @@
             : mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
     clientCompositionDisplay.maxLuminance =
             mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
-    clientCompositionDisplay.targetLuminanceNits = outputState.clientTargetWhitePointNits;
+    clientCompositionDisplay.targetLuminanceNits =
+            outputState.clientTargetBrightness * outputState.displayBrightnessNits;
 
     // Compute the global color transform matrix.
-    if (!outputState.usesDeviceComposition && !getSkipColorTransform()) {
-        clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
-    }
+    clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
+    clientCompositionDisplay.deviceHandlesColorTransform =
+            outputState.usesDeviceComposition || getSkipColorTransform();
 
     // Generate the client composition requests for the layers on this output.
     std::vector<LayerFE*> clientCompositionLayersFE;
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index acc9216..482250a 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -52,6 +52,10 @@
     dumpVal(out, "dataspace", toString(dataspace), dataspace);
     dumpVal(out, "colorTransformMatrix", colorTransformMatrix);
     dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace);
+    dumpVal(out, "displayBrightnessNits", displayBrightnessNits);
+    dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits);
+    dumpVal(out, "clientTargetBrightness", clientTargetBrightness);
+    dumpVal(out, "displayBrightness", displayBrightness);
 
     out.append("\n");
 }
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/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index cfa740e..6749427 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -67,6 +67,8 @@
     dumpVal(out, "sourceCrop", sourceCrop);
     dumpVal(out, "bufferTransform", toString(bufferTransform), bufferTransform);
     dumpVal(out, "dataspace", toString(dataspace), dataspace);
+    dumpVal(out, "whitePointNits", whitePointNits);
+    dumpVal(out, "dimmingRatio", dimmingRatio);
     dumpVal(out, "override buffer", overrideInfo.buffer.get());
     dumpVal(out, "override acquire fence", overrideInfo.acquireFence.get());
     dumpVal(out, "override display frame", overrideInfo.displayFrame);
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 44d34a3..cd03235 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -839,7 +839,7 @@
 
     auto& state = mDisplay->getState();
     EXPECT_EQ(clientTargetProperty.dataspace, state.dataspace);
-    EXPECT_EQ(kWhitePointNits, state.clientTargetWhitePointNits);
+    EXPECT_EQ(kWhitePointNits, state.clientTargetBrightness);
 }
 
 /*
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/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/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index e72bc9f..c2521b2 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3067,7 +3067,7 @@
         mOutput.mState.usesDeviceComposition = false;
         mOutput.mState.reusedClientComposition = false;
         mOutput.mState.flipClientTarget = false;
-        mOutput.mState.clientTargetWhitePointNits = kClientTargetLuminanceNits;
+        mOutput.mState.clientTargetBrightness = kClientTargetBrightness;
 
         EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine));
         EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
@@ -3103,8 +3103,9 @@
     static constexpr float kDefaultAvgLuminance = 0.7f;
     static constexpr float kDefaultMinLuminance = 0.1f;
     static constexpr float kUnknownLuminance = -1.f;
-    static constexpr float kDisplayLuminance = 80.f;
+    static constexpr float kDisplayLuminance = 400.f;
     static constexpr float kClientTargetLuminanceNits = 200.f;
+    static constexpr float kClientTargetBrightness = 0.5f;
 
     static const Rect kDefaultOutputFrame;
     static const Rect kDefaultOutputViewport;
@@ -3487,7 +3488,8 @@
                                             .maxLuminance = kDefaultMaxLuminance,
                                             .currentLuminanceNits = kDefaultMaxLuminance,
                                             .outputDataspace = kDefaultOutputDataspace,
-                                            .colorTransform = mat4(),
+                                            .colorTransform = kDefaultColorTransformMat,
+                                            .deviceHandlesColorTransform = true,
                                             .orientation = kDefaultOutputOrientationFlags,
                                             .targetLuminanceNits = kClientTargetLuminanceNits})
             .execute()
@@ -3505,7 +3507,8 @@
                                             .maxLuminance = kDefaultMaxLuminance,
                                             .currentLuminanceNits = kDisplayLuminance,
                                             .outputDataspace = kDefaultOutputDataspace,
-                                            .colorTransform = mat4(),
+                                            .colorTransform = kDefaultColorTransformMat,
+                                            .deviceHandlesColorTransform = true,
                                             .orientation = kDefaultOutputOrientationFlags,
                                             .targetLuminanceNits = kClientTargetLuminanceNits})
             .execute()
@@ -3522,7 +3525,8 @@
                                             .maxLuminance = kDefaultMaxLuminance,
                                             .currentLuminanceNits = kDefaultMaxLuminance,
                                             .outputDataspace = kDefaultOutputDataspace,
-                                            .colorTransform = mat4(),
+                                            .colorTransform = kDefaultColorTransformMat,
+                                            .deviceHandlesColorTransform = true,
                                             .orientation = kDefaultOutputOrientationFlags,
                                             .targetLuminanceNits = kClientTargetLuminanceNits})
             .execute()
@@ -3540,6 +3544,7 @@
                                             .currentLuminanceNits = kDefaultMaxLuminance,
                                             .outputDataspace = kDefaultOutputDataspace,
                                             .colorTransform = kDefaultColorTransformMat,
+                                            .deviceHandlesColorTransform = false,
                                             .orientation = kDefaultOutputOrientationFlags,
                                             .targetLuminanceNits = kClientTargetLuminanceNits})
             .execute()
@@ -3557,6 +3562,7 @@
                                             .currentLuminanceNits = kDefaultMaxLuminance,
                                             .outputDataspace = kDefaultOutputDataspace,
                                             .colorTransform = kDefaultColorTransformMat,
+                                            .deviceHandlesColorTransform = false,
                                             .orientation = kDefaultOutputOrientationFlags,
                                             .targetLuminanceNits = kClientTargetLuminanceNits})
             .execute()
@@ -3574,7 +3580,8 @@
                                             .maxLuminance = kDefaultMaxLuminance,
                                             .currentLuminanceNits = kDefaultMaxLuminance,
                                             .outputDataspace = kDefaultOutputDataspace,
-                                            .colorTransform = mat4(),
+                                            .colorTransform = kDefaultColorTransformMat,
+                                            .deviceHandlesColorTransform = true,
                                             .orientation = kDefaultOutputOrientationFlags,
                                             .targetLuminanceNits = kClientTargetLuminanceNits})
             .execute()
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 2b41ef4..45b98bb 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -141,7 +141,7 @@
     return mCompositionDisplay->getRenderSurface()->getPageFlipCount();
 }
 
-std::pair<gui::DisplayInfo, ui::Transform> DisplayDevice::getInputInfo() const {
+auto DisplayDevice::getInputInfo() const -> InputInfo {
     gui::DisplayInfo info;
     info.displayId = getLayerStack().id;
 
@@ -166,10 +166,13 @@
 
     info.logicalWidth = getLayerStackSpaceRect().width();
     info.logicalHeight = getLayerStackSpaceRect().height();
-    return {info, displayTransform};
+
+    return {.info = info,
+            .transform = displayTransform,
+            .receivesInput = receivesInput(),
+            .isSecure = isSecure()};
 }
 
-// ----------------------------------------------------------------------------
 void DisplayDevice::setPowerMode(hal::PowerMode mode) {
     mPowerMode = mode;
     getCompositionDisplay()->setCompositionEnabled(mPowerMode != hal::PowerMode::OFF);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e8bd62d..690f240 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -174,9 +174,14 @@
         return mDeviceProductInfo;
     }
 
-    // Get the DisplayInfo that will be sent to InputFlinger, and the display transform that should
-    // be applied to all the input windows on the display.
-    std::pair<gui::DisplayInfo, ui::Transform> getInputInfo() const;
+    struct InputInfo {
+        gui::DisplayInfo info;
+        ui::Transform transform;
+        bool receivesInput;
+        bool isSecure;
+    };
+
+    InputInfo getInputInfo() const;
 
     /* ------------------------------------------------------------------------
      * Display power mode management.
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 04723a2..80e2d99 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -20,6 +20,7 @@
 
 #include "AidlComposerHal.h"
 
+#include <android-base/file.h>
 #include <android/binder_ibinder_platform.h>
 #include <android/binder_manager.h>
 #include <log/log.h>
@@ -115,7 +116,7 @@
 AidlPerFrameMetadataBlob translate(IComposerClient::PerFrameMetadataBlob x) {
     AidlPerFrameMetadataBlob blob;
     blob.key = translate<AidlPerFrameMetadataKey>(x.key),
-    std::copy(blob.blob.begin(), blob.blob.end(), x.blob.begin());
+    std::copy(x.blob.begin(), x.blob.end(), std::inserter(blob.blob, blob.blob.end()));
     return blob;
 }
 
@@ -262,13 +263,27 @@
 }
 
 std::string AidlComposer::dumpDebugInfo() {
-    std::string info;
-    const auto status = mAidlComposer->dumpDebugInfo(&info);
-    if (!status.isOk()) {
-        ALOGE("dumpDebugInfo failed %s", status.getDescription().c_str());
+    int pipefds[2];
+    int result = pipe(pipefds);
+    if (result < 0) {
+        ALOGE("dumpDebugInfo: pipe failed: %s", strerror(errno));
         return {};
     }
-    return info;
+
+    std::string str;
+    const auto status = mAidlComposer->dump(pipefds[1], /*args*/ nullptr, /*numArgs*/ 0);
+    // Close the write-end of the pipe to make sure that when reading from the
+    // read-end we will get eof instead of blocking forever
+    close(pipefds[1]);
+
+    if (status == STATUS_OK) {
+        base::ReadFdToString(pipefds[0], &str);
+    } else {
+        ALOGE("dumpDebugInfo: dump failed: %d", status);
+    }
+
+    close(pipefds[0]);
+    return str;
 }
 
 void AidlComposer::registerCallback(HWC2::ComposerCallback& callback) {
@@ -1054,17 +1069,16 @@
 
 Error AidlComposer::getClientTargetProperty(
         Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
-        float* whitePointNits) {
+        float* outBrightness) {
     const auto property = mReader.takeClientTargetProperty(translate<int64_t>(display));
     *outClientTargetProperty =
             translate<IComposerClient::ClientTargetProperty>(property.clientTargetProperty);
-    *whitePointNits = property.whitePointNits;
+    *outBrightness = property.brightness;
     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;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index ed8049a..80ca8da 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -209,10 +209,10 @@
             std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
     Error getClientTargetProperty(Display display,
                                   IComposerClient::ClientTargetProperty* outClientTargetProperty,
-                                  float* outClientTargetWhitePointNits) override;
+                                  float* outBrightness) 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;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 2c5164d..23886d4 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -261,10 +261,10 @@
 
     virtual Error getClientTargetProperty(
             Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
-            float* outWhitePointNits) = 0;
+            float* outBrightness) = 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;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 50a6604..a1b663c 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -947,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 f03aafc..334d6ec 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -327,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;
 };
@@ -376,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:
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 6a3162e..ed6e4b0 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -479,13 +479,12 @@
     RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
 
     DeviceRequestedChanges::ClientTargetProperty clientTargetProperty;
-    float clientTargetWhitePointNits;
-    error = hwcDisplay->getClientTargetProperty(&clientTargetProperty, &clientTargetWhitePointNits);
+    float brightness = 1.f;
+    error = hwcDisplay->getClientTargetProperty(&clientTargetProperty, &brightness);
 
     outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
                                                std::move(layerRequests),
-                                               std::move(clientTargetProperty),
-                                               clientTargetWhitePointNits});
+                                               std::move(clientTargetProperty), brightness});
     error = hwcDisplay->acceptChanges();
     RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 916c4b7..5b2e265 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -86,7 +86,7 @@
         DisplayRequests displayRequests;
         LayerRequests layerRequests;
         ClientTargetProperty clientTargetProperty;
-        float clientTargetWhitePointNits;
+        float clientTargetBrightness;
     };
 
     struct HWCDisplayMode {
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index e33f1e0..f735bba 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -1297,13 +1297,13 @@
 
 Error HidlComposer::getClientTargetProperty(
         Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
-        float* outWhitePointNits) {
+        float* outBrightness) {
     mReader.takeClientTargetProperty(display, outClientTargetProperty);
-    *outWhitePointNits = -1.f;
+    *outBrightness = 1.f;
     return Error::NONE;
 }
 
-Error HidlComposer::setLayerWhitePointNits(Display, Layer, float) {
+Error HidlComposer::setLayerBrightness(Display, Layer, float) {
     return Error::NONE;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 6b33945..c2b60cb 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -318,10 +318,10 @@
             std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
     Error getClientTargetProperty(Display display,
                                   IComposerClient::ClientTargetProperty* outClientTargetProperty,
-                                  float* outWhitePointNits) override;
+                                  float* outBrightness) 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;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 6f02843..3dab389 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -16,6 +16,8 @@
 
 //#define LOG_NDEBUG 0
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #undef LOG_TAG
 #define LOG_TAG "PowerAdvisor"
 
@@ -27,6 +29,7 @@
 #include <android-base/properties.h>
 #include <utils/Log.h>
 #include <utils/Mutex.h>
+#include <utils/Trace.h>
 
 #include <android/hardware/power/1.3/IPower.h>
 #include <android/hardware/power/IPower.h>
@@ -70,6 +73,14 @@
     return timeout;
 }
 
+void traceExpensiveRendering(bool enabled) {
+    if (enabled) {
+        ATRACE_ASYNC_BEGIN("ExpensiveRendering", 0);
+    } else {
+        ATRACE_ASYNC_END("ExpensiveRendering", 0);
+    }
+}
+
 } // namespace
 
 PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger)
@@ -247,6 +258,9 @@
     bool setExpensiveRendering(bool enabled) override {
         ALOGV("HIDL setExpensiveRendering %s", enabled ? "T" : "F");
         auto ret = mPowerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, enabled);
+        if (ret.isOk()) {
+            traceExpensiveRendering(enabled);
+        }
         return ret.isOk();
     }
 
@@ -323,6 +337,9 @@
         }
 
         auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
+        if (ret.isOk()) {
+            traceExpensiveRendering(enabled);
+        }
         return ret.isOk();
     }
 
diff --git a/services/surfaceflinger/FlagManager.cpp b/services/surfaceflinger/FlagManager.cpp
index e09a192..bd3cf74 100644
--- a/services/surfaceflinger/FlagManager.cpp
+++ b/services/surfaceflinger/FlagManager.cpp
@@ -101,7 +101,6 @@
 }
 
 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);
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 86e96d7..81747d5 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -492,17 +492,22 @@
 
 void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& refreshRate,
                                       nsecs_t& deadlineDelta) {
-    if (mPredictionState == PredictionState::Expired ||
-        mActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
+    if (mActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
         // Cannot do any classification for invalid present time.
-        // For prediction expired case, we do not know what happened here to classify this
-        // correctly. This could potentially be AppDeadlineMissed but that's assuming no app will
-        // request frames 120ms apart.
         mJankType = JankType::Unknown;
         deadlineDelta = -1;
         return;
     }
 
+    if (mPredictionState == PredictionState::Expired) {
+        // We classify prediction expired as AppDeadlineMissed as the
+        // TokenManager::kMaxTokens we store is large enough to account for a
+        // reasonable app, so prediction expire would mean a huge scheduling delay.
+        mJankType = JankType::AppDeadlineMissed;
+        deadlineDelta = -1;
+        return;
+    }
+
     if (mPredictionState == PredictionState::None) {
         // Cannot do jank classification on frames that don't have a token.
         return;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a039250..533acfd 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(); });
 
@@ -2144,6 +2142,9 @@
             (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
         }
     }
+
+    LayerProtoHelper::writeToProto(state.destinationFrame,
+                                   [&]() { return layerInfo->mutable_destination_frame(); });
 }
 
 bool Layer::isRemovedFromCurrentState() const  {
@@ -2161,8 +2162,7 @@
 void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
     Rect tmpBounds = getInputBounds();
     if (!tmpBounds.isValid()) {
-        info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE;
-        info.focusable = false;
+        info.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, true);
         info.touchableRegion.clear();
         // A layer could have invalid input bounds and still expect to receive touch input if it has
         // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated
@@ -2309,7 +2309,6 @@
         mDrawingState.inputInfo.ownerUid = mOwnerUid;
         mDrawingState.inputInfo.ownerPid = mOwnerPid;
         mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL;
-        mDrawingState.inputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL;
         mDrawingState.inputInfo.displayId = getLayerStack().id;
     }
 
@@ -2327,7 +2326,9 @@
     // We are just using these layers for occlusion detection in
     // InputDispatcher, and obviously if they aren't visible they can't occlude
     // anything.
-    info.visible = hasInputInfo() ? canReceiveInput() : isVisible();
+    const bool visible = hasInputInfo() ? canReceiveInput() : isVisible();
+    info.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible);
+
     info.alpha = getAlpha();
     fillTouchOcclusionMode(info);
     handleDropInputMode(info);
@@ -2349,8 +2350,9 @@
 
     // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
     // if it was set by WM for a known system overlay
-    info.trustedOverlay = info.trustedOverlay || isTrustedOverlay();
-
+    if (isTrustedOverlay()) {
+        info.inputConfig |= WindowInfo::InputConfig::TRUSTED_OVERLAY;
+    }
 
     // If the layer is a clone, we need to crop the input region to cloned root to prevent
     // touches from going outside the cloned area.
@@ -2482,7 +2484,7 @@
     }
     // Cloned layers shouldn't handle watch outside since their z order is not determined by
     // WM or the client.
-    mDrawingState.inputInfo.flags &= ~WindowInfo::Flag::WATCH_OUTSIDE_TOUCH;
+    mDrawingState.inputInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, false);
 }
 
 void Layer::updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e51af1e..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.
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 015caa6..0506c47 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());
     }
 }
 
@@ -175,12 +175,12 @@
     }
 
     InputWindowInfoProto* proto = getInputWindowInfoProto();
-    proto->set_layout_params_flags(inputInfo.flags.get());
+    proto->set_layout_params_flags(inputInfo.layoutParamsFlags.get());
     using U = std::underlying_type_t<WindowInfo::Type>;
     // TODO(b/129481165): This static assert can be safely removed once conversion warnings
     // are re-enabled.
     static_assert(std::is_same_v<U, int32_t>);
-    proto->set_layout_params_type(static_cast<U>(inputInfo.type));
+    proto->set_layout_params_type(static_cast<U>(inputInfo.layoutParamsType));
 
     LayerProtoHelper::writeToProto({inputInfo.frameLeft, inputInfo.frameTop, inputInfo.frameRight,
                                     inputInfo.frameBottom},
@@ -189,9 +189,10 @@
                                    [&]() { return proto->mutable_touchable_region(); });
 
     proto->set_surface_inset(inputInfo.surfaceInset);
-    proto->set_visible(inputInfo.visible);
-    proto->set_focusable(inputInfo.focusable);
-    proto->set_has_wallpaper(inputInfo.hasWallpaper);
+    using InputConfig = gui::WindowInfo::InputConfig;
+    proto->set_visible(!inputInfo.inputConfig.test(InputConfig::NOT_VISIBLE));
+    proto->set_focusable(!inputInfo.inputConfig.test(InputConfig::NOT_FOCUSABLE));
+    proto->set_has_wallpaper(inputInfo.inputConfig.test(InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
 
     proto->set_global_scale_factor(inputInfo.globalScaleFactor);
     LayerProtoHelper::writeToProtoDeprecated(inputInfo.transform, proto->mutable_transform());
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 2d0da46..5ba8a1b 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -87,9 +87,10 @@
                                 to_string(event.header.displayId).c_str(),
                                 event.hotplug.connected ? "connected" : "disconnected");
         case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
-            return StringPrintf("VSync{displayId=%s, count=%u, expectedVSyncTimestamp=%" PRId64 "}",
+            return StringPrintf("VSync{displayId=%s, count=%u, expectedPresentationTime=%" PRId64
+                                "}",
                                 to_string(event.header.displayId).c_str(), event.vsync.count,
-                                event.vsync.expectedVSyncTimestamp);
+                                event.vsync.vsyncData.preferredExpectedPresentationTime());
         case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
             return StringPrintf("ModeChanged{displayId=%s, modeId=%u}",
                                 to_string(event.header.displayId).c_str(), event.modeChange.modeId);
@@ -107,13 +108,19 @@
 }
 
 DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp,
-                                      uint32_t count, nsecs_t expectedVSyncTimestamp,
+                                      uint32_t count, nsecs_t expectedPresentationTime,
                                       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.vsyncData.preferredFrameTimelineIndex = 0;
+    // Temporarily store the current vsync information in frameTimelines[0], marked as
+    // platform-preferred. When the event is dispatched later, the frame interval at that time is
+    // used with this information to generate multiple frame timeline choices.
+    event.vsync.vsyncData.frameTimelines[0] = {.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID,
+                                               .deadlineTimestamp = deadlineTimestamp,
+                                               .expectedPresentationTime =
+                                                       expectedPresentationTime};
     return event;
 }
 
@@ -186,9 +193,10 @@
     return binder::Status::ok();
 }
 
-binder::Status EventThreadConnection::getLatestVsyncEventData(VsyncEventData* outVsyncEventData) {
+binder::Status EventThreadConnection::getLatestVsyncEventData(
+        ParcelableVsyncEventData* outVsyncEventData) {
     ATRACE_CALL();
-    *outVsyncEventData = mEventThread->getLatestVsyncEventData(this);
+    outVsyncEventData->vsync = mEventThread->getLatestVsyncEventData(this);
     return binder::Status::ok();
 }
 
@@ -338,10 +346,16 @@
 
 VsyncEventData EventThread::getLatestVsyncEventData(
         const sp<EventThreadConnection>& connection) const {
-    nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid);
     VsyncEventData vsyncEventData;
+    nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid);
     vsyncEventData.frameInterval = frameInterval;
-    generateFrameTimeline(vsyncEventData, frameInterval, systemTime(SYSTEM_TIME_MONOTONIC));
+    VSyncSource::VSyncData vsyncData;
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        vsyncData = mVSyncSource->getLatestVSyncData();
+    }
+    generateFrameTimeline(vsyncEventData, frameInterval, systemTime(SYSTEM_TIME_MONOTONIC),
+                          vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp);
     return vsyncEventData;
 }
 
@@ -370,7 +384,7 @@
 
     LOG_FATAL_IF(!mVSyncState);
     mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
-                                       vsyncData.expectedVSyncTimestamp,
+                                       vsyncData.expectedPresentationTime,
                                        vsyncData.deadlineTimestamp));
     mCondition.notify_all();
 }
@@ -518,7 +532,8 @@
                                      const sp<EventThreadConnection>& connection) const {
     const auto throttleVsync = [&] {
         return mThrottleVsyncCallback &&
-                mThrottleVsyncCallback(event.vsync.expectedVSyncTimestamp, connection->mOwnerUid);
+                mThrottleVsyncCallback(event.vsync.vsyncData.preferredExpectedPresentationTime(),
+                                       connection->mOwnerUid);
     };
 
     switch (event.header.type) {
@@ -568,79 +583,49 @@
 }
 
 int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp,
-                                   nsecs_t expectedVSyncTimestamp) const {
+                                   nsecs_t expectedPresentationTime) const {
     if (mTokenManager != nullptr) {
         return mTokenManager->generateTokenForPredictions(
-                {timestamp, deadlineTimestamp, expectedVSyncTimestamp});
+                {timestamp, deadlineTimestamp, expectedPresentationTime});
     }
     return FrameTimelineInfo::INVALID_VSYNC_ID;
 }
 
-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 {
+void EventThread::generateFrameTimeline(VsyncEventData& outVsyncEventData, nsecs_t frameInterval,
+                                        nsecs_t timestamp,
+                                        nsecs_t preferredExpectedPresentationTime,
+                                        nsecs_t preferredDeadlineTimestamp) const {
     // Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included.
     for (int64_t multiplier = -VsyncEventData::kFrameTimelinesLength + 1, currentIndex = 0;
          currentIndex < VsyncEventData::kFrameTimelinesLength; multiplier++) {
-        nsecs_t deadline = preferredDeadlineTimestamp + multiplier * frameInterval;
+        nsecs_t deadlineTimestamp = preferredDeadlineTimestamp + multiplier * frameInterval;
         // Valid possible frame timelines must have future values.
-        if (deadline > timestamp) {
+        if (deadlineTimestamp > timestamp) {
             if (multiplier == 0) {
-                setPreferredFrameTimelineIndex(currentIndex);
+                outVsyncEventData.preferredFrameTimelineIndex = currentIndex;
             }
-            nsecs_t expectedVSyncTimestamp =
-                    preferredExpectedVSyncTimestamp + multiplier * frameInterval;
-            setFrameTimeline(currentIndex,
-                             generateToken(timestamp, deadline, expectedVSyncTimestamp),
-                             expectedVSyncTimestamp, deadline);
+            nsecs_t expectedPresentationTime =
+                    preferredExpectedPresentationTime + multiplier * frameInterval;
+            outVsyncEventData.frameTimelines[currentIndex] =
+                    {.vsyncId =
+                             generateToken(timestamp, deadlineTimestamp, expectedPresentationTime),
+                     .deadlineTimestamp = deadlineTimestamp,
+                     .expectedPresentationTime = expectedPresentationTime};
             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) {
         DisplayEventReceiver::Event copy = event;
         if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
-            copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid);
-            generateFrameTimeline(copy);
+            const int64_t frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid);
+            copy.vsync.vsyncData.frameInterval = frameInterval;
+            generateFrameTimeline(copy.vsync.vsyncData, frameInterval, copy.header.timestamp,
+                                  event.vsync.vsyncData.preferredExpectedPresentationTime(),
+                                  event.vsync.vsyncData.preferredDeadlineTimestamp());
         }
         switch (consumer->postEvent(copy)) {
             case NO_ERROR:
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index a858169..c406478 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -45,6 +45,7 @@
 class TokenManager;
 } // namespace frametimeline
 
+using gui::ParcelableVsyncEventData;
 using gui::VsyncEventData;
 
 // ---------------------------------------------------------------------------
@@ -66,7 +67,7 @@
 public:
     class VSyncData {
     public:
-        nsecs_t expectedVSyncTimestamp;
+        nsecs_t expectedPresentationTime;
         nsecs_t deadlineTimestamp;
     };
 
@@ -99,7 +100,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;
+    binder::Status getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) override;
 
     // Called in response to requestNextVsync.
     const ResyncCallback resyncCallback;
@@ -217,17 +218,10 @@
     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;
+                          nsecs_t expectedPresentationTime) const;
+    void generateFrameTimeline(VsyncEventData& outVsyncEventData, nsecs_t frameInterval,
+                               nsecs_t timestamp, nsecs_t preferredExpectedPresentationTime,
+                               nsecs_t preferredDeadlineTimestamp) 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/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 0efc28b..5f64efa 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -83,8 +83,7 @@
 
 void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) {
     std::lock_guard lock(mLock);
-    LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first !=
-                                LayerHistory::layerStatus::NotFound,
+    LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first != LayerStatus::NotFound,
                         "%s already registered", layer->getName().c_str());
     auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type);
 
@@ -108,9 +107,9 @@
     auto id = layer->getSequence();
 
     auto [found, layerPair] = findLayer(id);
-    if (found == LayerHistory::layerStatus::NotFound) {
+    if (found == LayerStatus::NotFound) {
         // Offscreen layer
-        ALOGV("LayerHistory::record: %s not registered", layer->getName().c_str());
+        ALOGV("%s: %s not registered", __func__, layer->getName().c_str());
         return;
     }
 
@@ -126,16 +125,15 @@
     info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps);
 
     // Activate layer if inactive.
-    if (found == LayerHistory::layerStatus::LayerInInactiveMap) {
+    if (found == LayerStatus::LayerInInactiveMap) {
         mActiveLayerInfos.insert(
                 {id, std::make_pair(layerPair->first, std::move(layerPair->second))});
         mInactiveLayerInfos.erase(id);
     }
 }
 
-LayerHistory::Summary LayerHistory::summarize(const RefreshRateConfigs& refreshRateConfigs,
-                                              nsecs_t now) {
-    LayerHistory::Summary summary;
+auto LayerHistory::summarize(const RefreshRateConfigs& configs, nsecs_t now) -> Summary {
+    Summary summary;
 
     std::lock_guard lock(mLock);
 
@@ -148,9 +146,9 @@
         ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority,
               layerFocused ? "" : "not");
 
-        const auto vote = info->getRefreshRateVote(refreshRateConfigs, now);
+        const auto vote = info->getRefreshRateVote(configs, now);
         // Skip NoVote layer as those don't have any requirements
-        if (vote.type == LayerHistory::LayerVoteType::NoVote) {
+        if (vote.type == LayerVoteType::NoVote) {
             continue;
         }
 
@@ -187,7 +185,7 @@
             it = mInactiveLayerInfos.erase(it);
         } else {
             if (CC_UNLIKELY(mTraceEnabled)) {
-                trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
+                trace(*info, LayerVoteType::NoVote, 0);
             }
             info->onLayerInactive(now);
             it++;
@@ -224,7 +222,7 @@
             it++;
         } else {
             if (CC_UNLIKELY(mTraceEnabled)) {
-                trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
+                trace(*info, LayerVoteType::NoVote, 0);
             }
             info->onLayerInactive(now);
             // move this to the inactive map
@@ -251,37 +249,23 @@
 float LayerHistory::getLayerFramerate(nsecs_t now, int32_t id) const {
     std::lock_guard lock(mLock);
     auto [found, layerPair] = findLayer(id);
-    if (found != LayerHistory::layerStatus::NotFound) {
+    if (found != LayerStatus::NotFound) {
         return layerPair->second->getFps(now).getValue();
     }
     return 0.f;
 }
 
-std::pair<LayerHistory::layerStatus, LayerHistory::LayerPair*> LayerHistory::findLayer(int32_t id) {
+auto LayerHistory::findLayer(int32_t id) -> std::pair<LayerStatus, LayerPair*> {
     // the layer could be in either the active or inactive map, try both
     auto it = mActiveLayerInfos.find(id);
     if (it != mActiveLayerInfos.end()) {
-        return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second));
+        return {LayerStatus::LayerInActiveMap, &(it->second)};
     }
     it = mInactiveLayerInfos.find(id);
     if (it != mInactiveLayerInfos.end()) {
-        return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second));
+        return {LayerStatus::LayerInInactiveMap, &(it->second)};
     }
-    return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr);
-}
-
-std::pair<LayerHistory::layerStatus, const LayerHistory::LayerPair*> LayerHistory::findLayer(
-        int32_t id) const {
-    // the layer could be in either the active or inactive map, try both
-    auto it = mActiveLayerInfos.find(id);
-    if (it != mActiveLayerInfos.end()) {
-        return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second));
-    }
-    it = mInactiveLayerInfos.find(id);
-    if (it != mInactiveLayerInfos.end()) {
-        return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second));
-    }
-    return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr);
+    return {LayerStatus::NotFound, nullptr};
 }
 
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index cc55700..7b6096f 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -89,7 +89,7 @@
     // worst case time complexity is O(2 * inactive + active)
     void partitionLayers(nsecs_t now) REQUIRES(mLock);
 
-    enum class layerStatus {
+    enum class LayerStatus {
         NotFound,
         LayerInActiveMap,
         LayerInInactiveMap,
@@ -97,9 +97,11 @@
 
     // looks up a layer by sequence id in both layerInfo maps.
     // The first element indicates if and where the item was found
-    std::pair<layerStatus, LayerHistory::LayerPair*> findLayer(int32_t id) REQUIRES(mLock);
-    std::pair<layerStatus, const LayerHistory::LayerPair*> findLayer(int32_t id) const
-            REQUIRES(mLock);
+    std::pair<LayerStatus, LayerPair*> findLayer(int32_t id) REQUIRES(mLock);
+
+    std::pair<LayerStatus, const LayerPair*> findLayer(int32_t id) const REQUIRES(mLock) {
+        return const_cast<LayerHistory*>(this)->findLayer(id);
+    }
 
     mutable std::mutex mLock;
 
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index a020e2c..712cd5b 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -191,7 +191,8 @@
         for (int i = 0; i < n; i++) {
             if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
                 auto& vsync = buffer[i].vsync;
-                mHandler->dispatchFrame(vsync.vsyncId, vsync.expectedVSyncTimestamp);
+                mHandler->dispatchFrame(vsync.vsyncData.preferredVsyncId(),
+                                        vsync.vsyncData.preferredExpectedPresentationTime());
                 break;
             }
         }
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 3b9cfa6..15e30b3 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -69,11 +69,6 @@
 using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
 using RefreshRate = RefreshRateConfigs::RefreshRate;
 
-bool RefreshRate::inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const {
-    using fps_approx_ops::operator<=;
-    return minRefreshRate <= getFps() && getFps() <= maxRefreshRate;
-}
-
 std::string RefreshRate::toString() const {
     return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
                               getModeId().value(), mode->getHwcId(), getFps().getValue(),
@@ -84,7 +79,7 @@
     return base::StringPrintf("default mode ID: %d, allowGroupSwitching = %d"
                               ", primary range: %s, app request range: %s",
                               defaultMode.value(), allowGroupSwitching,
-                              primaryRange.toString().c_str(), appRequestRange.toString().c_str());
+                              to_string(primaryRange).c_str(), to_string(appRequestRange).c_str());
 }
 
 std::pair<nsecs_t, nsecs_t> RefreshRateConfigs::getDisplayFrames(nsecs_t layerPeriod,
@@ -207,24 +202,24 @@
     }
 
     if (layer.vote == LayerVoteType::ExplicitExact) {
-        const int divider = getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate);
+        const int divisor = getFrameRateDivisor(refreshRate.getFps(), layer.desiredRefreshRate);
         if (mSupportsFrameRateOverrideByContent) {
             // Since we support frame rate override, allow refresh rates which are
             // multiples of the layer's request, as those apps would be throttled
             // down to run at the desired refresh rate.
-            return divider > 0;
+            return divisor > 0;
         }
 
-        return divider == 1;
+        return divisor == 1;
     }
 
-    // If the layer frame rate is a divider of the refresh rate it should score
+    // If the layer frame rate is a divisor of the refresh rate it should score
     // the highest score.
-    if (getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate) > 0) {
+    if (getFrameRateDivisor(refreshRate.getFps(), layer.desiredRefreshRate) > 0) {
         return 1.0f * seamlessness;
     }
 
-    // The layer frame rate is not a divider of the refresh rate,
+    // The layer frame rate is not a divisor of the refresh rate,
     // there is a small penalty attached to the score to favor the frame rates
     // the exactly matches the display refresh rate or a multiple.
     constexpr float kNonExactMatchingPenalty = 0.95f;
@@ -396,8 +391,9 @@
                 continue;
             }
 
-            bool inPrimaryRange = scores[i].refreshRate->inPolicy(policy->primaryRange.min,
-                                                                  policy->primaryRange.max);
+            const bool inPrimaryRange =
+                    policy->primaryRange.includes(scores[i].refreshRate->getFps());
+
             if ((primaryRangeIsSingleRate || !inPrimaryRange) &&
                 !(layer.focused &&
                   (layer.vote == LayerVoteType::ExplicitDefault ||
@@ -547,11 +543,11 @@
             }
         }
 
-        // We just care about the refresh rates which are a divider of the
+        // We just care about the refresh rates which are a divisor of the
         // display refresh rate
         auto iter =
                 std::remove_if(scores.begin(), scores.end(), [&](const RefreshRateScore& score) {
-                    return getFrameRateDivider(displayFrameRate, score.refreshRate->getFps()) == 0;
+                    return getFrameRateDivisor(displayFrameRate, score.refreshRate->getFps()) == 0;
                 });
         scores.erase(iter, scores.end());
 
@@ -727,7 +723,7 @@
     if (mConfig.enableFrameRateOverride) {
         for (const auto& mode1 : sortedModes) {
             for (const auto& mode2 : sortedModes) {
-                if (getFrameRateDivider(mode1->getFps(), mode2->getFps()) >= 2) {
+                if (getFrameRateDivisor(mode1->getFps(), mode2->getFps()) >= 2) {
                     mSupportsFrameRateOverrideByContent = true;
                     break;
                 }
@@ -746,7 +742,7 @@
         return false;
     }
     const RefreshRate& refreshRate = *iter->second;
-    if (!refreshRate.inPolicy(policy.primaryRange.min, policy.primaryRange.max)) {
+    if (!policy.primaryRange.includes(refreshRate.getFps())) {
         ALOGE("Default mode is not in the primary range.");
         return false;
     }
@@ -843,7 +839,7 @@
     ALOGV("constructAvailableRefreshRates: %s ", policy->toString().c_str());
 
     auto filterRefreshRates =
-            [&](Fps min, Fps max, const char* listName,
+            [&](FpsRange range, const char* rangeName,
                 std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock) {
                 getSortedRefreshRateListLocked(
                         [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
@@ -855,13 +851,13 @@
                                     mode->getDpiY() == defaultMode->getDpiY() &&
                                     (policy->allowGroupSwitching ||
                                      mode->getGroup() == defaultMode->getGroup()) &&
-                                    refreshRate.inPolicy(min, max);
+                                    range.includes(mode->getFps());
                         },
                         outRefreshRates);
 
-                LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(),
-                                    "No matching modes for %s range: min=%s max=%s", listName,
-                                    to_string(min).c_str(), to_string(max).c_str());
+                LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(), "No matching modes for %s range %s",
+                                    rangeName, to_string(range).c_str());
+
                 auto stringifyRefreshRates = [&]() -> std::string {
                     std::string str;
                     for (auto refreshRate : *outRefreshRates) {
@@ -869,13 +865,11 @@
                     }
                     return str;
                 };
-                ALOGV("%s refresh rates: %s", listName, stringifyRefreshRates().c_str());
+                ALOGV("%s refresh rates: %s", rangeName, stringifyRefreshRates().c_str());
             };
 
-    filterRefreshRates(policy->primaryRange.min, policy->primaryRange.max, "primary",
-                       &mPrimaryRefreshRates);
-    filterRefreshRates(policy->appRequestRange.min, policy->appRequestRange.max, "app request",
-                       &mAppRequestRefreshRates);
+    filterRefreshRates(policy->primaryRange, "primary", &mPrimaryRefreshRates);
+    filterRefreshRates(policy->appRequestRange, "app request", &mAppRequestRefreshRates);
 }
 
 Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const {
@@ -921,7 +915,7 @@
     return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
 }
 
-int RefreshRateConfigs::getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate) {
+int RefreshRateConfigs::getFrameRateDivisor(Fps displayFrameRate, Fps layerFrameRate) {
     // This calculation needs to be in sync with the java code
     // in DisplayManagerService.getDisplayInfoForFrameRateOverride
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index ade1787..14583e3 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -22,7 +22,6 @@
 #include <type_traits>
 #include <utility>
 
-#include <android-base/stringprintf.h>
 #include <gui/DisplayEventReceiver.h>
 
 #include <scheduler/Fps.h>
@@ -101,21 +100,6 @@
     using AllRefreshRatesMapType =
             std::unordered_map<DisplayModeId, std::unique_ptr<const RefreshRate>>;
 
-    struct FpsRange {
-        Fps min = Fps::fromValue(0.f);
-        Fps max = Fps::fromValue(std::numeric_limits<float>::max());
-
-        bool operator==(const FpsRange& other) const {
-            return isApproxEqual(min, other.min) && isApproxEqual(max, other.max);
-        }
-
-        bool operator!=(const FpsRange& other) const { return !(*this == other); }
-
-        std::string toString() const {
-            return base::StringPrintf("[%s %s]", to_string(min).c_str(), to_string(max).c_str());
-        }
-    };
-
     struct Policy {
     private:
         static constexpr int kAllowGroupSwitchingDefault = false;
@@ -140,24 +124,24 @@
 
         Policy() = default;
 
-        Policy(DisplayModeId defaultMode, const FpsRange& range)
+        Policy(DisplayModeId defaultMode, FpsRange range)
               : Policy(defaultMode, kAllowGroupSwitchingDefault, range, range) {}
 
-        Policy(DisplayModeId defaultMode, bool allowGroupSwitching, const FpsRange& range)
+        Policy(DisplayModeId defaultMode, bool allowGroupSwitching, FpsRange range)
               : Policy(defaultMode, allowGroupSwitching, range, range) {}
 
-        Policy(DisplayModeId defaultMode, const FpsRange& primaryRange,
-               const FpsRange& appRequestRange)
+        Policy(DisplayModeId defaultMode, FpsRange primaryRange, FpsRange appRequestRange)
               : Policy(defaultMode, kAllowGroupSwitchingDefault, primaryRange, appRequestRange) {}
 
-        Policy(DisplayModeId defaultMode, bool allowGroupSwitching, const FpsRange& primaryRange,
-               const FpsRange& appRequestRange)
+        Policy(DisplayModeId defaultMode, bool allowGroupSwitching, FpsRange primaryRange,
+               FpsRange appRequestRange)
               : defaultMode(defaultMode),
                 allowGroupSwitching(allowGroupSwitching),
                 primaryRange(primaryRange),
                 appRequestRange(appRequestRange) {}
 
         bool operator==(const Policy& other) const {
+            using namespace fps_approx_ops;
             return defaultMode == other.defaultMode && primaryRange == other.primaryRange &&
                     appRequestRange == other.appRequestRange &&
                     allowGroupSwitching == other.allowGroupSwitching;
@@ -332,10 +316,10 @@
 
     bool supportsFrameRateOverrideByContent() const { return mSupportsFrameRateOverrideByContent; }
 
-    // Return the display refresh rate divider to match the layer
+    // Return the display refresh rate divisor to match the layer
     // frame rate, or 0 if the display refresh rate is not a multiple of the
     // layer refresh rate.
-    static int getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate);
+    static int getFrameRateDivisor(Fps displayFrameRate, Fps layerFrameRate);
 
     // Returns if the provided frame rates have a ratio t*1000/1001 or t*1001/1000
     // for an integer t.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index de27bd1..1fa455a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -173,15 +173,15 @@
             return basePeriod;
         }
 
-        const auto divider =
-                scheduler::RefreshRateConfigs::getFrameRateDivider(refreshRateConfigs
+        const auto divisor =
+                scheduler::RefreshRateConfigs::getFrameRateDivisor(refreshRateConfigs
                                                                            ->getCurrentRefreshRate()
                                                                            .getFps(),
                                                                    *frameRate);
-        if (divider <= 1) {
+        if (divisor <= 1) {
             return basePeriod;
         }
-        return basePeriod * divider;
+        return basePeriod * divisor;
     };
 }
 
@@ -263,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;
     {
@@ -531,50 +535,13 @@
 }
 
 void Scheduler::chooseRefreshRateForContent() {
-    {
-        std::scoped_lock lock(mRefreshRateConfigsLock);
-        if (!mRefreshRateConfigs->canSwitch()) return;
-    }
+    const auto configs = holdRefreshRateConfigs();
+    if (!configs->canSwitch()) return;
 
     ATRACE_CALL();
 
-    DisplayModePtr newMode;
-    GlobalSignals consideredSignals;
-
-    bool frameRateChanged;
-    bool frameRateOverridesChanged;
-
-    const auto refreshRateConfigs = holdRefreshRateConfigs();
-    LayerHistory::Summary summary = mLayerHistory.summarize(*refreshRateConfigs, systemTime());
-    {
-        std::lock_guard<std::mutex> lock(mPolicyLock);
-        mPolicy.contentRequirements = std::move(summary);
-
-        std::tie(newMode, consideredSignals) = chooseDisplayMode();
-        frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
-
-        if (mPolicy.mode == newMode) {
-            // We don't need to change the display mode, but we might need to send an event
-            // about a mode change, since it was suppressed due to a previous idleConsidered
-            if (!consideredSignals.idle) {
-                dispatchCachedReportedMode();
-            }
-            frameRateChanged = false;
-        } else {
-            mPolicy.mode = newMode;
-            frameRateChanged = true;
-        }
-    }
-    if (frameRateChanged) {
-        const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId());
-
-        mSchedulerCallback.changeRefreshRate(newRefreshRate,
-                                             consideredSignals.idle ? DisplayModeEvent::None
-                                                                    : DisplayModeEvent::Changed);
-    }
-    if (frameRateOverridesChanged) {
-        mSchedulerCallback.triggerOnFrameRateOverridesChanged();
-    }
+    LayerHistory::Summary summary = mLayerHistory.summarize(*configs, systemTime());
+    applyPolicy(&Policy::contentRequirements, std::move(summary));
 }
 
 void Scheduler::resetIdleTimer() {
@@ -636,7 +603,7 @@
 }
 
 void Scheduler::idleTimerCallback(TimerState state) {
-    handleTimerStateChanged(&mPolicy.idleTimer, state);
+    applyPolicy(&Policy::idleTimer, state);
     ATRACE_INT("ExpiredIdleTimer", static_cast<int>(state));
 }
 
@@ -646,14 +613,14 @@
     // Clear layer history to get fresh FPS detection.
     // NOTE: Instead of checking all the layers, we should be checking the layer
     // that is currently on top. b/142507166 will give us this capability.
-    if (handleTimerStateChanged(&mPolicy.touch, touch)) {
+    if (applyPolicy(&Policy::touch, touch).touch) {
         mLayerHistory.clear();
     }
     ATRACE_INT("TouchState", static_cast<int>(touch));
 }
 
 void Scheduler::displayPowerTimerCallback(TimerState state) {
-    handleTimerStateChanged(&mPolicy.displayPowerTimer, state);
+    applyPolicy(&Policy::displayPowerTimer, state);
     ATRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state));
 }
 
@@ -682,10 +649,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,
@@ -695,8 +662,8 @@
     return false;
 }
 
-template <class T>
-bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
+template <typename S, typename T>
+auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals {
     DisplayModePtr newMode;
     GlobalSignals consideredSignals;
 
@@ -706,15 +673,17 @@
     const auto refreshRateConfigs = holdRefreshRateConfigs();
     {
         std::lock_guard<std::mutex> lock(mPolicyLock);
-        if (*currentState == newState) {
-            return false;
-        }
-        *currentState = newState;
+
+        auto& currentState = mPolicy.*statePtr;
+        if (currentState == newState) return {};
+        currentState = std::forward<T>(newState);
+
         std::tie(newMode, consideredSignals) = chooseDisplayMode();
         frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
+
         if (mPolicy.mode == newMode) {
             // We don't need to change the display mode, but we might need to send an event
-            // about a mode change, since it was suppressed due to a previous idleConsidered
+            // about a mode change, since it was suppressed if previously considered idle.
             if (!consideredSignals.idle) {
                 dispatchCachedReportedMode();
             }
@@ -733,7 +702,7 @@
     if (frameRateOverridesChanged) {
         mSchedulerCallback.triggerOnFrameRateOverridesChanged();
     }
-    return consideredSignals.touch;
+    return consideredSignals;
 }
 
 auto Scheduler::chooseDisplayMode() -> std::pair<DisplayModePtr, GlobalSignals> {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 468c4cc..f6c81c0 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -169,6 +169,7 @@
     // The period is the vsync period from the current display configuration.
     void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
     void resync() EXCLUDES(mRefreshRateConfigsLock);
+    void forceNextResync() { mLastResyncTime = 0; }
 
     // Passes a vsync sample to VsyncController. periodFlushed will be true if
     // VsyncController detected that the vsync period changed, and false otherwise.
@@ -263,14 +264,17 @@
     void touchTimerCallback(TimerState);
     void displayPowerTimerCallback(TimerState);
 
-    // handles various timer features to change the refresh rate.
-    template <class T>
-    bool handleTimerStateChanged(T* currentState, T newState);
-
     void setVsyncPeriod(nsecs_t period);
 
     using GlobalSignals = RefreshRateConfigs::GlobalSignals;
 
+    struct Policy;
+
+    // Sets the S state of the policy to the T value under mPolicyLock, and chooses a display mode
+    // that fulfills the new policy if the state changed. Returns the signals that were considered.
+    template <typename S, typename T>
+    GlobalSignals applyPolicy(S Policy::*, T&&) EXCLUDES(mPolicyLock);
+
     // Returns the display mode that fulfills the policy, and the signals that were considered.
     std::pair<DisplayModePtr, GlobalSignals> chooseDisplayMode() REQUIRES(mPolicyLock);
 
@@ -323,7 +327,7 @@
 
     mutable std::mutex mPolicyLock;
 
-    struct {
+    struct Policy {
         // Policy for choosing the display mode.
         LayerHistory::Summary contentRequirements;
         TimerState idleTimer = TimerState::Reset;
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 61d2fb7..77782e9 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -256,7 +256,7 @@
 
 /*
  * Returns whether a given vsync timestamp is in phase with a frame rate.
- * If the frame rate is not a divider of the refresh rate, it is always considered in phase.
+ * If the frame rate is not a divisor of the refresh rate, it is always considered in phase.
  * For example, if the vsync timestamps are (16.6,33.3,50.0,66.6):
  * isVSyncInPhase(16.6, 30) = true
  * isVSyncInPhase(33.3, 30) = false
@@ -271,42 +271,42 @@
     };
 
     std::lock_guard lock(mMutex);
-    const auto divider =
-            RefreshRateConfigs::getFrameRateDivider(Fps::fromPeriodNsecs(mIdealPeriod), frameRate);
-    if (divider <= 1 || timePoint == 0) {
+    const auto divisor =
+            RefreshRateConfigs::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod), frameRate);
+    if (divisor <= 1 || timePoint == 0) {
         return true;
     }
 
     const nsecs_t period = mRateMap[mIdealPeriod].slope;
     const nsecs_t justBeforeTimePoint = timePoint - period / 2;
-    const nsecs_t dividedPeriod = mIdealPeriod / divider;
+    const nsecs_t dividedPeriod = mIdealPeriod / divisor;
 
-    // If this is the first time we have asked about this divider with the
+    // If this is the first time we have asked about this divisor with the
     // current vsync period, it is considered in phase and we store the closest
     // vsync timestamp
-    const auto knownTimestampIter = mRateDividerKnownTimestampMap.find(dividedPeriod);
-    if (knownTimestampIter == mRateDividerKnownTimestampMap.end()) {
+    const auto knownTimestampIter = mRateDivisorKnownTimestampMap.find(dividedPeriod);
+    if (knownTimestampIter == mRateDivisorKnownTimestampMap.end()) {
         const auto vsync = nextAnticipatedVSyncTimeFromLocked(justBeforeTimePoint);
-        mRateDividerKnownTimestampMap[dividedPeriod] = vsync;
+        mRateDivisorKnownTimestampMap[dividedPeriod] = vsync;
         return true;
     }
 
-    // Find the next N vsync timestamp where N is the divider.
+    // Find the next N vsync timestamp where N is the divisor.
     // One of these vsyncs will be in phase. We return the one which is
     // the most aligned with the last known in phase vsync
-    std::vector<VsyncError> vsyncs(static_cast<size_t>(divider));
+    std::vector<VsyncError> vsyncs(static_cast<size_t>(divisor));
     const nsecs_t knownVsync = knownTimestampIter->second;
     nsecs_t point = justBeforeTimePoint;
-    for (size_t i = 0; i < divider; i++) {
+    for (size_t i = 0; i < divisor; i++) {
         const nsecs_t vsync = nextAnticipatedVSyncTimeFromLocked(point);
-        const auto numPeriods = static_cast<float>(vsync - knownVsync) / (period * divider);
+        const auto numPeriods = static_cast<float>(vsync - knownVsync) / (period * divisor);
         const auto error = std::abs(std::round(numPeriods) - numPeriods);
         vsyncs[i] = {vsync, error};
         point = vsync + 1;
     }
 
     const auto minVsyncError = std::min_element(vsyncs.begin(), vsyncs.end());
-    mRateDividerKnownTimestampMap[dividedPeriod] = minVsyncError->vsyncTimestamp;
+    mRateDivisorKnownTimestampMap[dividedPeriod] = minVsyncError->vsyncTimestamp;
     return std::abs(minVsyncError->vsyncTimestamp - timePoint) < period / 2;
 }
 
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index cfaf7d6..3181102 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -96,7 +96,7 @@
     std::unordered_map<nsecs_t, Model> mutable mRateMap GUARDED_BY(mMutex);
 
     // Map between the divided vsync period and the last known vsync timestamp
-    std::unordered_map<nsecs_t, nsecs_t> mutable mRateDividerKnownTimestampMap GUARDED_BY(mMutex);
+    std::unordered_map<nsecs_t, nsecs_t> mutable mRateDivisorKnownTimestampMap GUARDED_BY(mMutex);
 
     size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0;
     std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex);
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
index 245db0f..be57b2a 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
@@ -134,16 +134,27 @@
     return mVsyncConfig;
 }
 
-const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const {
+auto VsyncModulator::getNextVsyncConfigType() const -> VsyncConfigType {
     // Early offsets are used if we're in the middle of a refresh rate
     // change, or if we recently begin a transaction.
     if (!mEarlyWakeupRequests.empty() || mTransactionSchedule == Schedule::EarlyEnd ||
         mEarlyTransactionFrames > 0 || mRefreshRateChangePending) {
-        return mVsyncConfigSet.early;
+        return VsyncConfigType::Early;
     } else if (mEarlyGpuFrames > 0) {
-        return mVsyncConfigSet.earlyGpu;
+        return VsyncConfigType::EarlyGpu;
     } else {
-        return mVsyncConfigSet.late;
+        return VsyncConfigType::Late;
+    }
+}
+
+const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const {
+    switch (getNextVsyncConfigType()) {
+        case VsyncConfigType::Early:
+            return mVsyncConfigSet.early;
+        case VsyncConfigType::EarlyGpu:
+            return mVsyncConfigSet.earlyGpu;
+        case VsyncConfigType::Late:
+            return mVsyncConfigSet.late;
     }
 }
 
@@ -176,4 +187,9 @@
     static_cast<void>(updateVsyncConfigLocked());
 }
 
+bool VsyncModulator::isVsyncConfigDefault() const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return getNextVsyncConfigType() == VsyncConfigType::Late;
+}
+
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h
index 2000c54..537cae1 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.h
@@ -109,11 +109,16 @@
 
     [[nodiscard]] VsyncConfigOpt onDisplayRefresh(bool usedGpuComposition);
 
+    [[nodiscard]] bool isVsyncConfigDefault() const;
+
 protected:
     // Called from unit tests as well
     void binderDied(const wp<IBinder>&) override EXCLUDES(mMutex);
 
 private:
+    enum class VsyncConfigType { Early, EarlyGpu, Late };
+
+    VsyncConfigType getNextVsyncConfigType() const REQUIRES(mMutex);
     const VsyncConfig& getNextVsyncConfig() const REQUIRES(mMutex);
     [[nodiscard]] VsyncConfig updateVsyncConfig() EXCLUDES(mMutex);
     [[nodiscard]] VsyncConfig updateVsyncConfigLocked() REQUIRES(mMutex);
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
index 639b3e5..bd4f409 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <cmath>
+#include <limits>
 #include <ostream>
 #include <string>
 #include <type_traits>
@@ -60,6 +61,13 @@
     nsecs_t mPeriod = 0;
 };
 
+struct FpsRange {
+    Fps min = Fps::fromValue(0.f);
+    Fps max = Fps::fromValue(std::numeric_limits<float>::max());
+
+    bool includes(Fps) const;
+};
+
 static_assert(std::is_trivially_copyable_v<Fps>);
 
 constexpr Fps operator""_Hz(unsigned long long frequency) {
@@ -111,8 +119,21 @@
     return !isApproxLess(lhs, rhs);
 }
 
+inline bool operator==(FpsRange lhs, FpsRange rhs) {
+    return isApproxEqual(lhs.min, rhs.min) && isApproxEqual(lhs.max, rhs.max);
+}
+
+inline bool operator!=(FpsRange lhs, FpsRange rhs) {
+    return !(lhs == rhs);
+}
+
 } // namespace fps_approx_ops
 
+inline bool FpsRange::includes(Fps fps) const {
+    using fps_approx_ops::operator<=;
+    return min <= fps && fps <= max;
+}
+
 struct FpsApproxEqual {
     bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); }
 };
@@ -125,4 +146,9 @@
     return stream << to_string(fps);
 }
 
+inline std::string to_string(FpsRange range) {
+    const auto [min, max] = range;
+    return base::StringPrintf("[%s, %s]", to_string(min).c_str(), to_string(max).c_str());
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 54a777a..d139d64 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -50,6 +50,7 @@
 #include <cutils/compiler.h>
 #include <cutils/properties.h>
 #include <ftl/future.h>
+#include <ftl/small_map.h>
 #include <gui/BufferQueue.h>
 #include <gui/DebugEGLImageTracker.h>
 #include <gui/IProducerListener.h>
@@ -146,15 +147,16 @@
 
 #define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock)
 
+// Note: The parentheses around `expr` are needed to deduce an lvalue or rvalue reference.
 #define ON_MAIN_THREAD(expr)                                       \
-    [&] {                                                          \
+    [&]() -> decltype(auto) {                                      \
         LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
         UnnecessaryLock lock(mStateLock);                          \
         return (expr);                                             \
     }()
 
 #define MAIN_THREAD_GUARD(expr)                                    \
-    [&] {                                                          \
+    [&]() -> decltype(auto) {                                      \
         LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
         MainThreadScopedGuard lock(SF_MAIN_THREAD);                \
         return (expr);                                             \
@@ -250,11 +252,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;
 
@@ -510,7 +507,7 @@
         return LatchUnsignaledConfig::Always;
     }
 
-    if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, false)) {
+    if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, true)) {
         return LatchUnsignaledConfig::AutoSingleLayer;
     }
 
@@ -1349,9 +1346,8 @@
     auto future = mScheduler->schedule([=]() MAIN_THREAD {
         ATRACE_CALL();
         if (mPowerAdvisor.isUsingExpensiveRendering()) {
-            const auto& displays = ON_MAIN_THREAD(mDisplays);
-            for (const auto& [_, display] : displays) {
-                const static constexpr auto kDisable = false;
+            for (const auto& [_, display] : mDisplays) {
+                constexpr bool kDisable = false;
                 mPowerAdvisor.setExpensiveRenderingExpected(display->getId(), kDisable);
             }
         }
@@ -1744,11 +1740,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);
@@ -1964,8 +1964,8 @@
 }
 
 void SurfaceFlinger::onComposerHalVsyncIdle(hal::HWDisplayId) {
-    // TODO(b/198106220): force enable HWVsync to avoid drift problem during
-    // idle.
+    ATRACE_CALL();
+    mScheduler->forceNextResync();
 }
 
 void SurfaceFlinger::setVsyncEnabled(bool enabled) {
@@ -2351,16 +2351,19 @@
 
 void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats,
                                                 nsecs_t compositeToPresentLatency) {
+    // Avoid division by 0 by defaulting to 60Hz
+    const auto vsyncPeriod = stats.vsyncPeriod ?: (60_Hz).getPeriodNsecs();
+
     // Integer division and modulo round toward 0 not -inf, so we need to
     // treat negative and positive offsets differently.
     nsecs_t idealLatency = (mVsyncConfiguration->getCurrentConfigs().late.sfOffset > 0)
-            ? (stats.vsyncPeriod -
-               (mVsyncConfiguration->getCurrentConfigs().late.sfOffset % stats.vsyncPeriod))
-            : ((-mVsyncConfiguration->getCurrentConfigs().late.sfOffset) % stats.vsyncPeriod);
+            ? (vsyncPeriod -
+               (mVsyncConfiguration->getCurrentConfigs().late.sfOffset % vsyncPeriod))
+            : ((-mVsyncConfiguration->getCurrentConfigs().late.sfOffset) % vsyncPeriod);
 
     // Just in case mVsyncConfiguration->getCurrentConfigs().late.sf == -vsyncInterval.
     if (idealLatency <= 0) {
-        idealLatency = stats.vsyncPeriod;
+        idealLatency = vsyncPeriod;
     }
 
     // Snap the latency to a value that removes scheduling jitter from the
@@ -2369,16 +2372,14 @@
     // something (such as user input) to an accurate diasplay time.
     // Snapping also allows an app to precisely calculate
     // mVsyncConfiguration->getCurrentConfigs().late.sf with (presentLatency % interval).
-    const nsecs_t bias = stats.vsyncPeriod / 2;
-    const int64_t extraVsyncs = (stats.vsyncPeriod) > 0 ?
-        ((compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod) :
-        0;
+    const nsecs_t bias = vsyncPeriod / 2;
+    const int64_t extraVsyncs = ((compositeToPresentLatency - idealLatency + bias) / vsyncPeriod);
     const nsecs_t snappedCompositeToPresentLatency =
-            (extraVsyncs > 0) ? idealLatency + (extraVsyncs * stats.vsyncPeriod) : idealLatency;
+            (extraVsyncs > 0) ? idealLatency + (extraVsyncs * vsyncPeriod) : idealLatency;
 
     std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
     getBE().mCompositorTiming.deadline = stats.vsyncTime - idealLatency;
-    getBE().mCompositorTiming.interval = stats.vsyncPeriod;
+    getBE().mCompositorTiming.interval = vsyncPeriod;
     getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
 }
 
@@ -3243,9 +3244,7 @@
         return;
     }
 
-    const auto& displays = ON_MAIN_THREAD(mDisplays);
-
-    for (const auto& [_, display] : displays) {
+    for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
         if (const auto brightness = display->getStagedBrightness(); brightness) {
             if (!needsComposite) {
                 const status_t error =
@@ -3266,60 +3265,48 @@
 
 void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos,
                                       std::vector<DisplayInfo>& outDisplayInfos) {
-    struct Details {
-        Details(bool receivesInput, bool isSecure, const ui::Transform& transform,
-                const DisplayInfo& info)
-              : receivesInput(receivesInput),
-                isSecure(isSecure),
-                transform(std::move(transform)),
-                info(std::move(info)) {}
-        bool receivesInput;
-        bool isSecure;
-        ui::Transform transform;
-        DisplayInfo info;
-    };
-    std::unordered_map<uint32_t /*layerStackId*/, Details> inputDisplayDetails;
+    ftl::SmallMap<ui::LayerStack, DisplayDevice::InputInfo, 4> displayInputInfos;
+
     for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
-        const uint32_t layerStackId = display->getLayerStack().id;
-        const auto& [info, transform] = display->getInputInfo();
-        const auto& [it, emplaced] =
-                inputDisplayDetails.try_emplace(layerStackId, display->receivesInput(),
-                                                display->isSecure(), transform, info);
+        const auto layerStack = display->getLayerStack();
+        const auto info = display->getInputInfo();
+
+        const auto [it, emplaced] = displayInputInfos.try_emplace(layerStack, info);
         if (emplaced) {
             continue;
         }
 
-        // There is more than one display for the layerStack. In this case, the display that is
-        // configured to receive input takes precedence.
-        auto& details = it->second;
-        if (!display->receivesInput()) {
-            continue;
+        // If the layer stack is mirrored on multiple displays, the first display that is configured
+        // to receive input takes precedence.
+        auto& otherInfo = it->second;
+        if (otherInfo.receivesInput) {
+            ALOGW_IF(display->receivesInput(),
+                     "Multiple displays claim to accept input for the same layer stack: %u",
+                     layerStack.id);
+        } else {
+            otherInfo = info;
         }
-        ALOGE_IF(details.receivesInput,
-                 "Multiple displays claim to accept input for the same layer stack: %u",
-                 layerStackId);
-        details.receivesInput = display->receivesInput();
-        details.isSecure = display->isSecure();
-        details.transform = std::move(transform);
-        details.info = std::move(info);
     }
 
+    static size_t sNumWindowInfos = 0;
+    outWindowInfos.reserve(sNumWindowInfos);
+    sNumWindowInfos = 0;
+
     mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
         if (!layer->needsInputInfo()) return;
 
-        const uint32_t layerStackId = layer->getLayerStack().id;
-        const auto it = inputDisplayDetails.find(layerStackId);
-        if (it == inputDisplayDetails.end()) {
-            // Do not create WindowInfos for windows on displays that cannot receive input.
-            return;
+        // Do not create WindowInfos for windows on displays that cannot receive input.
+        if (const auto opt = displayInputInfos.get(layer->getLayerStack())) {
+            const auto& info = opt->get();
+            outWindowInfos.push_back(layer->fillInputInfo(info.transform, info.isSecure));
         }
-
-        const auto& details = it->second;
-        outWindowInfos.push_back(layer->fillInputInfo(details.transform, details.isSecure));
     });
 
-    for (const auto& [_, details] : inputDisplayDetails) {
-        outDisplayInfos.push_back(std::move(details.info));
+    sNumWindowInfos = outWindowInfos.size();
+
+    outDisplayInfos.reserve(displayInputInfos.size());
+    for (const auto& [_, info] : displayInputInfos) {
+        outDisplayInfos.push_back(info.info);
     }
 }
 
@@ -3667,6 +3654,54 @@
     return false;
 }
 
+void SurfaceFlinger::flushPendingTransactionQueues(
+        std::vector<TransactionState>& transactions,
+        std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent,
+        std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions,
+        bool tryApplyUnsignaled) {
+    auto it = mPendingTransactionQueues.begin();
+    while (it != mPendingTransactionQueues.end()) {
+        auto& [applyToken, transactionQueue] = *it;
+        while (!transactionQueue.empty()) {
+            if (stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) {
+                ATRACE_NAME("stopTransactionProcessing");
+                break;
+            }
+
+            auto& transaction = transactionQueue.front();
+            const auto ready =
+                    transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
+                                                  transaction.isAutoTimestamp,
+                                                  transaction.desiredPresentTime,
+                                                  transaction.originUid, transaction.states,
+                                                  bufferLayersReadyToPresent, transactions.size(),
+                                                  tryApplyUnsignaled);
+            ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
+            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 (transactionQueue.empty()) {
+            it = mPendingTransactionQueues.erase(it);
+            mTransactionQueueCV.broadcast();
+        } else {
+            it = std::next(it, 1);
+        }
+    }
+}
+
 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
@@ -3679,60 +3714,25 @@
         Mutex::Autolock _l(mStateLock);
         {
             Mutex::Autolock _l(mQueueLock);
-            // 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();
-                    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);
-                    }
+            // First collect transactions from the pending transaction queues.
+            // We are not allowing unsignaled buffers here as we want to
+            // collect all the transactions from applyTokens that are ready first.
+            flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
+                                          applyTokensWithUnsignaledTransactions,
+                                          /*tryApplyUnsignaled*/ false);
 
-                    transactions.emplace_back(std::move(transaction));
-                    transactionQueue.pop();
-                }
-
-                if (transactionQueue.empty()) {
-                    it = mPendingTransactionQueues.erase(it);
-                    mTransactionQueueCV.broadcast();
-                } else {
-                    it = std::next(it, 1);
-                }
-            }
-
-            // Collect transactions from current transaction queue or queue to pending transactions.
-            // Case 1: push to pending when transactionIsReadyToBeApplied is false
-            // or the first transaction was unsignaled.
-            // Case 2: push to pending when there exist a pending queue.
-            // Case 3: others are the transactions that are ready to apply.
+            // Second, collect transactions from the transaction queue.
+            // Here as well we are not allowing unsignaled buffers for the same
+            // reason as above.
             while (!mTransactionQueue.empty()) {
                 auto& transaction = mTransactionQueue.front();
                 const bool pendingTransactions =
                         mPendingTransactionQueues.find(transaction.applyToken) !=
                         mPendingTransactionQueues.end();
                 const auto ready = [&]() REQUIRES(mStateLock) {
-                    if (pendingTransactions ||
-                        stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) {
+                    if (pendingTransactions) {
+                        ATRACE_NAME("pendingTransactions");
                         return TransactionReadiness::NotReady;
                     }
 
@@ -3741,25 +3741,31 @@
                                                          transaction.desiredPresentTime,
                                                          transaction.originUid, transaction.states,
                                                          bufferLayersReadyToPresent,
-                                                         transactions.size());
+                                                         transactions.size(),
+                                                         /*tryApplyUnsignaled*/ false);
                 }();
-
+                ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
                 if (ready == TransactionReadiness::NotReady) {
                     mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction));
                 } else {
                     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));
                 }
                 mTransactionQueue.pop_front();
                 ATRACE_INT("TransactionQueue", mTransactionQueue.size());
             }
 
+            // We collected all transactions that could apply without latching unsignaled buffers.
+            // If we are allowing latch unsignaled of some form, now it's the time to go over the
+            // transactions that were not applied and try to apply them unsignaled.
+            if (enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
+                flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
+                                              applyTokensWithUnsignaledTransactions,
+                                              /*tryApplyUnsignaled*/ true);
+            }
+
             return applyTransactions(transactions, vsyncId);
         }
     }
@@ -3818,7 +3824,7 @@
             prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold;
 }
 bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state,
-                                           size_t numStates, size_t totalTXapplied) {
+                                           size_t numStates, size_t totalTXapplied) const {
     if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
         ALOGV("%s: false (LatchUnsignaledConfig::Disabled)", __func__);
         return false;
@@ -3836,11 +3842,22 @@
         return false;
     }
 
-    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer &&
-        totalTXapplied > 0) {
-        ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)", __func__,
-              totalTXapplied);
-        return false;
+    if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) {
+        if (totalTXapplied > 0) {
+            ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)",
+                  __func__, totalTXapplied);
+            return false;
+        }
+
+        // We don't want to latch unsignaled if are in early / client composition
+        // as it leads to jank due to RenderEngine waiting for unsignaled buffer
+        // or window animations being slow.
+        const auto isDefaultVsyncConfig = mVsyncModulator->isVsyncConfigDefault();
+        if (!isDefaultVsyncConfig) {
+            ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; !isDefaultVsyncConfig)",
+                  __func__);
+            return false;
+        }
     }
 
     if (!layer->simpleBufferUpdate(state)) {
@@ -3856,7 +3873,7 @@
         const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
         uid_t originUid, const Vector<ComposerState>& states,
         const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent,
-        size_t totalTXapplied) const -> TransactionReadiness {
+        size_t totalTXapplied, bool tryApplyUnsignaled) const -> TransactionReadiness {
     ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId);
     const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
     // Do not present if the desiredPresentTime has not passed unless it is more than one second
@@ -3893,11 +3910,10 @@
             continue;
         }
 
-        ATRACE_NAME(layer->getName().c_str());
-
-        const bool allowLatchUnsignaled =
+        const bool allowLatchUnsignaled = tryApplyUnsignaled &&
                 shouldLatchUnsignaled(layer, s, states.size(), totalTXapplied);
-        ATRACE_INT("allowLatchUnsignaled", allowLatchUnsignaled);
+        ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(),
+                      allowLatchUnsignaled ? "true" : "false");
 
         const bool acquireFenceChanged = s.bufferData &&
                 s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) &&
@@ -5109,11 +5125,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;
@@ -5154,8 +5168,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);
     }
 }
@@ -5352,7 +5365,7 @@
     colorizer.reset(result);
     const bool hwcDisabled = mDebugDisableHWC || mDebugFlashDelay;
     StringAppendF(&result, "  h/w composer %s\n", hwcDisabled ? "disabled" : "enabled");
-    getHwComposer().dump(result);
+    dumpHwc(result);
 
     /*
      * Dump gralloc state
@@ -5406,30 +5419,21 @@
         // access to SF.
         case BOOT_FINISHED:
         case CLEAR_ANIMATION_FRAME_STATS:
-        case CREATE_DISPLAY:
-        case DESTROY_DISPLAY:
         case GET_ANIMATION_FRAME_STATS:
         case OVERRIDE_HDR_TYPES:
         case GET_HDR_CAPABILITIES:
         case SET_DESIRED_DISPLAY_MODE_SPECS:
         case GET_DESIRED_DISPLAY_MODE_SPECS:
         case SET_ACTIVE_COLOR_MODE:
-        case GET_BOOT_DISPLAY_MODE_SUPPORT:
         case SET_BOOT_DISPLAY_MODE:
-        case CLEAR_BOOT_DISPLAY_MODE:
         case GET_AUTO_LOW_LATENCY_MODE_SUPPORT:
-        case SET_AUTO_LOW_LATENCY_MODE:
         case GET_GAME_CONTENT_TYPE_SUPPORT:
-        case SET_GAME_CONTENT_TYPE:
-        case SET_POWER_MODE:
         case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
         case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
         case GET_DISPLAYED_CONTENT_SAMPLE:
         case ADD_TUNNEL_MODE_ENABLED_LISTENER:
         case REMOVE_TUNNEL_MODE_ENABLED_LISTENER:
-        case NOTIFY_POWER_BOOST:
         case SET_GLOBAL_SHADOW_SETTINGS:
-        case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
         case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
             // OVERRIDE_HDR_TYPES is used by CTS tests, which acquire the necessary
             // permission dynamically. Don't use the permission cache for this check.
@@ -5460,15 +5464,11 @@
         case AUTHENTICATE_SURFACE:
         case GET_ACTIVE_COLOR_MODE:
         case GET_ACTIVE_DISPLAY_MODE:
-        case GET_PHYSICAL_DISPLAY_IDS:
-        case GET_PHYSICAL_DISPLAY_TOKEN:
         case GET_DISPLAY_COLOR_MODES:
         case GET_DISPLAY_NATIVE_PRIMARIES:
         case GET_STATIC_DISPLAY_INFO:
         case GET_DYNAMIC_DISPLAY_INFO:
         case GET_DISPLAY_MODES:
-        case GET_DISPLAY_STATE:
-        case GET_DISPLAY_STATS:
         case GET_SUPPORTED_FRAME_TIMESTAMPS:
         // Calling setTransactionState is safe, because you need to have been
         // granted a reference to Client* and Handle* to do anything with it.
@@ -5477,34 +5477,16 @@
         case GET_COLOR_MANAGEMENT:
         case GET_COMPOSITION_PREFERENCE:
         case GET_PROTECTED_CONTENT_SUPPORT:
-        case IS_WIDE_COLOR_DISPLAY:
         // setFrameRate() is deliberately available for apps to call without any
         // special permissions.
         case SET_FRAME_RATE:
-        case GET_DISPLAY_BRIGHTNESS_SUPPORT:
         case GET_DISPLAY_DECORATION_SUPPORT:
-        // captureLayers and captureDisplay will handle the permission check in the function
-        case CAPTURE_LAYERS:
-        case CAPTURE_DISPLAY:
         case SET_FRAME_TIMELINE_INFO:
         case GET_GPU_CONTEXT_PRIORITY:
         case GET_MAX_ACQUIRED_BUFFER_COUNT: {
             // This is not sensitive information, so should not require permission control.
             return OK;
         }
-        case SET_DISPLAY_BRIGHTNESS:
-        case ADD_HDR_LAYER_INFO_LISTENER:
-        case REMOVE_HDR_LAYER_INFO_LISTENER: {
-            IPCThreadState* ipc = IPCThreadState::self();
-            const int pid = ipc->getCallingPid();
-            const int uid = ipc->getCallingUid();
-            if ((uid != AID_GRAPHICS) &&
-                !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) {
-                ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid);
-                return PERMISSION_DENIED;
-            }
-            return OK;
-        }
         case ADD_FPS_LISTENER:
         case REMOVE_FPS_LISTENER:
         case ADD_REGION_SAMPLING_LISTENER:
@@ -5520,8 +5502,7 @@
             }
             return OK;
         }
-        case ADD_TRANSACTION_TRACE_LISTENER:
-        case CAPTURE_DISPLAY_BY_ID: {
+        case ADD_TRANSACTION_TRACE_LISTENER: {
             IPCThreadState* ipc = IPCThreadState::self();
             const int uid = ipc->getCallingUid();
             if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) {
@@ -5551,6 +5532,29 @@
             }
             return PERMISSION_DENIED;
         }
+        case CREATE_DISPLAY:
+        case DESTROY_DISPLAY:
+        case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
+        case GET_PHYSICAL_DISPLAY_IDS:
+        case GET_PHYSICAL_DISPLAY_TOKEN:
+        case SET_POWER_MODE:
+        case GET_DISPLAY_STATE:
+        case GET_DISPLAY_STATS:
+        case CLEAR_BOOT_DISPLAY_MODE:
+        case GET_BOOT_DISPLAY_MODE_SUPPORT:
+        case SET_AUTO_LOW_LATENCY_MODE:
+        case SET_GAME_CONTENT_TYPE:
+        case CAPTURE_LAYERS:
+        case CAPTURE_DISPLAY:
+        case CAPTURE_DISPLAY_BY_ID:
+        case IS_WIDE_COLOR_DISPLAY:
+        case GET_DISPLAY_BRIGHTNESS_SUPPORT:
+        case SET_DISPLAY_BRIGHTNESS:
+        case ADD_HDR_LAYER_INFO_LISTENER:
+        case REMOVE_HDR_LAYER_INFO_LISTENER:
+        case NOTIFY_POWER_BOOST:
+            LOG_FATAL("Deprecated opcode: %d, migrated to AIDL", code);
+            return PERMISSION_DENIED;
     }
 
     // These codes are used for the IBinder protocol to either interrogate the recipient
@@ -5750,9 +5754,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) {
@@ -5764,6 +5768,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();
@@ -6016,9 +6024,9 @@
                         mTransactionTracing->setBufferSize(
                                 TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE);
                     } else {
+                        mTransactionTracing->writeToFile();
                         mTransactionTracing->setBufferSize(
                                 TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE);
-                        mTransactionTracing->writeToFile();
                     }
                 }
                 reply->writeInt32(NO_ERROR);
@@ -7195,6 +7203,223 @@
     mLayersAdded = true;
     return true;
 }
+
+// gui::ISurfaceComposer
+
+binder::Status SurfaceComposerAIDL::createDisplay(const std::string& displayName, bool secure,
+                                                  sp<IBinder>* outDisplay) {
+    status_t status = checkAccessPermission();
+    if (status != OK) {
+        return binder::Status::fromStatusT(status);
+    }
+    String8 displayName8 = String8::format("%s", displayName.c_str());
+    *outDisplay = mFlinger->createDisplay(displayName8, secure);
+    return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::destroyDisplay(const sp<IBinder>& display) {
+    status_t status = checkAccessPermission();
+    if (status != OK) {
+        return binder::Status::fromStatusT(status);
+    }
+    mFlinger->destroyDisplay(display);
+    return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) {
+    std::vector<PhysicalDisplayId> physicalDisplayIds = mFlinger->getPhysicalDisplayIds();
+    std::vector<int64_t> displayIds;
+    displayIds.reserve(physicalDisplayIds.size());
+    for (auto item : physicalDisplayIds) {
+        displayIds.push_back(static_cast<int64_t>(item.value));
+    }
+    *outDisplayIds = displayIds;
+    return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::getPrimaryPhysicalDisplayId(int64_t* outDisplayId) {
+    status_t status = checkAccessPermission();
+    if (status != OK) {
+        return binder::Status::fromStatusT(status);
+    }
+
+    PhysicalDisplayId id;
+    status = mFlinger->getPrimaryPhysicalDisplayId(&id);
+    if (status == NO_ERROR) {
+        *outDisplayId = id.value;
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId,
+                                                            sp<IBinder>* outDisplay) {
+    const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
+    *outDisplay = mFlinger->getPhysicalDisplayToken(*id);
+    return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::setPowerMode(const sp<IBinder>& display, int mode) {
+    status_t status = checkAccessPermission();
+    if (status != OK) {
+        return binder::Status::fromStatusT(status);
+    }
+    mFlinger->setPowerMode(display, mode);
+    return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayStats(const sp<IBinder>& display,
+                                                    gui::DisplayStatInfo* outStatInfo) {
+    DisplayStatInfo statInfo;
+    status_t status = mFlinger->getDisplayStats(display, &statInfo);
+    if (status == NO_ERROR) {
+        outStatInfo->vsyncTime = static_cast<long>(statInfo.vsyncTime);
+        outStatInfo->vsyncPeriod = static_cast<long>(statInfo.vsyncPeriod);
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayState(const sp<IBinder>& display,
+                                                    gui::DisplayState* outState) {
+    ui::DisplayState state;
+    status_t status = mFlinger->getDisplayState(display, &state);
+    if (status == NO_ERROR) {
+        outState->layerStack = state.layerStack.id;
+        outState->orientation = static_cast<gui::Rotation>(state.orientation);
+        outState->layerStackSpaceRect.width = state.layerStackSpaceRect.width;
+        outState->layerStackSpaceRect.height = state.layerStackSpaceRect.height;
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::clearBootDisplayMode(const sp<IBinder>& display) {
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->clearBootDisplayMode(display);
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getBootDisplayModeSupport(bool* outMode) {
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->getBootDisplayModeSupport(outMode);
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
+    status_t status = checkAccessPermission();
+    if (status != OK) {
+        return binder::Status::fromStatusT(status);
+    }
+    mFlinger->setAutoLowLatencyMode(display, on);
+    return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::setGameContentType(const sp<IBinder>& display, bool on) {
+    status_t status = checkAccessPermission();
+    if (status != OK) {
+        return binder::Status::fromStatusT(status);
+    }
+    mFlinger->setGameContentType(display, on);
+    return binder::Status::ok();
+}
+
+binder::Status SurfaceComposerAIDL::captureDisplay(
+        const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
+    status_t status = mFlinger->captureDisplay(args, captureListener);
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::captureDisplayById(
+        int64_t displayId, const sp<IScreenCaptureListener>& captureListener) {
+    status_t status;
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int uid = ipc->getCallingUid();
+    if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) {
+        std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId));
+        status = mFlinger->captureDisplay(*id, captureListener);
+    } else {
+        status = PERMISSION_DENIED;
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::captureLayers(
+        const LayerCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
+    status_t status = mFlinger->captureLayers(args, captureListener);
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::isWideColorDisplay(const sp<IBinder>& token,
+                                                       bool* outIsWideColorDisplay) {
+    status_t status = mFlinger->isWideColorDisplay(token, outIsWideColorDisplay);
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+                                                                bool* outSupport) {
+    status_t status = mFlinger->getDisplayBrightnessSupport(displayToken, outSupport);
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setDisplayBrightness(const sp<IBinder>& displayToken,
+                                                         const gui::DisplayBrightness& brightness) {
+    status_t status = checkControlDisplayBrightnessPermission();
+    if (status == OK) {
+        status = mFlinger->setDisplayBrightness(displayToken, brightness);
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::addHdrLayerInfoListener(
+        const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
+    status_t status = checkControlDisplayBrightnessPermission();
+    if (status == OK) {
+        status = mFlinger->addHdrLayerInfoListener(displayToken, listener);
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::removeHdrLayerInfoListener(
+        const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) {
+    status_t status = checkControlDisplayBrightnessPermission();
+    if (status == OK) {
+        status = mFlinger->removeHdrLayerInfoListener(displayToken, listener);
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::notifyPowerBoost(int boostId) {
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->notifyPowerBoost(boostId);
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) {
+    if (!mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) {
+        IPCThreadState* ipc = IPCThreadState::self();
+        ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", ipc->getCallingPid(),
+              ipc->getCallingUid());
+        return PERMISSION_DENIED;
+    }
+    return OK;
+}
+
+status_t SurfaceComposerAIDL::checkControlDisplayBrightnessPermission() {
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+    if ((uid != AID_GRAPHICS) &&
+        !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) {
+        ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid);
+        return PERMISSION_DENIED;
+    }
+    return OK;
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9525573..d44acff 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -7,7 +7,6 @@
  *
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
@@ -23,6 +22,9 @@
  */
 
 #include <android-base/thread_annotations.h>
+#include <android/gui/BnSurfaceComposer.h>
+#include <android/gui/DisplayStatInfo.h>
+#include <android/gui/DisplayState.h>
 #include <cutils/atomic.h>
 #include <cutils/compiler.h>
 #include <gui/BufferQueue.h>
@@ -106,9 +108,13 @@
 class RenderArea;
 class TimeStats;
 class FrameTracer;
+class ScreenCapturer;
 class WindowInfosListenerInvoker;
 
+using gui::CaptureArgs;
+using gui::DisplayCaptureArgs;
 using gui::IRegionSamplingListener;
+using gui::LayerCaptureArgs;
 using gui::ScreenCaptureResults;
 
 namespace frametimeline {
@@ -177,6 +183,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,
@@ -507,17 +518,30 @@
     bool callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache = true)
             EXCLUDES(mStateLock);
 
+    // the following two methods are moved from ISurfaceComposer.h
+    // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+    std::optional<PhysicalDisplayId> getInternalDisplayId() const {
+        const auto displayIds = getPhysicalDisplayIds();
+        return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
+    }
+
+    // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+    sp<IBinder> getInternalDisplayToken() const {
+        const auto displayId = getInternalDisplayId();
+        return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+    }
+
     // Implements ISurfaceComposer
     sp<ISurfaceComposerClient> createConnection() override;
-    sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
-    void destroyDisplay(const sp<IBinder>& displayToken) override;
-    std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override EXCLUDES(mStateLock) {
+    sp<IBinder> createDisplay(const String8& displayName, bool secure);
+    void destroyDisplay(const sp<IBinder>& displayToken);
+    std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const EXCLUDES(mStateLock) {
         Mutex::Autolock lock(mStateLock);
         return getPhysicalDisplayIdsLocked();
     }
-    status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override EXCLUDES(mStateLock);
+    status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const EXCLUDES(mStateLock);
 
-    sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
+    sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const;
     status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
                                  const Vector<ComposerState>& state,
                                  const Vector<DisplayState>& displays, uint32_t flags,
@@ -535,13 +559,13 @@
             ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp,
             ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) override;
 
-    status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&) override;
-    status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) override;
-    status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) override;
+    status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&);
+    status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&);
+    status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&);
 
-    status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
+    status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
     status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*)
-            EXCLUDES(mStateLock) override;
+            EXCLUDES(mStateLock);
     status_t getStaticDisplayInfo(const sp<IBinder>& displayToken, ui::StaticDisplayInfo*)
             EXCLUDES(mStateLock) override;
     status_t getDynamicDisplayInfo(const sp<IBinder>& displayToken, ui::DynamicDisplayInfo*)
@@ -549,12 +573,12 @@
     status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
                                        ui::DisplayPrimaries&) override;
     status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
-    status_t getBootDisplayModeSupport(bool* outSupport) const override;
+    status_t getBootDisplayModeSupport(bool* outSupport) const;
     status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id) override;
-    status_t clearBootDisplayMode(const sp<IBinder>& displayToken) override;
-    void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) override;
-    void setGameContentType(const sp<IBinder>& displayToken, bool on) override;
-    void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
+    status_t clearBootDisplayMode(const sp<IBinder>& displayToken);
+    void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on);
+    void setGameContentType(const sp<IBinder>& displayToken, bool on);
+    void setPowerMode(const sp<IBinder>& displayToken, int mode);
     status_t clearAnimationFrameStats() override;
     status_t getAnimationFrameStats(FrameStats* outStats) const override;
     status_t overrideHdrTypes(const sp<IBinder>& displayToken,
@@ -577,8 +601,7 @@
                                        uint64_t timestamp,
                                        DisplayedFrameStats* outStats) const override;
     status_t getProtectedContentSupport(bool* outSupported) const override;
-    status_t isWideColorDisplay(const sp<IBinder>& displayToken,
-                                bool* outIsWideColorDisplay) const override;
+    status_t isWideColorDisplay(const sp<IBinder>& displayToken, bool* outIsWideColorDisplay) const;
     status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
                                        const sp<IRegionSamplingListener>& listener) override;
     status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
@@ -600,15 +623,14 @@
                                         float* outPrimaryRefreshRateMax,
                                         float* outAppRequestRefreshRateMin,
                                         float* outAppRequestRefreshRateMax) override;
-    status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
-                                         bool* outSupport) const override;
+    status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) const;
     status_t setDisplayBrightness(const sp<IBinder>& displayToken,
-                                  const gui::DisplayBrightness& brightness) override;
+                                  const gui::DisplayBrightness& brightness);
     status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken,
-                                     const sp<gui::IHdrLayerInfoListener>& listener) override;
+                                     const sp<gui::IHdrLayerInfoListener>& listener);
     status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken,
-                                        const sp<gui::IHdrLayerInfoListener>& listener) override;
-    status_t notifyPowerBoost(int32_t boostId) override;
+                                        const sp<gui::IHdrLayerInfoListener>& listener);
+    status_t notifyPowerBoost(int32_t boostId);
     status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
                                      float lightPosY, float lightPosZ, float lightRadius) override;
     status_t getDisplayDecorationSupport(
@@ -745,6 +767,12 @@
     // Returns true if there is at least one transaction that needs to be flushed
     bool transactionFlushNeeded();
 
+    void flushPendingTransactionQueues(
+            std::vector<TransactionState>& transactions,
+            std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent,
+            std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions,
+            bool tryApplyUnsignaled) REQUIRES(mStateLock, mQueueLock);
+
     uint32_t setClientStateLocked(const FrameTimelineInfo&, ComposerState&,
                                   int64_t desiredPresentTime, bool isAutoTimestamp,
                                   int64_t postTime, uint32_t permissions) REQUIRES(mStateLock);
@@ -775,10 +803,10 @@
             const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
             uid_t originUid, const Vector<ComposerState>& states,
             const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent,
-            size_t totalTXapplied) const REQUIRES(mStateLock);
+            size_t totalTXapplied, bool tryApplyUnsignaled) const REQUIRES(mStateLock);
     static LatchUnsignaledConfig getLatchUnsignaledConfig();
-    static bool shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t&,
-                                      size_t numStates, size_t totalTXapplied);
+    bool shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t&, size_t numStates,
+                               size_t totalTXapplied) const;
     bool stopTransactionProcessing(const std::unordered_set<sp<IBinder>, SpHash<IBinder>>&
                                            applyTokensWithUnsignaledTransactions) const;
     bool applyTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId)
@@ -1283,6 +1311,7 @@
     ui::Dataspace mDefaultCompositionDataspace;
     ui::Dataspace mWideColorGamutCompositionDataspace;
     ui::Dataspace mColorSpaceAgnosticDataspace;
+    float mDimmingRatio = -1.f;
 
     SurfaceFlingerBE mBE;
     std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
@@ -1395,6 +1424,54 @@
     } mPowerHintSessionData GUARDED_BY(SF_MAIN_THREAD);
 
     nsecs_t mAnimationTransactionTimeout = s2ns(5);
+
+    friend class SurfaceComposerAIDL;
+};
+
+class SurfaceComposerAIDL : public gui::BnSurfaceComposer {
+public:
+    SurfaceComposerAIDL(sp<SurfaceFlinger> sf) { mFlinger = sf; }
+
+    binder::Status createDisplay(const std::string& displayName, bool secure,
+                                 sp<IBinder>* outDisplay) override;
+    binder::Status destroyDisplay(const sp<IBinder>& display) override;
+    binder::Status getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) override;
+    binder::Status getPrimaryPhysicalDisplayId(int64_t* outDisplayId) override;
+    binder::Status getPhysicalDisplayToken(int64_t displayId, sp<IBinder>* outDisplay) override;
+    binder::Status setPowerMode(const sp<IBinder>& display, int mode) override;
+    binder::Status getDisplayStats(const sp<IBinder>& display,
+                                   gui::DisplayStatInfo* outStatInfo) override;
+    binder::Status getDisplayState(const sp<IBinder>& display,
+                                   gui::DisplayState* outState) override;
+    binder::Status clearBootDisplayMode(const sp<IBinder>& display) override;
+    binder::Status getBootDisplayModeSupport(bool* outMode) override;
+    binder::Status setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override;
+    binder::Status setGameContentType(const sp<IBinder>& display, bool on) override;
+    binder::Status captureDisplay(const DisplayCaptureArgs&,
+                                  const sp<IScreenCaptureListener>&) override;
+    binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override;
+    binder::Status captureLayers(const LayerCaptureArgs&,
+                                 const sp<IScreenCaptureListener>&) override;
+    binder::Status isWideColorDisplay(const sp<IBinder>& token,
+                                      bool* outIsWideColorDisplay) override;
+    binder::Status getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+                                               bool* outSupport) override;
+    binder::Status setDisplayBrightness(const sp<IBinder>& displayToken,
+                                        const gui::DisplayBrightness& brightness) override;
+    binder::Status addHdrLayerInfoListener(const sp<IBinder>& displayToken,
+                                           const sp<gui::IHdrLayerInfoListener>& listener) override;
+    binder::Status removeHdrLayerInfoListener(
+            const sp<IBinder>& displayToken,
+            const sp<gui::IHdrLayerInfoListener>& listener) override;
+    binder::Status notifyPowerBoost(int boostId) override;
+
+private:
+    static const constexpr bool kUsePermissionCache = true;
+    status_t checkAccessPermission(bool usePermissionCache = kUsePermissionCache);
+    status_t checkControlDisplayBrightnessPermission();
+
+private:
+    sp<SurfaceFlinger> mFlinger;
 };
 
 } // namespace android
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..4cd5ace 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <gui/SurfaceComposerClient.h>
+#include <ui/Fence.h>
 #include <ui/Rect.h>
 
 #include "LayerProtoHelper.h"
@@ -22,9 +23,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 +32,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 +47,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 +71,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 +137,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 +180,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);
@@ -183,13 +198,16 @@
         if (layer.windowInfoHandle) {
             const gui::WindowInfo* inputInfo = layer.windowInfoHandle->getInfo();
             proto::LayerState_WindowInfo* windowInfoProto = proto.mutable_window_info_handle();
-            windowInfoProto->set_layout_params_flags(inputInfo->flags.get());
-            windowInfoProto->set_layout_params_type(static_cast<int32_t>(inputInfo->type));
+            windowInfoProto->set_layout_params_flags(inputInfo->layoutParamsFlags.get());
+            windowInfoProto->set_layout_params_type(
+                    static_cast<int32_t>(inputInfo->layoutParamsType));
             LayerProtoHelper::writeToProto(inputInfo->touchableRegion,
                                            windowInfoProto->mutable_touchable_region());
             windowInfoProto->set_surface_inset(inputInfo->surfaceInset);
-            windowInfoProto->set_focusable(inputInfo->focusable);
-            windowInfoProto->set_has_wallpaper(inputInfo->hasWallpaper);
+            windowInfoProto->set_focusable(
+                    !inputInfo->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE));
+            windowInfoProto->set_has_wallpaper(inputInfo->inputConfig.test(
+                    gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
             windowInfoProto->set_global_scale_factor(inputInfo->globalScaleFactor);
             proto::LayerState_Transform* transformProto = windowInfoProto->mutable_transform();
             transformProto->set_dsdx(inputInfo->transform.dsdx());
@@ -200,12 +218,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 +266,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 +301,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 +315,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 +337,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 +364,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,13 +424,15 @@
         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();
+        layer.bufferData->acquireFence = Fence::NO_FENCE;
     }
 
     if (proto.what() & layer_state_t::eApiChanged) {
@@ -445,24 +451,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();
     }
@@ -471,13 +477,17 @@
         gui::WindowInfo inputInfo;
         const proto::LayerState_WindowInfo& windowInfoProto = proto.window_info_handle();
 
-        inputInfo.flags = static_cast<gui::WindowInfo::Flag>(windowInfoProto.layout_params_flags());
-        inputInfo.type = static_cast<gui::WindowInfo::Type>(windowInfoProto.layout_params_type());
+        inputInfo.layoutParamsFlags =
+                static_cast<gui::WindowInfo::Flag>(windowInfoProto.layout_params_flags());
+        inputInfo.layoutParamsType =
+                static_cast<gui::WindowInfo::Type>(windowInfoProto.layout_params_type());
         LayerProtoHelper::readFromProto(windowInfoProto.touchable_region(),
                                         inputInfo.touchableRegion);
         inputInfo.surfaceInset = windowInfoProto.surface_inset();
-        inputInfo.focusable = windowInfoProto.focusable();
-        inputInfo.hasWallpaper = windowInfoProto.has_wallpaper();
+        inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE,
+                                 !windowInfoProto.focusable());
+        inputInfo.setInputConfig(gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER,
+                                 windowInfoProto.has_wallpaper());
         inputInfo.globalScaleFactor = windowInfoProto.global_scale_factor();
         const proto::LayerState_Transform& transformProto = windowInfoProto.transform();
         inputInfo.transform.set(transformProto.dsdx(), transformProto.dtdx(), transformProto.dtdy(),
@@ -486,9 +496,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 +542,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/Tracing/tools/Android.bp b/services/surfaceflinger/Tracing/tools/Android.bp
new file mode 100644
index 0000000..e8fe734
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/Android.bp
@@ -0,0 +1,55 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_binary {
+    name: "layertracegenerator",
+    defaults: [
+        "libsurfaceflinger_mocks_defaults",
+        "surfaceflinger_defaults",
+        "skia_renderengine_deps",
+    ],
+    srcs: [
+        ":libsurfaceflinger_sources",
+        ":libsurfaceflinger_mock_sources",
+        ":layertracegenerator_sources",
+        "main.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+    ],
+    header_libs: [
+        "libsurfaceflinger_mocks_headers",
+    ],
+}
+
+filegroup {
+    name: "layertracegenerator_sources",
+    srcs: [
+        "LayerTraceGenerator.cpp",
+    ],
+}
+
+cc_library_headers {
+    name: "layertracegenerator_headers",
+    export_include_dirs: ["."],
+}
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
new file mode 100644
index 0000000..9cbd257
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LayerTraceGenerator"
+
+#include <TestableSurfaceFlinger.h>
+#include <Tracing/TransactionProtoParser.h>
+#include <binder/IPCThreadState.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerState.h>
+#include <log/log.h>
+#include <mock/MockEventThread.h>
+#include <renderengine/ExternalTexture.h>
+#include <renderengine/mock/FakeExternalTexture.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <utils/String16.h>
+#include <string>
+
+#include "LayerTraceGenerator.h"
+
+namespace android {
+
+class Factory final : public surfaceflinger::Factory {
+public:
+    ~Factory() = default;
+
+    std::unique_ptr<HWComposer> createHWComposer(const std::string&) override { return nullptr; }
+
+    std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
+            Fps /*currentRefreshRate*/) override {
+        return std::make_unique<scheduler::FakePhaseOffsets>();
+    }
+
+    sp<SurfaceInterceptor> createSurfaceInterceptor() override {
+        return new android::impl::SurfaceInterceptor();
+    }
+
+    sp<StartPropertySetThread> createStartPropertySetThread(
+            bool /* timestampPropertyValue */) override {
+        return nullptr;
+    }
+
+    sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& /* creationArgs */) override {
+        return nullptr;
+    }
+
+    sp<GraphicBuffer> createGraphicBuffer(uint32_t /* width */, uint32_t /* height */,
+                                          PixelFormat /* format */, uint32_t /* layerCount */,
+                                          uint64_t /* usage */,
+                                          std::string /* requestorName */) override {
+        return nullptr;
+    }
+
+    void createBufferQueue(sp<IGraphicBufferProducer>* /* outProducer */,
+                           sp<IGraphicBufferConsumer>* /* outConsumer */,
+                           bool /* consumerIsSurfaceFlinger */) override {}
+
+    sp<IGraphicBufferProducer> createMonitoredProducer(
+            const sp<IGraphicBufferProducer>& /* producer */,
+            const sp<SurfaceFlinger>& /* flinger */, const wp<Layer>& /* layer */) override {
+        return nullptr;
+    }
+
+    sp<BufferLayerConsumer> createBufferLayerConsumer(
+            const sp<IGraphicBufferConsumer>& /* consumer */,
+            renderengine::RenderEngine& /* renderEngine */, uint32_t /* textureName */,
+            Layer* /* layer */) override {
+        return nullptr;
+    }
+
+    std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
+            const sp<IGraphicBufferProducer>& /* producer */) override {
+        return nullptr;
+    }
+
+    std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override {
+        return compositionengine::impl::createCompositionEngine();
+    }
+
+    sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) {
+        return sp<ContainerLayer>::make(args);
+    }
+
+    sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) {
+        return new BufferStateLayer(args);
+    }
+
+    sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) {
+        return new EffectLayer(args);
+    }
+
+    sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
+        return nullptr;
+    }
+
+    std::unique_ptr<FrameTracer> createFrameTracer() override {
+        return std::make_unique<testing::NiceMock<mock::FrameTracer>>();
+    }
+
+    std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
+            std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid = 0) override {
+        return std::make_unique<testing::NiceMock<mock::FrameTimeline>>(timeStats,
+                                                                        surfaceFlingerPid);
+    }
+};
+
+class MockSurfaceFlinger : public SurfaceFlinger {
+public:
+    MockSurfaceFlinger(Factory& factory)
+          : SurfaceFlinger(factory, SurfaceFlinger::SkipInitialization) {}
+    std::shared_ptr<renderengine::ExternalTexture> getExternalTextureFromBufferData(
+            const BufferData& bufferData, const char* /* layerName */) const override {
+        return std::make_shared<renderengine::mock::FakeExternalTexture>(bufferData.getWidth(),
+                                                                         bufferData.getHeight(),
+                                                                         bufferData.getId(),
+                                                                         bufferData
+                                                                                 .getPixelFormat(),
+                                                                         bufferData.getUsage());
+    };
+
+    // b/220017192 migrate from transact codes to ISurfaceComposer apis
+    void setLayerTracingFlags(int32_t flags) {
+        Parcel data;
+        Parcel reply;
+        data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
+        data.writeInt32(flags);
+        transact(1033, data, &reply, 0 /* flags */);
+    }
+
+    void startLayerTracing(int64_t traceStartTime) {
+        Parcel data;
+        Parcel reply;
+        data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
+        data.writeInt32(1);
+        data.writeInt64(traceStartTime);
+        transact(1025, data, &reply, 0 /* flags */);
+    }
+
+    void stopLayerTracing(const char* tracePath) {
+        Parcel data;
+        Parcel reply;
+        data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
+        data.writeInt32(2);
+        data.writeCString(tracePath);
+        transact(1025, data, &reply, 0 /* flags */);
+    }
+};
+
+class TraceGenFlingerDataMapper : public TransactionProtoParser::FlingerDataMapper {
+public:
+    std::unordered_map<int32_t /*layerId*/, sp<IBinder> /* handle */> mLayerHandles;
+    sp<IBinder> getLayerHandle(int32_t layerId) const override {
+        if (layerId == -1) {
+            ALOGE("Error: Called with layer=%d", layerId);
+            return nullptr;
+        }
+        auto it = mLayerHandles.find(layerId);
+        if (it == mLayerHandles.end()) {
+            ALOGE("Error: Could not find handle for layer=%d", layerId);
+            return nullptr;
+        }
+        return it->second;
+    }
+};
+
+bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile,
+                                   const char* outputLayersTracePath) {
+    if (traceFile.entry_size() == 0) {
+        ALOGD("Trace file is empty");
+        return false;
+    }
+
+    Factory mFactory;
+    sp<MockSurfaceFlinger> flinger = new MockSurfaceFlinger(mFactory);
+    TestableSurfaceFlinger mFlinger(flinger);
+    mFlinger.setupRenderEngine(
+            std::make_unique<testing::NiceMock<renderengine::mock::RenderEngine>>());
+    mock::VsyncController* mVsyncController = new testing::NiceMock<mock::VsyncController>();
+    mock::VSyncTracker* mVSyncTracker = new testing::NiceMock<mock::VSyncTracker>();
+    mock::EventThread* mEventThread = new testing::NiceMock<mock::EventThread>();
+    mock::EventThread* mSFEventThread = new testing::NiceMock<mock::EventThread>();
+    mFlinger.setupScheduler(std::unique_ptr<scheduler::VsyncController>(mVsyncController),
+                            std::unique_ptr<scheduler::VSyncTracker>(mVSyncTracker),
+                            std::unique_ptr<EventThread>(mEventThread),
+                            std::unique_ptr<EventThread>(mSFEventThread),
+                            TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
+                            TestableSurfaceFlinger::kOneDisplayMode, true /* useNiceMock */);
+
+    Hwc2::mock::Composer* mComposer = new testing::NiceMock<Hwc2::mock::Composer>();
+    mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+    mFlinger.mutableMaxRenderTargetSize() = 16384;
+
+    flinger->setLayerTracingFlags(LayerTracing::TRACE_BUFFERS | LayerTracing::TRACE_INPUT |
+                                  LayerTracing::TRACE_BUFFERS);
+    flinger->startLayerTracing(traceFile.entry(0).elapsed_realtime_nanos());
+    std::unique_ptr<TraceGenFlingerDataMapper> mapper =
+            std::make_unique<TraceGenFlingerDataMapper>();
+    TraceGenFlingerDataMapper* dataMapper = mapper.get();
+    TransactionProtoParser parser(std::move(mapper));
+
+    nsecs_t frameTime;
+    int64_t vsyncId;
+    ALOGD("Generating %d transactions...", traceFile.entry_size());
+    for (int i = 0; i < traceFile.entry_size(); i++) {
+        proto::TransactionTraceEntry entry = traceFile.entry(i);
+        ALOGV("    Entry %04d/%04d for time=%" PRId64 " vsyncid=%" PRId64
+              " layers +%d -%d transactions=%d",
+              i, traceFile.entry_size(), entry.elapsed_realtime_nanos(), entry.vsync_id(),
+              entry.added_layers_size(), entry.removed_layers_size(), entry.transactions_size());
+
+        for (int j = 0; j < entry.added_layers_size(); j++) {
+            // create layers
+            TracingLayerCreationArgs tracingArgs;
+            parser.fromProto(entry.added_layers(j), tracingArgs);
+
+            sp<IBinder> outHandle;
+            int32_t outLayerId;
+            LayerCreationArgs args(mFlinger.flinger(), nullptr /* client */, tracingArgs.name,
+                                   tracingArgs.flags, LayerMetadata());
+            args.sequence = std::make_optional<int32_t>(tracingArgs.layerId);
+
+            if (tracingArgs.mirrorFromId == -1) {
+                sp<IBinder> parentHandle = nullptr;
+                if ((tracingArgs.parentId != -1) &&
+                    (dataMapper->mLayerHandles.find(tracingArgs.parentId) ==
+                     dataMapper->mLayerHandles.end())) {
+                    args.addToRoot = false;
+                } else {
+                    parentHandle = dataMapper->getLayerHandle(tracingArgs.parentId);
+                }
+                mFlinger.createLayer(args, &outHandle, parentHandle, &outLayerId,
+                                     nullptr /* parentLayer */, nullptr /* outTransformHint */);
+            } else {
+                sp<IBinder> mirrorFromHandle = dataMapper->getLayerHandle(tracingArgs.mirrorFromId);
+                mFlinger.mirrorLayer(args, mirrorFromHandle, &outHandle, &outLayerId);
+            }
+            LOG_ALWAYS_FATAL_IF(outLayerId != tracingArgs.layerId,
+                                "Could not create layer expected:%d actual:%d", tracingArgs.layerId,
+                                outLayerId);
+            dataMapper->mLayerHandles[tracingArgs.layerId] = outHandle;
+        }
+
+        for (int j = 0; j < entry.transactions_size(); j++) {
+            // apply transactions
+            TransactionState transaction = parser.fromProto(entry.transactions(j));
+            mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
+                                         transaction.displays, transaction.flags,
+                                         transaction.applyToken, transaction.inputWindowCommands,
+                                         transaction.desiredPresentTime,
+                                         transaction.isAutoTimestamp, {},
+                                         transaction.hasListenerCallbacks,
+                                         transaction.listenerCallbacks, transaction.id);
+        }
+
+        for (int j = 0; j < entry.removed_layer_handles_size(); j++) {
+            dataMapper->mLayerHandles.erase(entry.removed_layer_handles(j));
+        }
+
+        frameTime = entry.elapsed_realtime_nanos();
+        vsyncId = entry.vsync_id();
+        mFlinger.commit(frameTime, vsyncId);
+    }
+
+    flinger->stopLayerTracing(outputLayersTracePath);
+    ALOGD("End of generating trace file. File written to %s", outputLayersTracePath);
+    dataMapper->mLayerHandles.clear();
+    return true;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h
similarity index 66%
copy from libs/gui/aidl/android/gui/VsyncEventData.aidl
copy to services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h
index 7343515..ee1ea6c 100644
--- a/libs/gui/aidl/android/gui/VsyncEventData.aidl
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 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,6 +14,13 @@
  * limitations under the License.
  */
 
-package android.gui;
+#pragma once
 
-parcelable VsyncEventData cpp_header "gui/VsyncEventData.h";
+#include <Tracing/TransactionTracing.h>
+
+namespace android {
+class LayerTraceGenerator {
+public:
+    bool generate(const proto::TransactionTraceFile&, const char* outputLayersTracePath);
+};
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Tracing/tools/main.cpp b/services/surfaceflinger/Tracing/tools/main.cpp
new file mode 100644
index 0000000..f3cf42d
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/main.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LayerTraceGenerator"
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include "LayerTraceGenerator.h"
+
+using namespace android;
+
+int main(int argc, char** argv) {
+    if (argc > 3) {
+        std::cout << "Usage: " << argv[0]
+                  << " [transaction-trace-path] [output-layers-trace-path]\n";
+        return -1;
+    }
+
+    const char* transactionTracePath =
+            (argc > 1) ? argv[1] : "/data/misc/wmtrace/transactions_trace.winscope";
+    std::cout << "Parsing " << transactionTracePath << "\n";
+    std::fstream input(transactionTracePath, std::ios::in | std::ios::binary);
+    if (!input) {
+        std::cout << "Error: Could not open " << transactionTracePath;
+        return -1;
+    }
+
+    proto::TransactionTraceFile transactionTraceFile;
+    if (!transactionTraceFile.ParseFromIstream(&input)) {
+        std::cout << "Error: Failed to parse " << transactionTracePath;
+        return -1;
+    }
+
+    const char* outputLayersTracePath =
+            (argc == 3) ? argv[2] : "/data/misc/wmtrace/layers_trace.winscope";
+    ;
+    ALOGD("Generating %s...", outputLayersTracePath);
+    std::cout << "Generating " << outputLayersTracePath << "\n";
+    if (!LayerTraceGenerator().generate(transactionTraceFile, outputLayersTracePath)) {
+        std::cout << "Error: Failed to generate layers trace " << outputLayersTracePath;
+        return -1;
+    }
+    return 0;
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/Tracing/tools/readme.md b/services/surfaceflinger/Tracing/tools/readme.md
new file mode 100644
index 0000000..143c14f
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/readme.md
@@ -0,0 +1,13 @@
+### LayerTraceGenerator ###
+
+Generates layer traces from transaction traces. The tool is a custom
+surface flinger build that mocks out everything else apart from the
+front end logic. Transaction traces are written when the transaction
+is applied, along wth a timestamp and vsync id. The transactions
+are parsed from proto and applied to recreate the layer state. The
+result is then written as a layer trace.
+
+Usage:
+1. build and push to device
+2. run ./layertracegenerator [transaction-trace-path] [output-layers-trace-path]
+
diff --git a/services/surfaceflinger/Tracing/tools/run.sh b/services/surfaceflinger/Tracing/tools/run.sh
new file mode 100644
index 0000000..baa93f1
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/run.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+set -ex
+
+# Build, push and run layertracegenerator
+$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode layertracegenerator
+adb wait-for-device && adb push $OUT/system/bin/layertracegenerator /data/layertracegenerator
+echo "Writing transaction trace to file"
+adb shell service call SurfaceFlinger 1041 i32 0
+adb shell /data/layertracegenerator
+adb pull /data/misc/wmtrace/layers_trace.winscope
\ No newline at end of file
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index 23cd993..30b9d8f 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-#include "WindowInfosListenerInvoker.h"
+#include <ftl/small_vector.h>
 #include <gui/ISurfaceComposer.h>
-#include <unordered_set>
+
 #include "SurfaceFlinger.h"
+#include "WindowInfosListenerInvoker.h"
 
 namespace android {
 
@@ -41,18 +42,17 @@
       : mFlinger(flinger),
         mWindowInfosReportedListener(sp<WindowInfosReportedListener>::make(*this)) {}
 
-void WindowInfosListenerInvoker::addWindowInfosListener(
-        const sp<IWindowInfosListener>& windowInfosListener) {
-    sp<IBinder> asBinder = IInterface::asBinder(windowInfosListener);
-
+void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) {
+    sp<IBinder> asBinder = IInterface::asBinder(listener);
     asBinder->linkToDeath(this);
+
     std::scoped_lock lock(mListenersMutex);
-    mWindowInfosListeners.emplace(asBinder, windowInfosListener);
+    mWindowInfosListeners.try_emplace(asBinder, std::move(listener));
 }
 
 void WindowInfosListenerInvoker::removeWindowInfosListener(
-        const sp<IWindowInfosListener>& windowInfosListener) {
-    sp<IBinder> asBinder = IInterface::asBinder(windowInfosListener);
+        const sp<IWindowInfosListener>& listener) {
+    sp<IBinder> asBinder = IInterface::asBinder(listener);
 
     std::scoped_lock lock(mListenersMutex);
     asBinder->unlinkToDeath(this);
@@ -67,12 +67,11 @@
 void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
                                                     const std::vector<DisplayInfo>& displayInfos,
                                                     bool shouldSync) {
-    std::unordered_set<sp<IWindowInfosListener>, SpHash<IWindowInfosListener>> windowInfosListeners;
-
+    ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;
     {
         std::scoped_lock lock(mListenersMutex);
         for (const auto& [_, listener] : mWindowInfosListeners) {
-            windowInfosListeners.insert(listener);
+            windowInfosListeners.push_back(listener);
         }
     }
 
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index 2eabf48..d8d8d0f 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -20,10 +20,8 @@
 #include <android/gui/IWindowInfosListener.h>
 #include <android/gui/IWindowInfosReportedListener.h>
 #include <binder/IBinder.h>
+#include <ftl/small_map.h>
 #include <utils/Mutex.h>
-#include <unordered_map>
-
-#include "WpHash.h"
 
 namespace android {
 
@@ -33,7 +31,7 @@
 public:
     explicit WindowInfosListenerInvoker(SurfaceFlinger&);
 
-    void addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
+    void addWindowInfosListener(sp<gui::IWindowInfosListener>);
     void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
 
     void windowInfosChanged(const std::vector<gui::WindowInfo>&,
@@ -48,8 +46,11 @@
 
     SurfaceFlinger& mFlinger;
     std::mutex mListenersMutex;
-    std::unordered_map<wp<IBinder>, const sp<gui::IWindowInfosListener>, WpHash>
+
+    static constexpr size_t kStaticCapacity = 3;
+    ftl::SmallMap<wp<IBinder>, const sp<gui::IWindowInfosListener>, kStaticCapacity>
             mWindowInfosListeners GUARDED_BY(mListenersMutex);
+
     sp<gui::IWindowInfosReportedListener> mWindowInfosReportedListener;
     std::atomic<size_t> mCallbacksPending{0};
 };
diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp
index b0d216e..7350e09 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: [
@@ -102,3 +111,29 @@
         "surfaceflinger_scheduler_fuzzer.cpp",
     ],
 }
+
+cc_fuzz {
+    name: "surfaceflinger_layer_fuzzer",
+    defaults: [
+        "surfaceflinger_fuzz_defaults",
+    ],
+    header_libs: [
+        "libgui_headers",
+    ],
+    static_libs: [
+        "librenderengine",
+    ],
+    srcs: [
+        "surfaceflinger_layer_fuzzer.cpp",
+    ],
+}
+
+cc_fuzz {
+    name: "surfaceflinger_frametracer_fuzzer",
+    defaults: [
+        "surfaceflinger_fuzz_defaults",
+    ],
+    srcs: [
+        "surfaceflinger_frametracer_fuzzer.cpp",
+    ],
+}
diff --git a/services/surfaceflinger/fuzzer/README.md b/services/surfaceflinger/fuzzer/README.md
index 6231ca5..7a5f229 100644
--- a/services/surfaceflinger/fuzzer/README.md
+++ b/services/surfaceflinger/fuzzer/README.md
@@ -3,6 +3,8 @@
 + [SurfaceFlinger](#SurfaceFlinger)
 + [DisplayHardware](#DisplayHardware)
 + [Scheduler](#Scheduler)
++ [Layer](#Layer)
++ [FrameTracer](#FrameTracer)
 
 # <a name="SurfaceFlinger"></a> Fuzzer for SurfaceFlinger
 
@@ -70,3 +72,38 @@
   $ adb sync data
   $ adb shell /data/fuzz/arm64/surfaceflinger_scheduler_fuzzer/surfaceflinger_scheduler_fuzzer
 ```
+
+# <a name="Layer"></a> Fuzzer for Layer
+
+Layer supports the following parameters:
+1. Display Connection Types (parameter name: `fakeDisplay`)
+2. State Sets (parameter name: `traverseInZOrder`)
+3. State Subsets (parameter name: `prepareCompositionState`)
+4. Disconnect modes (parameter name: `disconnect`)
+5. Data Spaces (parameter name: `setDataspace`)
+
+You can find the possible values in the fuzzer's source code.
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) surfaceflinger_layer_fuzzer
+```
+2. Run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/surfaceflinger_layer_fuzzer/surfaceflinger_layer_fuzzer
+```
+
+# <a name="FrameTracer"></a> Fuzzer for FrameTracer
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) surfaceflinger_frametracer_fuzzer
+```
+2. To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/surfaceflinger_frametracer_fuzzer/surfaceflinger_frametracer_fuzzer
+```
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp
new file mode 100644
index 0000000..a22a778
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <FrameTracer/FrameTracer.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <perfetto/trace/trace.pb.h>
+
+namespace android::fuzz {
+
+using namespace google::protobuf;
+
+constexpr size_t kMaxStringSize = 100;
+constexpr size_t kMinLayerIds = 1;
+constexpr size_t kMaxLayerIds = 10;
+constexpr int32_t kConfigDuration = 500;
+constexpr int32_t kBufferSize = 1024;
+constexpr int32_t kTimeOffset = 100000;
+
+class FrameTracerFuzzer {
+public:
+    FrameTracerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) {
+        // Fuzzer is single-threaded, so no need to be thread-safe.
+        static bool wasInitialized = false;
+        if (!wasInitialized) {
+            perfetto::TracingInitArgs args;
+            args.backends = perfetto::kInProcessBackend;
+            perfetto::Tracing::Initialize(args);
+            wasInitialized = true;
+        }
+        mFrameTracer = std::make_unique<android::FrameTracer>();
+    }
+    ~FrameTracerFuzzer() { mFrameTracer.reset(); }
+    void process();
+
+private:
+    std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest();
+    void traceTimestamp();
+    std::vector<int32_t> generateLayerIds(size_t numLayerIds);
+    void traceTimestamp(std::vector<int32_t> layerIds, size_t numLayerIds);
+    void traceFence(std::vector<int32_t> layerIds, size_t numLayerIds);
+    std::unique_ptr<android::FrameTracer> mFrameTracer = nullptr;
+    FuzzedDataProvider mFdp;
+    android::FenceToFenceTimeMap mFenceFactory;
+};
+
+std::unique_ptr<perfetto::TracingSession> FrameTracerFuzzer::getTracingSessionForTest() {
+    perfetto::TraceConfig cfg;
+    cfg.set_duration_ms(kConfigDuration);
+    cfg.add_buffers()->set_size_kb(kBufferSize);
+    auto* dsCfg = cfg.add_data_sources()->mutable_config();
+    dsCfg->set_name(android::FrameTracer::kFrameTracerDataSource);
+
+    auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
+    tracingSession->Setup(cfg);
+    return tracingSession;
+}
+
+std::vector<int32_t> FrameTracerFuzzer::generateLayerIds(size_t numLayerIds) {
+    std::vector<int32_t> layerIds;
+    for (size_t i = 0; i < numLayerIds; ++i) {
+        layerIds.push_back(mFdp.ConsumeIntegral<int32_t>());
+    }
+    return layerIds;
+}
+
+void FrameTracerFuzzer::traceTimestamp(std::vector<int32_t> layerIds, size_t numLayerIds) {
+    int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange<size_t>(0, numLayerIds - 1));
+    mFrameTracer->traceTimestamp(layerId, mFdp.ConsumeIntegral<uint64_t>() /*bufferID*/,
+                                 mFdp.ConsumeIntegral<uint64_t>() /*frameNumber*/,
+                                 mFdp.ConsumeIntegral<nsecs_t>() /*timestamp*/,
+                                 android::FrameTracer::FrameEvent::UNSPECIFIED,
+                                 mFdp.ConsumeIntegral<nsecs_t>() /*duration*/);
+}
+
+void FrameTracerFuzzer::traceFence(std::vector<int32_t> layerIds, size_t numLayerIds) {
+    const nsecs_t signalTime = systemTime();
+    const nsecs_t startTime = signalTime + kTimeOffset;
+    auto fence = mFenceFactory.createFenceTimeForTest(android::Fence::NO_FENCE);
+    mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, signalTime);
+    int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange<size_t>(0, numLayerIds - 1));
+    mFrameTracer->traceFence(layerId, mFdp.ConsumeIntegral<uint64_t>() /*bufferID*/,
+                             mFdp.ConsumeIntegral<uint64_t>() /*frameNumber*/, fence,
+                             android::FrameTracer::FrameEvent::ACQUIRE_FENCE, startTime);
+}
+
+void FrameTracerFuzzer::process() {
+    mFrameTracer->registerDataSource();
+
+    auto tracingSession = getTracingSessionForTest();
+    tracingSession->StartBlocking();
+
+    size_t numLayerIds = mFdp.ConsumeIntegralInRange<size_t>(kMinLayerIds, kMaxLayerIds);
+    std::vector<int32_t> layerIds = generateLayerIds(numLayerIds);
+
+    for (auto it = layerIds.begin(); it != layerIds.end(); ++it) {
+        mFrameTracer->traceNewLayer(*it /*layerId*/,
+                                    mFdp.ConsumeRandomLengthString(kMaxStringSize) /*layerName*/);
+    }
+
+    traceTimestamp(layerIds, numLayerIds);
+    traceFence(layerIds, numLayerIds);
+
+    mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, systemTime());
+
+    tracingSession->StopBlocking();
+
+    for (auto it = layerIds.begin(); it != layerIds.end(); ++it) {
+        mFrameTracer->onDestroy(*it);
+    }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FrameTracerFuzzer frameTracerFuzzer(data, size);
+    frameTracerFuzzer.process();
+    return 0;
+}
+
+} // namespace android::fuzz
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index 30a6fbd..afc1abd 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -29,35 +29,6 @@
         LatchUnsignaledConfig::Disabled,
 };
 
-static constexpr ui::PixelFormat kPixelFormats[] = {ui::PixelFormat::RGBA_8888,
-                                                    ui::PixelFormat::RGBX_8888,
-                                                    ui::PixelFormat::RGB_888,
-                                                    ui::PixelFormat::RGB_565,
-                                                    ui::PixelFormat::BGRA_8888,
-                                                    ui::PixelFormat::YCBCR_422_SP,
-                                                    ui::PixelFormat::YCRCB_420_SP,
-                                                    ui::PixelFormat::YCBCR_422_I,
-                                                    ui::PixelFormat::RGBA_FP16,
-                                                    ui::PixelFormat::RAW16,
-                                                    ui::PixelFormat::BLOB,
-                                                    ui::PixelFormat::IMPLEMENTATION_DEFINED,
-                                                    ui::PixelFormat::YCBCR_420_888,
-                                                    ui::PixelFormat::RAW_OPAQUE,
-                                                    ui::PixelFormat::RAW10,
-                                                    ui::PixelFormat::RAW12,
-                                                    ui::PixelFormat::RGBA_1010102,
-                                                    ui::PixelFormat::Y8,
-                                                    ui::PixelFormat::Y16,
-                                                    ui::PixelFormat::YV12,
-                                                    ui::PixelFormat::DEPTH_16,
-                                                    ui::PixelFormat::DEPTH_24,
-                                                    ui::PixelFormat::DEPTH_24_STENCIL_8,
-                                                    ui::PixelFormat::DEPTH_32F,
-                                                    ui::PixelFormat::DEPTH_32F_STENCIL_8,
-                                                    ui::PixelFormat::STENCIL_8,
-                                                    ui::PixelFormat::YCBCR_P010,
-                                                    ui::PixelFormat::HSV_888};
-
 static constexpr ui::Rotation kRotations[] = {ui::Rotation::Rotation0, ui::Rotation::Rotation90,
                                               ui::Rotation::Rotation180, ui::Rotation::Rotation270};
 
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 0a458c2..2fcf856 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -123,6 +123,35 @@
                                                 ui::ColorMode::BT2100_HLG,
                                                 ui::ColorMode::DISPLAY_BT2020};
 
+static constexpr ui::PixelFormat kPixelFormats[] = {ui::PixelFormat::RGBA_8888,
+                                                    ui::PixelFormat::RGBX_8888,
+                                                    ui::PixelFormat::RGB_888,
+                                                    ui::PixelFormat::RGB_565,
+                                                    ui::PixelFormat::BGRA_8888,
+                                                    ui::PixelFormat::YCBCR_422_SP,
+                                                    ui::PixelFormat::YCRCB_420_SP,
+                                                    ui::PixelFormat::YCBCR_422_I,
+                                                    ui::PixelFormat::RGBA_FP16,
+                                                    ui::PixelFormat::RAW16,
+                                                    ui::PixelFormat::BLOB,
+                                                    ui::PixelFormat::IMPLEMENTATION_DEFINED,
+                                                    ui::PixelFormat::YCBCR_420_888,
+                                                    ui::PixelFormat::RAW_OPAQUE,
+                                                    ui::PixelFormat::RAW10,
+                                                    ui::PixelFormat::RAW12,
+                                                    ui::PixelFormat::RGBA_1010102,
+                                                    ui::PixelFormat::Y8,
+                                                    ui::PixelFormat::Y16,
+                                                    ui::PixelFormat::YV12,
+                                                    ui::PixelFormat::DEPTH_16,
+                                                    ui::PixelFormat::DEPTH_24,
+                                                    ui::PixelFormat::DEPTH_24_STENCIL_8,
+                                                    ui::PixelFormat::DEPTH_32F,
+                                                    ui::PixelFormat::DEPTH_32F_STENCIL_8,
+                                                    ui::PixelFormat::STENCIL_8,
+                                                    ui::PixelFormat::YCBCR_P010,
+                                                    ui::PixelFormat::HSV_888};
+
 FloatRect getFuzzedFloatRect(FuzzedDataProvider *fdp) {
     return FloatRect(fdp->ConsumeFloatingPoint<float>() /*left*/,
                      fdp->ConsumeFloatingPoint<float>() /*right*/,
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
new file mode 100644
index 0000000..46d52dd
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <BufferStateLayer.h>
+#include <Client.h>
+#include <DisplayDevice.h>
+#include <EffectLayer.h>
+#include <LayerRejecter.h>
+#include <LayerRenderArea.h>
+#include <MonitoredProducer.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gui/IProducerListener.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/WindowInfo.h>
+#include <renderengine/mock/FakeExternalTexture.h>
+#include <ui/DisplayStatInfo.h>
+
+#include <FuzzableDataspaces.h>
+#include <surfaceflinger_fuzzers_utils.h>
+
+namespace android::fuzzer {
+using namespace renderengine;
+
+constexpr uint16_t kRandomStringLength = 256;
+
+class LayerFuzzer {
+public:
+    LayerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void init();
+    void invokeBufferStateLayer();
+    void invokeEffectLayer();
+    LayerCreationArgs createLayerCreationArgs(TestableSurfaceFlinger* flinger, sp<Client> client);
+    Rect getFuzzedRect();
+    FrameTimelineInfo getFuzzedFrameTimelineInfo();
+
+private:
+    FuzzedDataProvider mFdp;
+};
+
+Rect LayerFuzzer::getFuzzedRect() {
+    return Rect(mFdp.ConsumeIntegral<int32_t>() /*left*/, mFdp.ConsumeIntegral<int32_t>() /*top*/,
+                mFdp.ConsumeIntegral<int32_t>() /*right*/,
+                mFdp.ConsumeIntegral<int32_t>() /*bottom*/);
+}
+
+FrameTimelineInfo LayerFuzzer::getFuzzedFrameTimelineInfo() {
+    return FrameTimelineInfo{.vsyncId = mFdp.ConsumeIntegral<int64_t>(),
+                             .inputEventId = mFdp.ConsumeIntegral<int32_t>()};
+}
+
+LayerCreationArgs LayerFuzzer::createLayerCreationArgs(TestableSurfaceFlinger* flinger,
+                                                       sp<Client> client) {
+    flinger->setupScheduler(std::make_unique<android::mock::VsyncController>(),
+                            std::make_unique<android::mock::VSyncTracker>(),
+                            std::make_unique<android::mock::EventThread>(),
+                            std::make_unique<android::mock::EventThread>());
+
+    return LayerCreationArgs(flinger->flinger(), client,
+                             mFdp.ConsumeRandomLengthString(kRandomStringLength) /*name*/,
+                             mFdp.ConsumeIntegral<uint32_t>() /*flags*/, {} /*metadata*/);
+}
+
+void LayerFuzzer::invokeEffectLayer() {
+    TestableSurfaceFlinger flinger;
+    sp<Client> client = sp<Client>::make(flinger.flinger());
+    const LayerCreationArgs layerCreationArgs = createLayerCreationArgs(&flinger, client);
+    sp<EffectLayer> effectLayer = sp<EffectLayer>::make(layerCreationArgs);
+
+    effectLayer->setColor({(mFdp.ConsumeFloatingPointInRange<float>(0, 255) /*x*/,
+                            mFdp.ConsumeFloatingPointInRange<float>(0, 255) /*y*/,
+                            mFdp.ConsumeFloatingPointInRange<float>(0, 255) /*z*/)});
+    effectLayer->setDataspace(mFdp.PickValueInArray(kDataspaces));
+    sp<EffectLayer> parent = sp<EffectLayer>::make(layerCreationArgs);
+    effectLayer->setChildrenDrawingParent(parent);
+
+    const FrameTimelineInfo frameInfo = getFuzzedFrameTimelineInfo();
+    const int64_t postTime = mFdp.ConsumeIntegral<int64_t>();
+    effectLayer->setFrameTimelineVsyncForBufferTransaction(frameInfo, postTime);
+    effectLayer->setFrameTimelineVsyncForBufferlessTransaction(frameInfo, postTime);
+    auto surfaceFrame = effectLayer->createSurfaceFrameForTransaction(frameInfo, postTime);
+    auto surfaceFrame1 =
+            effectLayer->createSurfaceFrameForBuffer(frameInfo, postTime,
+                                                     mFdp.ConsumeRandomLengthString(
+                                                             kRandomStringLength) /*bufferName*/);
+    effectLayer->addSurfaceFramePresentedForBuffer(surfaceFrame,
+                                                   mFdp.ConsumeIntegral<int64_t>() /*acquireTime*/,
+                                                   mFdp.ConsumeIntegral<int64_t>() /*currentTime*/);
+    effectLayer->addSurfaceFrameDroppedForBuffer(surfaceFrame1);
+
+    parent.clear();
+    client.clear();
+    effectLayer.clear();
+}
+
+void LayerFuzzer::invokeBufferStateLayer() {
+    TestableSurfaceFlinger flinger;
+    sp<Client> client = sp<Client>::make(flinger.flinger());
+    sp<BufferStateLayer> layer =
+            sp<BufferStateLayer>::make(createLayerCreationArgs(&flinger, client));
+    sp<Fence> fence = sp<Fence>::make();
+    const std::shared_ptr<FenceTime> fenceTime = std::make_shared<FenceTime>(fence);
+
+    const CompositorTiming compositor = {mFdp.ConsumeIntegral<int64_t>(),
+                                         mFdp.ConsumeIntegral<int64_t>(),
+                                         mFdp.ConsumeIntegral<int64_t>()};
+    std::packaged_task<renderengine::RenderEngineResult()> renderResult([&] {
+        return renderengine::RenderEngineResult{mFdp.ConsumeIntegral<int32_t>(),
+                                                base::unique_fd(fence->get())};
+    });
+    layer->onLayerDisplayed(renderResult.get_future());
+    layer->releasePendingBuffer(mFdp.ConsumeIntegral<int64_t>());
+    layer->finalizeFrameEventHistory(fenceTime, compositor);
+    layer->onPostComposition(nullptr, fenceTime, fenceTime, compositor);
+    layer->isBufferDue(mFdp.ConsumeIntegral<int64_t>());
+
+    layer->setTransform(mFdp.ConsumeIntegral<uint32_t>());
+    layer->setTransformToDisplayInverse(mFdp.ConsumeBool());
+    layer->setCrop(getFuzzedRect());
+
+    layer->setHdrMetadata(getFuzzedHdrMetadata(&mFdp));
+    layer->setDataspace(mFdp.PickValueInArray(kDataspaces));
+    if (mFdp.ConsumeBool()) {
+        layer->setSurfaceDamageRegion(Region());
+        layer->setTransparentRegionHint(Region());
+    } else {
+        layer->setSurfaceDamageRegion(Region(getFuzzedRect()));
+        layer->setTransparentRegionHint(Region(getFuzzedRect()));
+    }
+    layer->setApi(mFdp.ConsumeIntegral<int32_t>());
+
+    native_handle_t* testHandle = native_handle_create(0, 1);
+    const bool ownsHandle = mFdp.ConsumeBool();
+    sp<NativeHandle> nativeHandle = sp<NativeHandle>::make(testHandle, ownsHandle);
+    layer->setSidebandStream(nativeHandle);
+    layer->addFrameEvent(fence, mFdp.ConsumeIntegral<int64_t>() /*postedTime*/,
+                         mFdp.ConsumeIntegral<int64_t>() /*requestedTime*/);
+    layer->computeSourceBounds(getFuzzedFloatRect(&mFdp));
+
+    layer->fenceHasSignaled();
+    layer->framePresentTimeIsCurrent(mFdp.ConsumeIntegral<int64_t>());
+    layer->onPreComposition(mFdp.ConsumeIntegral<int64_t>());
+    const std::vector<sp<CallbackHandle>> callbacks;
+    layer->setTransactionCompletedListeners(callbacks);
+
+    std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared<
+            renderengine::mock::FakeExternalTexture>(mFdp.ConsumeIntegral<uint32_t>(),
+                                                     mFdp.ConsumeIntegral<uint32_t>(),
+                                                     mFdp.ConsumeIntegral<uint64_t>(),
+                                                     static_cast<android::PixelFormat>(
+                                                             mFdp.PickValueInArray(kPixelFormats)),
+                                                     mFdp.ConsumeIntegral<uint64_t>());
+    layer->setBuffer(texture, {} /*bufferData*/, mFdp.ConsumeIntegral<nsecs_t>() /*postTime*/,
+                     mFdp.ConsumeIntegral<nsecs_t>() /*desiredTime*/,
+                     mFdp.ConsumeBool() /*isAutoTimestamp*/,
+                     {mFdp.ConsumeIntegral<nsecs_t>()} /*dequeue*/, {} /*info*/);
+
+    LayerRenderArea layerArea(*(flinger.flinger()), layer, getFuzzedRect(),
+                              {mFdp.ConsumeIntegral<int32_t>(),
+                               mFdp.ConsumeIntegral<int32_t>()} /*reqSize*/,
+                              mFdp.PickValueInArray(kDataspaces), mFdp.ConsumeBool(),
+                              getFuzzedRect(), mFdp.ConsumeBool());
+    layerArea.render([]() {} /*drawLayers*/);
+
+    if (!ownsHandle) {
+        native_handle_close(testHandle);
+        native_handle_delete(testHandle);
+    }
+    nativeHandle.clear();
+    fence.clear();
+    client.clear();
+    layer.clear();
+}
+
+void LayerFuzzer::init() {
+    invokeBufferStateLayer();
+    invokeEffectLayer();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    LayerFuzzer layerFuzzer(data, size);
+    layerFuzzer.init();
+    return 0;
+}
+
+} // namespace android::fuzzer
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 09ffb02..d504155 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -357,7 +357,7 @@
                                                            mFdp.ConsumeFloatingPoint<float>()),
                                                    Fps::fromValue(
                                                            mFdp.ConsumeFloatingPoint<float>()));
-    RefreshRateConfigs::getFrameRateDivider(Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
+    RefreshRateConfigs::getFrameRateDivisor(Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
                                             Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()));
 
     android::mock::TimeStats timeStats;
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 2e9e659..3598308 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -136,6 +136,8 @@
 
   // Corner radius explicitly set on layer rather than inherited
   float requested_corner_radius = 56;
+
+  RectProto destination_frame = 57;
 }
 
 message PositionProto {
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index caeff4a..ec18054 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -152,6 +152,11 @@
     sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
                    IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
 
+    // publish gui::ISurfaceComposer, the new AIDL interface
+    sp<SurfaceComposerAIDL> composerAIDL = new SurfaceComposerAIDL(flinger);
+    sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false,
+                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
+
     startDisplayService(); // dependency on SF getting registered above
 
     if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) {
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index efcc386..ceddf27 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -26,6 +26,7 @@
     defaults: ["surfaceflinger_defaults"],
     test_suites: ["device-tests"],
     srcs: [
+        "BootDisplayMode_test.cpp",
         "BufferGenerator.cpp",
         "CommonTypes_test.cpp",
         "Credentials_test.cpp",
diff --git a/services/surfaceflinger/tests/BootDisplayMode_test.cpp b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
new file mode 100644
index 0000000..d70908e
--- /dev/null
+++ b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
+#include <chrono>
+
+namespace android {
+
+TEST(BootDisplayModeTest, setBootDisplayMode) {
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    sp<gui::ISurfaceComposer> sf_aidl(ComposerServiceAIDL::getComposerService());
+    auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+    bool bootModeSupport = false;
+    binder::Status status = sf_aidl->getBootDisplayModeSupport(&bootModeSupport);
+    ASSERT_NO_FATAL_FAILURE(status.transactionError());
+    if (bootModeSupport) {
+        ASSERT_EQ(NO_ERROR, sf->setBootDisplayMode(displayToken, 0));
+    }
+}
+
+TEST(BootDisplayModeTest, clearBootDisplayMode) {
+    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
+    auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+    bool bootModeSupport = false;
+    binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport);
+    ASSERT_NO_FATAL_FAILURE(status.transactionError());
+    if (bootModeSupport) {
+        status = sf->clearBootDisplayMode(displayToken);
+        ASSERT_EQ(NO_ERROR, status.transactionError());
+    }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
index 01adbc8..0e54664 100644
--- a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
+++ b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp
@@ -28,23 +28,24 @@
 
 TEST_F(DisplayEventReceiverTest, getLatestVsyncEventData) {
     const nsecs_t now = systemTime();
-    VsyncEventData vsyncEventData;
-    EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.getLatestVsyncEventData(&vsyncEventData));
+    ParcelableVsyncEventData parcelableVsyncEventData;
+    EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.getLatestVsyncEventData(&parcelableVsyncEventData));
 
+    const VsyncEventData& vsyncEventData = parcelableVsyncEventData.vsync;
     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,
+    for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+        EXPECT_NE(FrameTimelineInfo::INVALID_VSYNC_ID, vsyncEventData.frameTimelines[i].vsyncId);
+        EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime,
                   vsyncEventData.frameTimelines[i].deadlineTimestamp)
                 << "Expected vsync timestamp should be greater than deadline";
         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)
+            EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime,
+                      vsyncEventData.frameTimelines[i - 1].expectedPresentationTime)
                     << "Expected vsync timestamp out of order for frame timeline " << i;
         }
     }
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 5c16fee..8a2305b 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -141,11 +141,12 @@
                 continue;
             }
 
-            vsync = {event.vsync.vsyncId, event.vsync.expectedVSyncTimestamp};
+            vsync = {event.vsync.vsyncData.preferredVsyncId(),
+                     event.vsync.vsyncData.preferredExpectedPresentationTime()};
         }
 
         EXPECT_GE(vsync.vsyncId, 1);
-        EXPECT_GT(event.vsync.expectedVSyncTimestamp, systemTime());
+        EXPECT_GT(vsync.expectedPresentTime, systemTime());
 
         return vsync;
     }
diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp
index fa1a5ed..094b0ff 100644
--- a/services/surfaceflinger/tests/LayerState_test.cpp
+++ b/services/surfaceflinger/tests/LayerState_test.cpp
@@ -22,6 +22,8 @@
 #include <gui/LayerState.h>
 
 namespace android {
+using gui::DisplayCaptureArgs;
+using gui::LayerCaptureArgs;
 using gui::ScreenCaptureResults;
 
 namespace test {
@@ -40,11 +42,11 @@
     args.grayscale = true;
 
     Parcel p;
-    args.write(p);
+    args.writeToParcel(&p);
     p.setDataPosition(0);
 
     DisplayCaptureArgs args2;
-    args2.read(p);
+    args2.readFromParcel(&p);
 
     ASSERT_EQ(args.pixelFormat, args2.pixelFormat);
     ASSERT_EQ(args.sourceCrop, args2.sourceCrop);
@@ -71,11 +73,11 @@
     args.grayscale = true;
 
     Parcel p;
-    args.write(p);
+    args.writeToParcel(&p);
     p.setDataPosition(0);
 
     LayerCaptureArgs args2;
-    args2.read(p);
+    args2.readFromParcel(&p);
 
     ASSERT_EQ(args.pixelFormat, args2.pixelFormat);
     ASSERT_EQ(args.sourceCrop, args2.sourceCrop);
diff --git a/services/surfaceflinger/tests/tracing/Android.bp b/services/surfaceflinger/tests/tracing/Android.bp
new file mode 100644
index 0000000..ff3e1c5
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/Android.bp
@@ -0,0 +1,40 @@
+// 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.
+
+cc_test {
+    name: "transactiontrace_testsuite",
+    defaults: [
+        "libsurfaceflinger_mocks_defaults",
+        "surfaceflinger_defaults",
+        "skia_renderengine_deps",
+    ],
+    test_suites: ["device-tests"],
+    sanitize: {
+        address: false,
+    },
+    srcs: [
+        ":libsurfaceflinger_sources",
+        ":libsurfaceflinger_mock_sources",
+        ":layertracegenerator_sources",
+        "TransactionTraceTestSuite.cpp",
+    ],
+    static_libs: [
+        "libc++fs",
+    ],
+    header_libs: [
+        "libsurfaceflinger_mocks_headers",
+        "layertracegenerator_headers",
+    ],
+    data: ["testdata/*"],
+}
diff --git a/services/surfaceflinger/tests/tracing/AndroidTest.xml b/services/surfaceflinger/tests/tracing/AndroidTest.xml
new file mode 100644
index 0000000..c0aeb35
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<configuration description="Config for transactiontrace_testsuite">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push"
+        value="transactiontrace_testsuite->/data/local/tmp/transactiontrace_testsuite" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="transactiontrace_testsuite" />
+    </test>
+</configuration>
diff --git a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp
new file mode 100644
index 0000000..ac4354c
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include <LayerTraceGenerator.h>
+#include <Tracing/TransactionProtoParser.h>
+#include <layerproto/LayerProtoHeader.h>
+#include <log/log.h>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+
+class TransactionTraceTestSuite : public testing::Test,
+                                  public testing::WithParamInterface<std::filesystem::path> {
+public:
+    static std::vector<std::filesystem::path> sTransactionTraces;
+    static constexpr std::string_view sTransactionTracePrefix = "transactions_trace_";
+    static constexpr std::string_view sLayersTracePrefix = "layers_trace_";
+    static constexpr std::string_view sTracePostfix = ".winscope";
+
+    proto::TransactionTraceFile mTransactionTrace;
+    LayersTraceFileProto mExpectedLayersTraceProto;
+    LayersTraceFileProto mActualLayersTraceProto;
+
+protected:
+    void SetUp() override {
+        std::filesystem::path transactionTracePath = GetParam();
+        parseTransactionTraceFromFile(transactionTracePath.c_str(), mTransactionTrace);
+
+        std::string expectedLayersFilename = std::string(sLayersTracePrefix) +
+                transactionTracePath.filename().string().substr(sTransactionTracePrefix.length());
+        std::string expectedLayersTracePath =
+                transactionTracePath.parent_path().string() + "/" + expectedLayersFilename;
+        EXPECT_TRUE(std::filesystem::exists(std::filesystem::path(expectedLayersTracePath)));
+        parseLayersTraceFromFile(expectedLayersTracePath.c_str(), mExpectedLayersTraceProto);
+        TemporaryDir temp_dir;
+        std::string actualLayersTracePath =
+                std::string(temp_dir.path) + "/" + expectedLayersFilename + "_actual";
+
+        EXPECT_TRUE(
+                LayerTraceGenerator().generate(mTransactionTrace, actualLayersTracePath.c_str()))
+                << "Failed to generate layers trace from " << transactionTracePath;
+        EXPECT_TRUE(std::filesystem::exists(std::filesystem::path(actualLayersTracePath)));
+        parseLayersTraceFromFile(actualLayersTracePath.c_str(), mActualLayersTraceProto);
+    }
+
+    void parseTransactionTraceFromFile(const char* transactionTracePath,
+                                       proto::TransactionTraceFile& outProto) {
+        ALOGD("Parsing file %s...", transactionTracePath);
+        std::fstream input(transactionTracePath, std::ios::in | std::ios::binary);
+        EXPECT_TRUE(input) << "Error could not open " << transactionTracePath;
+        EXPECT_TRUE(outProto.ParseFromIstream(&input))
+                << "Failed to parse " << transactionTracePath;
+    }
+
+    void parseLayersTraceFromFile(const char* layersTracePath, LayersTraceFileProto& outProto) {
+        ALOGD("Parsing file %s...", layersTracePath);
+        std::fstream input(layersTracePath, std::ios::in | std::ios::binary);
+        EXPECT_TRUE(input) << "Error could not open " << layersTracePath;
+        EXPECT_TRUE(outProto.ParseFromIstream(&input)) << "Failed to parse " << layersTracePath;
+    }
+};
+
+std::vector<std::filesystem::path> TransactionTraceTestSuite::sTransactionTraces{};
+
+TEST_P(TransactionTraceTestSuite, validateEndState) {
+    ASSERT_GT(mActualLayersTraceProto.entry_size(), 0);
+    ASSERT_GT(mExpectedLayersTraceProto.entry_size(), 0);
+
+    auto expectedLastEntry =
+            mExpectedLayersTraceProto.entry(mExpectedLayersTraceProto.entry_size() - 1);
+    auto actualLastEntry = mActualLayersTraceProto.entry(mActualLayersTraceProto.entry_size() - 1);
+
+    EXPECT_EQ(expectedLastEntry.layers().layers_size(), actualLastEntry.layers().layers_size());
+    for (int i = 0;
+         i < expectedLastEntry.layers().layers_size() && i < actualLastEntry.layers().layers_size();
+         i++) {
+        auto expectedLayer = expectedLastEntry.layers().layers(i);
+        auto actualLayer = actualLastEntry.layers().layers(i);
+        EXPECT_EQ(expectedLayer.id(), actualLayer.id());
+        EXPECT_EQ(expectedLayer.name(), actualLayer.name());
+        EXPECT_EQ(expectedLayer.parent(), actualLayer.parent());
+        EXPECT_EQ(expectedLayer.z(), actualLayer.z());
+        EXPECT_EQ(expectedLayer.curr_frame(), actualLayer.curr_frame());
+        ALOGV("Validating %s[%d] parent=%d z=%d frame=%" PRIu64, expectedLayer.name().c_str(),
+              expectedLayer.id(), expectedLayer.parent(), expectedLayer.z(),
+              expectedLayer.curr_frame());
+    }
+}
+
+std::string PrintToStringParamName(const ::testing::TestParamInfo<std::filesystem::path>& info) {
+    const auto& prefix = android::TransactionTraceTestSuite::sTransactionTracePrefix;
+    const auto& postfix = android::TransactionTraceTestSuite::sTracePostfix;
+
+    const auto& filename = info.param.filename().string();
+    return filename.substr(prefix.length(), filename.length() - prefix.length() - postfix.length());
+}
+
+INSTANTIATE_TEST_CASE_P(TransactionTraceTestSuites, TransactionTraceTestSuite,
+                        testing::ValuesIn(TransactionTraceTestSuite::sTransactionTraces),
+                        PrintToStringParamName);
+
+} // namespace android
+
+int main(int argc, char** argv) {
+    for (const auto& entry : std::filesystem::directory_iterator(
+                 android::base::GetExecutableDirectory() + "/testdata/")) {
+        if (!entry.is_regular_file()) {
+            continue;
+        }
+        const auto& filename = entry.path().filename().string();
+        const auto& prefix = android::TransactionTraceTestSuite::sTransactionTracePrefix;
+        if (filename.compare(0, prefix.length(), prefix)) {
+            continue;
+        }
+        const std::string& path = entry.path().string();
+        const auto& postfix = android::TransactionTraceTestSuite::sTracePostfix;
+        if (path.compare(path.length() - postfix.length(), postfix.length(), postfix)) {
+            continue;
+        }
+        android::TransactionTraceTestSuite::sTransactionTraces.push_back(path);
+    }
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/tracing/readme.md b/services/surfaceflinger/tests/tracing/readme.md
new file mode 100644
index 0000000..3e80a74
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/readme.md
@@ -0,0 +1,20 @@
+### TransactionTrace Testsuite ###
+
+Hassle free way to test and validate whether a sequence of
+transactions will produce the expected front end state(s). Test
+runs through all testdata/transactions_trace_*.winscope files,
+generates layer states and checks if the states match the
+corresponding layer trace in testdata.
+
+
+#### Run Test ####
+`atest transactiontrace_testsuite`
+
+
+#### Workflow ####
+Add transaction traces that resulted in front end bugs along
+with the layer trace after fixing the issue. The layer trace
+can be generated by using the layertracegenerator tool. The
+main goal of this test suite is to add regression tests with
+minimal effort.
+
diff --git a/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope b/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope
new file mode 100644
index 0000000..9e4005c
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/testdata/layers_trace_boot.winscope
Binary files differ
diff --git a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope
new file mode 100644
index 0000000..8356ae7
--- /dev/null
+++ b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_boot.winscope
Binary files differ
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 48f18b9..58cd7ba 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -42,6 +42,7 @@
 cc_test {
     name: "libsurfaceflinger_unittest",
     defaults: [
+        "libsurfaceflinger_mocks_defaults",
         "skia_renderengine_deps",
         "surfaceflinger_defaults",
     ],
@@ -80,6 +81,7 @@
         "FpsReporterTest.cpp",
         "FpsTest.cpp",
         "FramebufferSurfaceTest.cpp",
+        "FrameRateOverrideMappingsTest.cpp",
         "FrameTimelineTest.cpp",
         "GameModeTest.cpp",
         "HWComposerTest.cpp",
@@ -121,6 +123,10 @@
         "VSyncReactorTest.cpp",
         "VsyncConfigurationTest.cpp",
     ],
+}
+
+cc_defaults {
+    name: "libsurfaceflinger_mocks_defaults",
     static_libs: [
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
@@ -192,3 +198,8 @@
         "libsurfaceflinger_headers",
     ],
 }
+
+cc_library_headers {
+    name: "libsurfaceflinger_mocks_headers",
+    export_include_dirs: ["."],
+}
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index 0b6b475..ec27eda 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -229,7 +229,7 @@
         ASSERT_TRUE(callbackData.has_value());
         const auto [when, vsyncData] = callbackData.value();
         EXPECT_EQ(when,
-                  vsyncData.expectedVSyncTimestamp - mWorkDuration.count() -
+                  vsyncData.expectedPresentationTime - mWorkDuration.count() -
                           mReadyDuration.count());
     }
 }
@@ -261,7 +261,7 @@
         ASSERT_TRUE(callbackData.has_value());
         const auto [when, vsyncData] = callbackData.value();
         EXPECT_EQ(when,
-                  vsyncData.expectedVSyncTimestamp - mWorkDuration.count() -
+                  vsyncData.expectedPresentationTime - mWorkDuration.count() -
                           mReadyDuration.count());
     }
 
@@ -283,7 +283,7 @@
         const auto callbackData = mVSyncEventCallRecorder.waitForCall();
         ASSERT_TRUE(callbackData.has_value());
         const auto [when, vsyncData] = callbackData.value();
-        EXPECT_EQ(when, vsyncData.expectedVSyncTimestamp - newDuration.count());
+        EXPECT_EQ(when, vsyncData.expectedPresentationTime - newDuration.count());
     }
 
     EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
@@ -307,9 +307,9 @@
 
     const auto vsyncData = mDispSyncSource->getLatestVSyncData();
     ASSERT_GT(vsyncData.deadlineTimestamp, now);
-    ASSERT_GT(vsyncData.expectedVSyncTimestamp, vsyncData.deadlineTimestamp);
+    ASSERT_GT(vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp);
     EXPECT_EQ(vsyncData.deadlineTimestamp,
-              vsyncData.expectedVSyncTimestamp - vsyncInternalDuration);
+              vsyncData.expectedPresentationTime - vsyncInternalDuration);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index cc0a40f..14d8f98 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -99,7 +99,7 @@
                                               nsecs_t expectedTimestamp, unsigned expectedCount);
     void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
     void expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp,
-                                               nsecs_t preferredDeadline);
+                                               VSyncSource::VSyncData preferredVsyncData);
     void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
                                                 bool expectedConnected);
     void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
@@ -252,40 +252,42 @@
                                          expectedCount);
 }
 
-void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp,
-                                                            nsecs_t preferredDeadline) {
+void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(
+        nsecs_t expectedTimestamp, VSyncSource::VSyncData preferredVsyncData) {
     auto args = mConnectionEventCallRecorder.waitForCall();
     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 < VsyncEventData::kFrameTimelinesLength; i++) {
-        auto prediction =
-                mTokenManager->getPredictionsForToken(event.vsync.frameTimelines[i].vsyncId);
+        auto prediction = mTokenManager->getPredictionsForToken(
+                event.vsync.vsyncData.frameTimelines[i].vsyncId);
         EXPECT_TRUE(prediction.has_value());
-        EXPECT_EQ(prediction.value().endTime, event.vsync.frameTimelines[i].deadlineTimestamp)
+        EXPECT_EQ(prediction.value().endTime,
+                  event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp)
                 << "Deadline timestamp does not match cached value";
         EXPECT_EQ(prediction.value().presentTime,
-                  event.vsync.frameTimelines[i].expectedVSyncTimestamp)
-                << "Expected vsync timestamp does not match cached value";
+                  event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime)
+                << "Expected vsync.vsyncData timestamp does not match cached value";
 
         if (i > 0) {
-            EXPECT_GT(event.vsync.frameTimelines[i].deadlineTimestamp,
-                      event.vsync.frameTimelines[i - 1].deadlineTimestamp)
+            EXPECT_GT(event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp,
+                      event.vsync.vsyncData.frameTimelines[i - 1].deadlineTimestamp)
                     << "Deadline timestamp out of order for frame timeline " << i;
-            EXPECT_GT(event.vsync.frameTimelines[i].expectedVSyncTimestamp,
-                      event.vsync.frameTimelines[i - 1].expectedVSyncTimestamp)
-                    << "Expected vsync timestamp out of order for frame timeline " << i;
+            EXPECT_GT(event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime,
+                      event.vsync.vsyncData.frameTimelines[i - 1].expectedPresentationTime)
+                    << "Expected vsync.vsyncData timestamp out of order for frame timeline " << i;
         }
 
         // Vsync ID order lines up with registration into test token manager.
-        EXPECT_EQ(i, event.vsync.frameTimelines[i].vsyncId)
+        EXPECT_EQ(i, event.vsync.vsyncData.frameTimelines[i].vsyncId)
                 << "Vsync ID incorrect for frame timeline " << i;
-        if (i == event.vsync.preferredFrameTimelineIndex) {
-            EXPECT_EQ(event.vsync.frameTimelines[i].deadlineTimestamp, preferredDeadline)
+        if (i == event.vsync.vsyncData.preferredFrameTimelineIndex) {
+            EXPECT_EQ(event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp,
+                      preferredVsyncData.deadlineTimestamp)
                     << "Preferred deadline timestamp incorrect" << i;
-            EXPECT_EQ(event.vsync.frameTimelines[i].expectedVSyncTimestamp,
-                      event.vsync.expectedVSyncTimestamp)
-                    << "Preferred expected vsync timestamp incorrect" << i;
+            EXPECT_EQ(event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime,
+                      preferredVsyncData.expectedPresentationTime)
+                    << "Preferred expected vsync.vsyncData timestamp incorrect" << i;
         }
     }
 }
@@ -397,16 +399,17 @@
 
     // 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});
+    VSyncSource::VSyncData vsyncData = {456, 789};
+    mCallback->onVSyncEvent(123, vsyncData);
     expectInterceptCallReceived(123);
-    expectVsyncEventFrameTimelinesCorrect(123, 789);
+    expectVsyncEventFrameTimelinesCorrect(123, vsyncData);
 }
 
 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,
+    const nsecs_t preferredExpectedPresentationTime = now + 20000000;
+    const VSyncSource::VSyncData preferredData = {preferredExpectedPresentationTime,
                                                   preferredDeadline};
     EXPECT_CALL(*mVSyncSource, getLatestVSyncData()).WillOnce(Return(preferredData));
 
@@ -415,14 +418,14 @@
             << "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);
+                mTokenManager->getPredictionsForToken(vsyncEventData.frameTimelines[i].vsyncId);
         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)
+                  vsyncEventData.frameTimelines[i].expectedPresentationTime)
                 << "Expected vsync timestamp does not match cached value";
-        EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime,
+        EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime,
                   vsyncEventData.frameTimelines[i].deadlineTimestamp)
                 << "Expected vsync timestamp should be greater than deadline";
 
@@ -430,19 +433,19 @@
             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)
+            EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime,
+                      vsyncEventData.frameTimelines[i - 1].expectedPresentationTime)
                     << "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)
+        EXPECT_EQ(i, vsyncEventData.frameTimelines[i].vsyncId)
                 << "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)
+            EXPECT_EQ(vsyncEventData.frameTimelines[i].expectedPresentationTime,
+                      preferredExpectedPresentationTime)
                     << "Preferred expected vsync timestamp incorrect" << i;
         }
     }
diff --git a/services/surfaceflinger/tests/unittests/FpsTest.cpp b/services/surfaceflinger/tests/unittests/FpsTest.cpp
index 88b74d2..2193c9d 100644
--- a/services/surfaceflinger/tests/unittests/FpsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FpsTest.cpp
@@ -68,4 +68,14 @@
     EXPECT_EQ(31, (30.5_Hz).getIntValue());
 }
 
+TEST(FpsTest, range) {
+    const auto fps = Fps::fromPeriodNsecs(16'666'665);
+
+    EXPECT_TRUE((FpsRange{60.000004_Hz, 60.000004_Hz}.includes(fps)));
+    EXPECT_TRUE((FpsRange{59_Hz, 60.1_Hz}.includes(fps)));
+    EXPECT_FALSE((FpsRange{75_Hz, 90_Hz}.includes(fps)));
+    EXPECT_FALSE((FpsRange{60.0011_Hz, 90_Hz}.includes(fps)));
+    EXPECT_FALSE((FpsRange{50_Hz, 59.998_Hz}.includes(fps)));
+}
+
 } // namespace android
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/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 397c619..834a560 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -1279,7 +1279,7 @@
     validateTraceEvent(actualSurfaceFrameEnd2, protoPresentedSurfaceFrameActualEnd);
 }
 
-TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpectedTimeline) {
+TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredIsAppMissedDeadline) {
     auto tracingSession = getTracingSessionForTest();
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
@@ -1312,7 +1312,7 @@
             createProtoActualSurfaceFrameStart(traceCookie + 1, surfaceFrameToken,
                                                displayFrameToken, sPidOne, sLayerNameOne,
                                                FrameTimelineEvent::PRESENT_UNSPECIFIED, false,
-                                               false, FrameTimelineEvent::JANK_UNKNOWN,
+                                               false, FrameTimelineEvent::JANK_APP_DEADLINE_MISSED,
                                                FrameTimelineEvent::PREDICTION_EXPIRED, true);
     auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1);
 
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index cdb2240..e108bea 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -97,7 +97,7 @@
     void setDefaultLayerVote(Layer* layer,
                              LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS {
         auto [found, layerPair] = history().findLayer(layer->getSequence());
-        if (found != LayerHistory::layerStatus::NotFound) {
+        if (found != LayerHistory::LayerStatus::NotFound) {
             layerPair->second->setDefaultLayerVote(vote);
         }
     }
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 4efcc05..97f3747 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -834,17 +834,6 @@
     EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers));
 }
 
-TEST_F(RefreshRateConfigsTest, testInPolicy) {
-    const auto refreshRate =
-            asRefreshRate(createDisplayMode(kModeId60, Fps::fromPeriodNsecs(16'666'665)));
-
-    EXPECT_TRUE(refreshRate.inPolicy(60.000004_Hz, 60.000004_Hz));
-    EXPECT_TRUE(refreshRate.inPolicy(59_Hz, 60.1_Hz));
-    EXPECT_FALSE(refreshRate.inPolicy(75_Hz, 90_Hz));
-    EXPECT_FALSE(refreshRate.inPolicy(60.0011_Hz, 90_Hz));
-    EXPECT_FALSE(refreshRate.inPolicy(50_Hz, 59.998_Hz));
-}
-
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) {
     TestableRefreshRateConfigs configs(kModes_60_90, kModeId60);
 
@@ -1884,37 +1873,37 @@
     EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction());
 }
 
-TEST_F(RefreshRateConfigsTest, getFrameRateDivider) {
+TEST_F(RefreshRateConfigsTest, getFrameRateDivisor) {
     RefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId30);
 
     const auto frameRate = 30_Hz;
     Fps displayRefreshRate = configs.getCurrentRefreshRate().getFps();
-    EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+    EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
 
     configs.setCurrentModeId(kModeId60);
     displayRefreshRate = configs.getCurrentRefreshRate().getFps();
-    EXPECT_EQ(2, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+    EXPECT_EQ(2, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
 
     configs.setCurrentModeId(kModeId72);
     displayRefreshRate = configs.getCurrentRefreshRate().getFps();
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
 
     configs.setCurrentModeId(kModeId90);
     displayRefreshRate = configs.getCurrentRefreshRate().getFps();
-    EXPECT_EQ(3, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+    EXPECT_EQ(3, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
 
     configs.setCurrentModeId(kModeId120);
     displayRefreshRate = configs.getCurrentRefreshRate().getFps();
-    EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+    EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
 
     configs.setCurrentModeId(kModeId90);
     displayRefreshRate = configs.getCurrentRefreshRate().getFps();
-    EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, 22.5_Hz));
+    EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, 22.5_Hz));
 
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(24_Hz, 25_Hz));
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(24_Hz, 23.976_Hz));
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(30_Hz, 29.97_Hz));
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(60_Hz, 59.94_Hz));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(24_Hz, 25_Hz));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(24_Hz, 23.976_Hz));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(30_Hz, 29.97_Hz));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(60_Hz, 59.94_Hz));
 }
 
 TEST_F(RefreshRateConfigsTest, isFractionalPairOrMultiple) {
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index f48abb7..a992a91 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -228,7 +228,8 @@
     mScheduler->setRefreshRateConfigs(
             std::make_shared<RefreshRateConfigs>(DisplayModes{mode60, mode120}, mode60->getId()));
 
-    sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+    const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
+    EXPECT_CALL(*layer, isVisible()).WillOnce(Return(true));
 
     mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
 
@@ -240,6 +241,10 @@
 
     EXPECT_CALL(mSchedulerCallback, changeRefreshRate(Is120Hz(), _)).Times(1);
     mScheduler->chooseRefreshRateForContent();
+
+    // No-op if layer requirements have not changed.
+    EXPECT_CALL(mSchedulerCallback, changeRefreshRate(_, _)).Times(0);
+    mScheduler->chooseRefreshRateForContent();
 }
 
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 8cadb31..d83b9bb 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -177,8 +177,10 @@
 public:
     using HotplugEvent = SurfaceFlinger::HotplugEvent;
 
-    TestableSurfaceFlinger()
-          : mFlinger(sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization)) {
+    TestableSurfaceFlinger(sp<SurfaceFlinger> flinger = nullptr) : mFlinger(flinger) {
+        if (!mFlinger) {
+            mFlinger = sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization);
+        }
         mFlinger->mAnimationTransactionTimeout = ms2ns(10);
     }
 
@@ -219,7 +221,8 @@
                         std::unique_ptr<EventThread> appEventThread,
                         std::unique_ptr<EventThread> sfEventThread,
                         SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp,
-                        DisplayModesVariant modesVariant = kOneDisplayMode) {
+                        DisplayModesVariant modesVariant = kOneDisplayMode,
+                        bool useNiceMock = false) {
         RefreshRateConfigsPtr configs;
         if (std::holds_alternative<RefreshRateConfigsPtr>(modesVariant)) {
             configs = std::move(std::get<RefreshRateConfigsPtr>(modesVariant));
@@ -256,9 +259,17 @@
                 ? static_cast<Callback&>(mNoOpSchedulerCallback)
                 : static_cast<Callback&>(mSchedulerCallback);
 
-        mScheduler = new scheduler::TestableScheduler(std::move(vsyncController),
-                                                      std::move(vsyncTracker), std::move(configs),
-                                                      callback);
+        if (useNiceMock) {
+            mScheduler =
+                    new testing::NiceMock<scheduler::TestableScheduler>(std::move(vsyncController),
+                                                                        std::move(vsyncTracker),
+                                                                        std::move(configs),
+                                                                        callback);
+        } else {
+            mScheduler = new scheduler::TestableScheduler(std::move(vsyncController),
+                                                          std::move(vsyncTracker),
+                                                          std::move(configs), callback);
+        }
 
         mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
         mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
@@ -270,6 +281,8 @@
     scheduler::TestableScheduler& mutableScheduler() { return *mScheduler; }
     scheduler::mock::SchedulerCallback& mockSchedulerCallback() { return mSchedulerCallback; }
 
+    auto& mutableVsyncModulator() { return mFlinger->mVsyncModulator; }
+
     using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
     void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
         mFactory.mCreateBufferQueue = f;
@@ -453,6 +466,23 @@
         mFlinger->onActiveDisplayChangedLocked(activeDisplay);
     }
 
+    auto commit(nsecs_t frameTime, int64_t vsyncId) {
+        const nsecs_t expectedVsyncTime = frameTime + 10'000'000;
+        mFlinger->commit(frameTime, vsyncId, expectedVsyncTime);
+    }
+
+    auto createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
+                     const sp<IBinder>& parentHandle, int32_t* outLayerId,
+                     const sp<Layer>& parentLayer, uint32_t* outTransformHint) {
+        return mFlinger->createLayer(args, outHandle, parentHandle, outLayerId, parentLayer,
+                                     outTransformHint);
+    }
+
+    auto mirrorLayer(const LayerCreationArgs& args, const sp<IBinder>& mirrorFromHandle,
+                     sp<IBinder>* outHandle, int32_t* outLayerId) {
+        return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId);
+    }
+
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */
@@ -848,8 +878,7 @@
 
 private:
     surfaceflinger::test::Factory mFactory;
-    sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
-
+    sp<SurfaceFlinger> mFlinger;
     scheduler::mock::SchedulerCallback mSchedulerCallback;
     scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback;
     scheduler::TestableScheduler* mScheduler = nullptr;
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 4683c51..46c8404 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -551,13 +551,52 @@
                          kExpectedTransactionsPending);
 }
 
-TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemoveSignaledWithUnsignaledIntact) {
+TEST_F(LatchUnsignaledAutoSingleLayerTest,
+       UnsignaledNotAppliedWhenThereAreSignaled_UnsignaledFirst) {
     const sp<IBinder> kApplyToken1 =
             IInterface::asBinder(TransactionCompletedListener::getIInstance());
     const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+    const sp<IBinder> kApplyToken3 = sp<BBinder>::make();
     const auto kLayerId1 = 1;
     const auto kLayerId2 = 2;
-    const auto kExpectedTransactionsApplied = 1u;
+    const auto kExpectedTransactionsApplied = 2u;
+    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),
+                                  });
+    const auto signaledTransaction2 =
+            createTransactionInfo(kApplyToken3,
+                                  {
+                                          createComposerState(kLayerId2,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+
+    setTransactionStates({unsignaledTransaction, signaledTransaction, signaledTransaction2},
+                         kExpectedTransactionsApplied, kExpectedTransactionsPending);
+}
+
+TEST_F(LatchUnsignaledAutoSingleLayerTest, UnsignaledNotAppliedWhenThereAreSignaled_SignaledFirst) {
+    const sp<IBinder> kApplyToken1 =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    const sp<IBinder> kApplyToken2 = sp<BBinder>::make();
+    const sp<IBinder> kApplyToken3 = sp<BBinder>::make();
+    const auto kLayerId1 = 1;
+    const auto kLayerId2 = 2;
+    const auto kExpectedTransactionsApplied = 2u;
     const auto kExpectedTransactionsPending = 1u;
 
     const auto signaledTransaction =
@@ -567,15 +606,23 @@
                                                               fence(Fence::Status::Signaled),
                                                               layer_state_t::eBufferChanged),
                                   });
-    const auto unsignaledTransaction =
+    const auto signaledTransaction2 =
             createTransactionInfo(kApplyToken2,
                                   {
+                                          createComposerState(kLayerId1,
+                                                              fence(Fence::Status::Signaled),
+                                                              layer_state_t::eBufferChanged),
+                                  });
+    const auto unsignaledTransaction =
+            createTransactionInfo(kApplyToken3,
+                                  {
                                           createComposerState(kLayerId2,
                                                               fence(Fence::Status::Unsignaled),
                                                               layer_state_t::eBufferChanged),
                                   });
-    setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied,
-                         kExpectedTransactionsPending);
+
+    setTransactionStates({signaledTransaction, signaledTransaction2, unsignaledTransaction},
+                         kExpectedTransactionsApplied, kExpectedTransactionsPending);
 }
 
 TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueueSameApplyToken) {
@@ -631,6 +678,28 @@
                          kExpectedTransactionsApplied, kExpectedTransactionsPending);
 }
 
+TEST_F(LatchUnsignaledAutoSingleLayerTest, DontLatchUnsignaledWhenEarlyOffset) {
+    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),
+                                  });
+
+    // Get VsyncModulator out of the default config
+    static_cast<void>(mFlinger.mutableVsyncModulator()->onRefreshRateChangeInitiated());
+
+    setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied,
+                         kExpectedTransactionsPending);
+}
+
 class LatchUnsignaledDisabledTest : public LatchUnsignaledTest {
 public:
     void SetUp() override {
@@ -999,4 +1068,26 @@
                          kExpectedTransactionsApplied, kExpectedTransactionsPending);
 }
 
+TEST_F(LatchUnsignaledAlwaysTest, LatchUnsignaledWhenEarlyOffset) {
+    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),
+                                  });
+
+    // Get VsyncModulator out of the default config
+    static_cast<void>(mFlinger.mutableVsyncModulator()->onRefreshRateChangeInitiated());
+
+    setTransactionStates({unsignaledTransaction}, 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/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 37ecd7c..74d2b7d 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -464,16 +464,16 @@
     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod - bias));
     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 990), Eq(mNow + 2 * mPeriod - bias));
 
-    const auto maxDivider = 5;
+    const auto maxDivisor = 5;
     const auto maxPeriods = 15;
-    for (int divider = 1; divider < maxDivider; divider++) {
+    for (int divisor = 1; divisor < maxDivisor; divisor++) {
         for (int i = 0; i < maxPeriods; i++) {
-            const bool expectedInPhase = (i % divider) == 0;
+            const bool expectedInPhase = (i % divisor) == 0;
             EXPECT_THAT(expectedInPhase,
                         tracker.isVSyncInPhase(mNow + i * mPeriod - bias,
-                                               Fps::fromPeriodNsecs(divider * mPeriod)))
+                                               Fps::fromPeriodNsecs(divisor * mPeriod)))
                     << "vsync at " << mNow + (i + 1) * mPeriod - bias << " is "
-                    << (expectedInPhase ? "not " : "") << "in phase for divider " << divider;
+                    << (expectedInPhase ? "not " : "") << "in phase for divisor " << divisor;
         }
     }
 }
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 4a7d8eb..a1aa7e8 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -152,7 +152,7 @@
                  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,
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 9be8cc7..570ffeb 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -131,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/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index cae7684..ee7e92c 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -16,6 +16,7 @@
 #pragma once
 
 #include <gui/SyncScreenCaptureListener.h>
+#include <private/gui/ComposerServiceAIDL.h>
 #include <ui/Rect.h>
 #include <utils/String8.h>
 #include <functional>
@@ -31,15 +32,15 @@
 public:
     static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
                                    ScreenCaptureResults& captureResults) {
-        const auto sf = ComposerService::getComposerService();
+        const auto sf = ComposerServiceAIDL::getComposerService();
         SurfaceComposerClient::Transaction().apply(true);
 
         captureArgs.dataspace = ui::Dataspace::V0_SRGB;
         const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
-        status_t status = sf->captureDisplay(captureArgs, captureListener);
+        binder::Status status = sf->captureDisplay(captureArgs, captureListener);
 
-        if (status != NO_ERROR) {
-            return status;
+        if (status.transactionError() != NO_ERROR) {
+            return status.transactionError();
         }
         captureResults = captureListener->waitForResults();
         return captureResults.result;
@@ -64,14 +65,14 @@
 
     static status_t captureLayers(LayerCaptureArgs& captureArgs,
                                   ScreenCaptureResults& captureResults) {
-        const auto sf = ComposerService::getComposerService();
+        const auto sf = ComposerServiceAIDL::getComposerService();
         SurfaceComposerClient::Transaction().apply(true);
 
         captureArgs.dataspace = ui::Dataspace::V0_SRGB;
         const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
-        status_t status = sf->captureLayers(captureArgs, captureListener);
-        if (status != NO_ERROR) {
-            return status;
+        binder::Status status = sf->captureLayers(captureArgs, captureListener);
+        if (status.transactionError() != NO_ERROR) {
+            return status.transactionError();
         }
         captureResults = captureListener->waitForResults();
         return captureResults.result;