Merge "binder_parcel_fuzzer: add markSensitive coverage" into main
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 372008e..9459087 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -134,6 +134,7 @@
         "main.cpp",
     ],
     required: [
+        "alloctop",
         "atrace",
         "bugreport_procdump",
         "default_screenshot",
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 4758607..fcc6108 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1264,6 +1264,15 @@
     RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
 }
 
+static void DumpKernelMemoryAllocations() {
+    if (!access("/proc/allocinfo", F_OK)) {
+        // Print the top 100 biggest memory allocations of at least one byte.
+        // The output is sorted by size, descending.
+        RunCommand("KERNEL MEMORY ALLOCATIONS",
+                   {"alloctop", "--once", "--sort", "s", "--min", "1", "--lines", "100"});
+    }
+}
+
 static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
                                                      std::chrono::milliseconds timeout,
                                                      std::chrono::milliseconds service_timeout) {
@@ -1773,6 +1782,8 @@
 
     DoKmsg();
 
+    DumpKernelMemoryAllocations();
+
     DumpShutdownCheckpoints();
 
     DumpIpAddrAndRules();
diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h
index 9ea6549..52dbb61 100644
--- a/include/android/performance_hint.h
+++ b/include/android/performance_hint.h
@@ -29,7 +29,7 @@
  * workloads are taking. The framework will then compare the actual durations to the target
  * duration and attempt to help the client reach a steady state under the target.
  *
- * Unlike reportActualWorkDuration, the "notify..." hints are intended to be sent in
+ * Unlike reportActualWorkDuration, the "notifyWorkload..." hints are intended to be sent in
  * advance of large changes in the workload, to prevent them from going over the target
  * when there is a sudden, unforseen change. Their effects are intended to last for only
  * one cycle, after which reportActualWorkDuration will have a chance to catch up.
@@ -71,6 +71,10 @@
 #include <stdint.h>
 #include <unistd.h>
 
+#if !defined(__DEPRECATED_IN)
+#define __DEPRECATED_IN(__api_level, ...) __attribute__((__deprecated__))
+#endif
+
 __BEGIN_DECLS
 
 struct APerformanceHintManager;
@@ -116,13 +120,13 @@
  * An opaque type representing a handle to a performance hint session creation configuration.
  * It is consumed by {@link APerformanceHint_createSessionUsingConfig}.
  *
- * A session creation config encapsulates the required information for a session.
- * Additionally, the caller can set various settings for the session,
- * to be passed during creation, streamlining the session setup process.
+ * A session creation config encapsulates the required information for creating a session. The only
+ * mandatory parameter is the set of TIDs, set using {@link ASessionCreationConfig_setTids}. Only
+ * parameters relevant to the session need to be set, and any unspecified functionality will be
+ * treated as unused on the session. Configurations without a valid set of TIDs, or which try to
+ * enable automatic timing without the graphics pipeline mode, are considered invalid.
  *
- * The caller may reuse this object and modify the settings in it
- * to create additional sessions.
- *
+ * The caller may reuse this object and modify the settings in it to create additional sessions.
  */
 typedef struct ASessionCreationConfig ASessionCreationConfig;
 
@@ -181,27 +185,43 @@
         int64_t initialTargetWorkDurationNanos) __INTRODUCED_IN(__ANDROID_API_T__);
 
 /**
- * Creates a session for the given set of threads that are graphics pipeline threads
- * and set their initial target work duration.
+ * Creates a session using arguments from a corresponding {@link ASessionCreationConfig}.
+ *
+ * Note: when using graphics pipeline mode, using too many cumulative graphics pipeline threads is
+ * not a failure and will still create a session, but it will cause all graphics pipeline sessions
+ * to have undefined behavior and the method will return EBUSY.
  *
  * @param manager The performance hint manager instance.
  * @param config The configuration struct containing required information
  *        to create a session.
- * @return APerformanceHintSession pointer on success, nullptr on failure.
+ * @param sessionOut A client-provided pointer, which will be set to the new APerformanceHintSession
+ *        on success or EBUSY, and to nullptr on failure.
+ *
+ * @return 0 on success.
+ *         EINVAL if the creation config is in an invalid state.
+ *         EPIPE if communication failed.
+ *         ENOTSUP if hint sessions are not supported, or if auto timing is enabled but unsupported.
+ *         EBUSY if too many graphics pipeline threads are passed.
  */
-APerformanceHintSession* _Nullable APerformanceHint_createSessionUsingConfig(
+int APerformanceHint_createSessionUsingConfig(
         APerformanceHintManager* _Nonnull manager,
-        ASessionCreationConfig* _Nonnull config)
-        __INTRODUCED_IN(36);
+        ASessionCreationConfig* _Nonnull config,
+        APerformanceHintSession * _Nullable * _Nonnull sessionOut) __INTRODUCED_IN(36);
 
 /**
  * Get preferred update rate information for this device.
  *
+ * @deprecated Client side rate limiting is not necessary, rate limiting is handled in the
+ *             framework. If you were using this to check for hint session support, please use
+ *             {@link APerformanceHint_isFeatureSupported} instead.
+ *
  * @param manager The performance hint manager instance.
  * @return the preferred update rate supported by device software.
  */
 int64_t APerformanceHint_getPreferredUpdateRateNanos(
-        APerformanceHintManager* _Nonnull manager) __INTRODUCED_IN(__ANDROID_API_T__);
+        APerformanceHintManager* _Nonnull manager)
+        __INTRODUCED_IN(__ANDROID_API_T__) __DEPRECATED_IN(36, "Client-side rate limiting is not"
+        " necessary, use APerformanceHint_isFeatureSupported for support checking.");
 
 /**
  * Get maximum number of graphics pipieline threads per-app for this device.
@@ -216,9 +236,11 @@
  * Updates this session's target duration for each cycle of work.
  *
  * @param session The performance hint session instance to update.
- * @param targetDurationNanos The new desired duration in nanoseconds. This must be positive.
+ * @param targetDurationNanos The new desired duration in nanoseconds. This must be positive for the
+ *        session to report work durations, and may be zero to disable this functionality.
+ *
  * @return 0 on success.
- *         EINVAL if targetDurationNanos is not positive.
+ *         EINVAL if targetDurationNanos is less than zero.
  *         EPIPE if communication with the system service has failed.
  */
 int APerformanceHint_updateTargetWorkDuration(
@@ -235,7 +257,7 @@
  * @param actualDurationNanos The duration of time the thread group took to complete its last
  *     task in nanoseconds. This must be positive.
  * @return 0 on success.
- *         EINVAL if actualDurationNanos is not positive.
+ *         EINVAL if actualDurationNanos is not positive or the target it not positive.
  *         EPIPE if communication with the system service has failed.
  */
 int APerformanceHint_reportActualWorkDuration(
@@ -258,15 +280,20 @@
  * Set a list of threads to the performance hint session. This operation will replace
  * the current list of threads with the given list of threads.
  *
+ * Note: when using a session with the graphics pipeline mode enabled, using too many cumulative
+ * graphics pipeline threads is not a failure, but it will cause all graphics pipeline sessions to
+ * have undefined behavior and the method will return EBUSY.
+ *
  * @param session The performance hint session instance to update.
  * @param threadIds The list of threads to be associated with this session. They must be part of
  *     this app's thread group.
  * @param size The size of the list of threadIds.
  * @return 0 on success.
  *         EINVAL if the list of thread ids is empty or if any of the thread ids are not part of
-               the thread group.
+ *         the thread group.
  *         EPIPE if communication with the system service has failed.
  *         EPERM if any thread id doesn't belong to the application.
+ *         EBUSY if too many graphics pipeline threads were passed.
  */
 int APerformanceHint_setThreads(
         APerformanceHintSession* _Nonnull session,
@@ -311,89 +338,102 @@
         AWorkDuration* _Nonnull workDuration) __INTRODUCED_IN(__ANDROID_API_V__);
 
 /**
- * Informs the framework of an upcoming increase in the workload of a graphics pipeline
- * bound to this session. The user can specify whether the increase is expected to be
- * on the CPU, GPU, or both.
+ * Informs the framework of an upcoming increase in the workload of this session.
+ * The user can specify whether the increase is expected to be on the CPU, GPU, or both.
  *
- * Sending hints for both CPU and GPU counts as two separate hints for the purposes of the
- * rate limiter.
+ * These hints should be sent shortly before the start of the cycle where the workload is going to
+ * change, or as early as possible during that cycle for maximum effect. Hints sent towards the end
+ * of the cycle may be interpreted as applying to the next cycle. Any unsupported hints will be
+ * silently dropped, to avoid the need for excessive support checking each time they are sent, and
+ * sending a hint for both CPU and GPU will count as two separate hints for the rate limiter. These
+ * hints should not be sent repeatedly for an ongoing expensive workload, as workload time reporting
+ * is intended to handle this.
  *
+ * @param session The {@link APerformanceHintSession} instance to send a hint for.
  * @param cpu Indicates if the workload increase is expected to affect the CPU.
  * @param gpu Indicates if the workload increase is expected to affect the GPU.
- * @param debugName A required string used to identify this specific hint during
- *        tracing. This debug string will only be held for the duration of the
- *        method, and can be safely discarded after.
+ * @param identifier A required string used to distinguish this specific hint, using utf-8 encoding.
+ *        This string will only be held for the duration of the method, and can be discarded after.
  *
  * @return 0 on success.
- *         EINVAL if no hints were requested.
  *         EBUSY if the hint was rate limited.
  *         EPIPE if communication with the system service has failed.
- *         ENOTSUP if the hint is not supported.
  */
 int APerformanceHint_notifyWorkloadIncrease(
         APerformanceHintSession* _Nonnull session,
-        bool cpu, bool gpu, const char* _Nonnull debugName) __INTRODUCED_IN(36);
+        bool cpu, bool gpu, const char* _Nonnull identifier) __INTRODUCED_IN(36);
 
 /**
- * Informs the framework of an upcoming reset in the workload of a graphics pipeline
- * bound to this session, or the imminent start of a new workload. The user can specify
- * whether the reset is expected to affect the CPU, GPU, or both.
+ * Informs the framework that the workload associated with this session is about to start, or that
+ * it is about to completely change, and that the system should discard any assumptions about its
+ * characteristics inferred from previous activity. The user can specify whether the reset is
+ * expected to affect the CPU, GPU, or both.
  *
- * Sending hints for both CPU and GPU counts as two separate hints for the purposes of the
- * this load tracking.
+ * These hints should be sent shortly before the start of the cycle where the workload is going to
+ * change, or as early as possible during that cycle for maximum effect. Hints sent towards the end
+ * of the cycle may be interpreted as applying to the next cycle. Any unsupported hints will be
+ * silently dropped, to avoid the need for excessive support checking each time they are sent, and
+ * sending a hint for both CPU and GPU will count as two separate hints for the rate limiter. These
+ * hints should not be sent repeatedly for an ongoing expensive workload, as workload time reporting
+ * is intended to handle this.
  *
+ * @param session The {@link APerformanceHintSession} instance to send a hint for.
  * @param cpu Indicates if the workload reset is expected to affect the CPU.
  * @param gpu Indicates if the workload reset is expected to affect the GPU.
- * @param debugName A required string used to identify this specific hint during
- *        tracing. This debug string will only be held for the duration of the
- *        method, and can be safely discarded after.
+ * @param identifier A required string used to distinguish this specific hint, using utf-8 encoding.
+ *        This string will only be held for the duration of the method, and can be discarded after.
  *
  * @return 0 on success.
- *         EINVAL if no hints were requested.
  *         EBUSY if the hint was rate limited.
  *         EPIPE if communication with the system service has failed.
- *         ENOTSUP if the hint is not supported.
  */
 int APerformanceHint_notifyWorkloadReset(
         APerformanceHintSession* _Nonnull session,
-        bool cpu, bool gpu, const char* _Nonnull debugName) __INTRODUCED_IN(36);
+        bool cpu, bool gpu, const char* _Nonnull identifier) __INTRODUCED_IN(36);
 
 /**
- * Informs the framework of an upcoming one-off expensive frame for a graphics pipeline
- * bound to this session. This frame will be treated as not representative of the workload as a
- * whole, and it will be discarded the purposes of load tracking. The user can specify
- * whether the workload spike is expected to be on the CPU, GPU, or both.
+ * Informs the framework of an upcoming one-off expensive workload cycle for a given session.
+ * This cycle will be treated as not representative of the workload as a whole, and it will be
+ * discarded the purposes of load tracking. The user can specify whether the workload spike is
+ * expected to be on the CPU, GPU, or both.
  *
- * Sending hints for both CPU and GPU counts as two separate hints for the purposes of the
- * rate limiter.
+ * These hints should be sent shortly before the start of the cycle where the workload is going to
+ * change, or as early as possible during that cycle for maximum effect. Hints sent towards the end
+ * of the cycle may be interpreted as applying to the next cycle. Any unsupported hints will be
+ * silently dropped, to avoid the need for excessive support checking each time they are sent, and
+ * sending a hint for both CPU and GPU will count as two separate hints for the rate limiter. These
+ * hints should not be sent repeatedly for an ongoing expensive workload, as workload time reporting
+ * is intended to handle this.
  *
+ * @param session The {@link APerformanceHintSession} instance to send a hint for.
  * @param cpu Indicates if the workload spike is expected to affect the CPU.
  * @param gpu Indicates if the workload spike is expected to affect the GPU.
- * @param debugName A required string used to identify this specific hint during
- *        tracing. This debug string will only be held for the duration of the
- *        method, and can be safely discarded after.
+ * @param identifier A required string used to distinguish this specific hint, using utf-8 encoding.
+ *        This string will only be held for the duration of the method, and can be discarded after.
  *
  * @return 0 on success.
- *         EINVAL if no hints were requested.
  *         EBUSY if the hint was rate limited.
  *         EPIPE if communication with the system service has failed.
- *         ENOTSUP if the hint is not supported.
  */
 int APerformanceHint_notifyWorkloadSpike(
         APerformanceHintSession* _Nonnull session,
-        bool cpu, bool gpu, const char* _Nonnull debugName) __INTRODUCED_IN(36);
+        bool cpu, bool gpu, const char* _Nonnull identifier) __INTRODUCED_IN(36);
 
 /**
  * Associates a session with any {@link ASurfaceControl} or {@link ANativeWindow}
- * instances managed by this session.
+ * instances managed by this session. Any previously associated objects that are not passed
+ * in again lose their association. Invalid or dead instances are ignored, and passing both
+ * lists as null drops all current associations.
  *
  * This method is primarily intended for sessions that manage the timing of an entire
- * graphics pipeline end-to-end, such as those using the
+ * graphics pipeline end-to-end for frame pacing, such as those using the
  * {@link ASessionCreationConfig_setGraphicsPipeline} API. However, any session directly
  * or indirectly managing a graphics pipeline should still associate themselves with
  * directly relevant ASurfaceControl or ANativeWindow instances for better optimization.
+ * Additionally, if the surface associated with a session changes, this method should be called
+ * again to re-create the association.
  *
- * To see any benefit from this method, the client must make sure they are updating the framerate
+ * To see any benefit from this method, the client must make sure they are updating the frame rate
  * of attached surfaces using methods such as {@link ANativeWindow_setFrameRate}, or by updating
  * any associated ASurfaceControls with transactions that have {ASurfaceTransaction_setFrameRate}.
  *
@@ -407,16 +447,77 @@
  *
  * @return 0 on success.
  *         EPIPE if communication has failed.
- *         ENOTSUP if unsupported.
- *         EINVAL if invalid or empty arguments passed.
+ *         ENOTSUP if this is not supported on the device.
  */
 
 int APerformanceHint_setNativeSurfaces(APerformanceHintSession* _Nonnull session,
-        ANativeWindow* _Nonnull* _Nullable nativeWindows, int nativeWindowsSize,
-        ASurfaceControl* _Nonnull* _Nullable surfaceControls, int surfaceControlsSize)
+        ANativeWindow* _Nonnull* _Nullable nativeWindows, size_t nativeWindowsSize,
+        ASurfaceControl* _Nonnull* _Nullable surfaceControls, size_t surfaceControlsSize)
         __INTRODUCED_IN(36);
 
 /**
+ * This enum represents different aspects of performance hint functionality. These can be passed
+ * to {@link APerformanceHint_isFeatureSupported} to determine whether the device exposes support
+ * for that feature.
+ *
+ * Some of these features will not expose failure to the client if used when unsupported, to prevent
+ * the client from needing to worry about handling different logic for each possible support
+ * configuration. The exception to this is features with important user-facing side effects, such as
+ * {@link APERF_HINT_AUTO_CPU} and {@link APERF_HINT_AUTO_GPU} modes which expect the client not to
+ * report durations while they are active.
+ */
+typedef enum APerformanceHintFeature : int32_t {
+    /**
+     * This value represents all APerformanceHintSession functionality. Using the Performance Hint
+     * API at all if this is not enabled will likely result in either
+     * {@link APerformanceHintManager} or {@link APerformanceHintSession} failing to create, or the
+     * session having little to no benefit even if creation succeeds.
+     */
+    APERF_HINT_SESSIONS,
+
+    /**
+     * This value represents the power efficiency mode, as exposed by
+     * {@link ASessionCreationConfig_setPreferPowerEfficiency} and
+     * {@link APerformanceHint_setPreferPowerEfficiency}.
+     */
+    APERF_HINT_POWER_EFFICIENCY,
+
+    /**
+     * This value the ability for sessions to bind to surfaces using
+     * {@link APerformanceHint_setNativeSurfaces} or
+     * {@link ASessionCreationConfig_setNativeSurfaces}
+     */
+    APERF_HINT_SURFACE_BINDING,
+
+    /**
+     * This value represents the "graphics pipeline" mode, as exposed by
+     * {@link ASessionCreationConfig_setGraphicsPipeline}.
+     */
+    APERF_HINT_GRAPHICS_PIPELINE,
+
+    /**
+     * This value represents the automatic CPU timing feature, as exposed by
+     * {@link ASessionCreationConfig_setUseAutoTiming}.
+     */
+    APERF_HINT_AUTO_CPU,
+
+    /**
+     * This value represents the automatic GPU timing feature, as exposed by
+     * {@link ASessionCreationConfig_setUseAutoTiming}.
+     */
+    APERF_HINT_AUTO_GPU,
+} APerformanceHintFeature;
+
+/**
+ * Checks whether the device exposes support for a specific feature.
+ *
+ * @param feature The specific feature enum to check.
+ *
+ * @return false if unsupported, true if supported.
+ */
+bool APerformanceHint_isFeatureSupported(APerformanceHintFeature feature) __INTRODUCED_IN(36);
+
+/**
  * Creates a new AWorkDuration. When the client finishes using {@link AWorkDuration}, it should
  * call {@link AWorkDuration_release()} to destroy {@link AWorkDuration} and release all resources
  * associated with it.
@@ -507,7 +608,6 @@
 ASessionCreationConfig* _Nonnull ASessionCreationConfig_create()
                 __INTRODUCED_IN(36);
 
-
 /**
  * Destroys a {@link ASessionCreationConfig} and frees all
  * resources associated with it.
@@ -526,11 +626,8 @@
  * @param tids The list of tids to be associated with this session. They must be part of
  *        this process' thread group.
  * @param size The size of the list of tids.
- *
- * @return 0 on success.
- *         EINVAL if invalid array pointer or the value of size
  */
-int ASessionCreationConfig_setTids(
+void ASessionCreationConfig_setTids(
         ASessionCreationConfig* _Nonnull config,
         const pid_t* _Nonnull tids, size_t size)  __INTRODUCED_IN(36);
 
@@ -539,15 +636,11 @@
  *
  * @param config The {@link ASessionCreationConfig}
  *        created by calling {@link ASessionCreationConfig_create()}.
- * @param targetWorkDurationNanos The parameter to specify a target duration
- *        in nanoseconds for the new session; this value must be positive to use
- *        the work duration API.
- *
- * @return 0 on success.
- *         ENOTSUP if unsupported
- *         EINVAL if invalid value
+ * @param targetWorkDurationNanos The parameter to specify a target duration in nanoseconds for the
+ *        new session; this value must be positive to use the work duration API, and may be ignored
+ *        otherwise or set to zero. Negative values are invalid.
  */
-int ASessionCreationConfig_setTargetWorkDurationNanos(
+void ASessionCreationConfig_setTargetWorkDurationNanos(
         ASessionCreationConfig* _Nonnull config,
         int64_t targetWorkDurationNanos)  __INTRODUCED_IN(36);
 
@@ -559,12 +652,8 @@
  * @param config The {@link ASessionCreationConfig}
  *        created by calling {@link ASessionCreationConfig_create()}.
  * @param enabled Whether power efficiency mode will be enabled.
- *
- * @return 0 on success.
- *         ENOTSUP if unsupported
- *         EINVAL if invalid pointer to creation config
  */
-int ASessionCreationConfig_setPreferPowerEfficiency(
+void ASessionCreationConfig_setPreferPowerEfficiency(
         ASessionCreationConfig* _Nonnull config, bool enabled)  __INTRODUCED_IN(36);
 
 /**
@@ -574,24 +663,31 @@
  * buffer is fully finished drawing.
  *
  * It should include any threads on the critical path of that pipeline,
- * up to a limit accessible from {@link getMaxGraphicsPipelineThreadsCount()}.
+ * up to a limit accessible from {@link APerformanceHint_getMaxGraphicsPipelineThreadsCount()}.
  *
  * @param config The {@link ASessionCreationConfig}
  *        created by calling {@link ASessionCreationConfig_create()}.
  * @param enabled Whether this session manages a graphics pipeline's critical path.
- *
- * @return 0 on success.
- *         ENOTSUP if unsupported
- *         EINVAL if invalid pointer to creation config or maximum threads for graphics
-                  pipeline is reached.
  */
-int ASessionCreationConfig_setGraphicsPipeline(
+void ASessionCreationConfig_setGraphicsPipeline(
         ASessionCreationConfig* _Nonnull config, bool enabled)  __INTRODUCED_IN(36);
 
 /**
- * Associates a session with any {@link ASurfaceControl} or {@link ANativeWindow}
- * instances managed by this session. See {@link APerformanceHint_setNativeSurfaces}
- * for more details.
+ * Associates the created session with any {@link ASurfaceControl} or {@link ANativeWindow}
+ * instances it will be managing. Invalid or dead instances are ignored.
+ *
+ * This method is primarily intended for sessions that manage the timing of an entire
+ * graphics pipeline end-to-end for frame pacing, such as those using the
+ * {@link ASessionCreationConfig_setGraphicsPipeline} API. However, any session directly
+ * or indirectly managing a graphics pipeline should still associate themselves with
+ * directly relevant ASurfaceControl or ANativeWindow instances for better optimization.
+ * Additionally, if the surface associated with a session changes, this method should be called
+ * again to re-create the association.
+ *
+ * To see any benefit from this method, the client must make sure they are updating the frame rate
+ * of attached surfaces using methods such as {@link ANativeWindow_setFrameRate}, or by updating
+ * any associated ASurfaceControls with transactions that have {ASurfaceTransaction_setFrameRate}.
+ *
  *
  * @param config The {@link ASessionCreationConfig}
  *        created by calling {@link ASessionCreationConfig_create()}.
@@ -601,49 +697,46 @@
  * @param surfaceControls A pointer to a list of ASurfaceControls associated with this session.
  *        nullptr can be passed to indicate there are no associated ASurfaceControls.
  * @param surfaceControlsSize The number of ASurfaceControls in the list.
- *
- * @return 0 on success.
- *         ENOTSUP if unsupported.
- *         EINVAL if invalid or empty arguments passed.
  */
-int ASessionCreationConfig_setNativeSurfaces(
+void ASessionCreationConfig_setNativeSurfaces(
         ASessionCreationConfig* _Nonnull config,
-        ANativeWindow* _Nonnull* _Nullable nativeWindows, int nativeWindowsSize,
-        ASurfaceControl* _Nonnull* _Nullable surfaceControls, int surfaceControlsSize)
+        ANativeWindow* _Nonnull* _Nullable nativeWindows, size_t nativeWindowsSize,
+        ASurfaceControl* _Nonnull* _Nullable surfaceControls, size_t surfaceControlsSize)
         __INTRODUCED_IN(36);
 
 /**
  * Enable automatic timing mode for sessions using the GRAPHICS_PIPELINE API with an attached
- * surface. In this mode, sessions do not need to report actual durations and only need
- * to keep their thread list up-to-date, set a native surface, call
- * {@link ASessionCreationConfig_setGraphicsPipeline()} to signal that the session is in
- * "graphics pipeline" mode, and then set whether automatic timing is desired for the
- * CPU, GPU, or both, using this method.
+ * surface. In this mode, sessions do not need to report timing data for the CPU, GPU, or both
+ * depending on the configuration. To use this mode, sessions should set a native surface
+ * using {@ASessionCreationConfig_setNativeSurfaces}, enable graphics pipeline mode with
+ * {@link ASessionCreationConfig_setGraphicsPipeline()}, and then call this method to set whether
+ * automatic timing is desired for the CPU, GPU, or both. Trying to enable this without also
+ * enabling the graphics pipeline mode will cause session creation to fail.
  *
  * It is still be beneficial to set an accurate target time, as this may help determine
  * timing information for some workloads where there is less information available from
  * the framework, such as games. Additionally, reported CPU durations will be ignored
  * while automatic CPU timing is enabled, and similarly GPU durations will be ignored
  * when automatic GPU timing is enabled. When both are enabled, the entire
- * reportActualWorkDuration call will be ignored, and the session will be managed
- * completely automatically.
+ * {@link APerformanceHint_reportActualWorkDuration} call will be ignored, and the session will be
+ * managed completely automatically.
  *
- * This mode will not work unless the client makes sure they are updating the framerate
- * of attached surfaces with methods such as {@link ANativeWindow_setFrameRate}, or updating
- * any associated ASurfaceControls with transactions that have {ASurfaceTransaction_setFrameRate}.
+ * If the client is manually controlling their frame rate for those surfaces, then they must make
+ * sure they are updating the frame rate with {@link ANativeWindow_setFrameRate}, or updating any
+ * associated ASurfaceControls with transactions that have {ASurfaceTransaction_setFrameRate} set.
+ *
+ * The user of this API should ensure this feature is supported by checking
+ * {@link APERF_HINT_AUTO_CPU} and {@link APERF_HINT_AUTO_GPU} with
+ * {@link APerformanceHint_isFeatureSupported} and falling back to manual timing if it is not.
+ * Trying to use automatic timing when it is unsupported will cause session creation to fail.
  *
  * @param config The {@link ASessionCreationConfig}
  *        created by calling {@link ASessionCreationConfig_create()}.
  * @param cpu Whether to enable automatic timing for the CPU for this session.
  * @param gpu Whether to enable automatic timing for the GPU for this session.
- *
- * @return 0 on success.
- *         ENOTSUP if unsupported.
  */
-int ASessionCreationConfig_setUseAutoTiming(
-        ASessionCreationConfig* _Nonnull config,
-        bool cpu, bool gpu)
-        __INTRODUCED_IN(36);
+void ASessionCreationConfig_setUseAutoTiming(
+        ASessionCreationConfig* _Nonnull config, bool cpu, bool gpu) __INTRODUCED_IN(36);
 
 __END_DECLS
 
diff --git a/include/input/AccelerationCurve.h b/include/input/AccelerationCurve.h
index 0cf648a..8a4a5d4 100644
--- a/include/input/AccelerationCurve.h
+++ b/include/input/AccelerationCurve.h
@@ -46,4 +46,15 @@
 std::vector<AccelerationCurveSegment> createAccelerationCurveForPointerSensitivity(
         int32_t sensitivity);
 
+/*
+ * Creates a flat acceleration curve for disabling pointer acceleration.
+ *
+ * This method generates a single AccelerationCurveSegment with specific values
+ * to effectively disable acceleration for both mice and touchpads.
+ * A flat acceleration curve ensures a constant gain, meaning that the output
+ * velocity is directly proportional to the input velocity, resulting in
+ * a 1:1 movement ratio between the input device and the on-screen pointer.
+ */
+std::vector<AccelerationCurveSegment> createFlatAccelerationCurve(int32_t sensitivity);
+
 } // namespace android
diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h
index e3f98ba..a468313 100644
--- a/include/private/performance_hint_private.h
+++ b/include/private/performance_hint_private.h
@@ -125,8 +125,10 @@
 /**
  * Creates a session using ASessionCreationConfig
  */
-APerformanceHintSession* APerformanceHint_createSessionUsingConfigInternal(
-        APerformanceHintManager* manager, ASessionCreationConfig* sessionCreationConfig,
+int APerformanceHint_createSessionUsingConfigInternal(
+        APerformanceHintManager* manager,
+        ASessionCreationConfig* config,
+        APerformanceHintSession** sessionOut,
         SessionTag tag);
 
 /**
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 9ef4e69..f7465e2 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -64,7 +64,10 @@
      * Returns the PID of the process which has made the current binder
      * call. If not in a binder call, this will return getpid.
      *
-     * Warning: oneway transactions do not receive PID. Even if you expect
+     * Warning do not use this as a security identifier! PID is unreliable
+     * as it may be re-used. This should mostly be used for debugging.
+     *
+     * oneway transactions do not receive PID. Even if you expect
      * a transaction to be synchronous, a misbehaving client could send it
      * as an asynchronous call and result in a 0 PID here. Additionally, if
      * there is a race and the calling process dies, the PID may still be
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index bd46c47..d69d318 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -419,6 +419,9 @@
  * This can be used with higher-level system services to determine the caller's identity and check
  * permissions.
  *
+ * Warning do not use this as a security identifier! PID is unreliable as it may be re-used. This
+ * should mostly be used for debugging.
+ *
  * Available since API level 29.
  *
  * \return calling uid or the current process's UID if this thread isn't processing a transaction.
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index 8a06274..c0cac83 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -101,7 +101,10 @@
     /// dies and is replaced with another process with elevated permissions and
     /// the same PID.
     ///
-    /// Warning: oneway transactions do not receive PID. Even if you expect
+    /// Warning: do not use this as a security identifier! PID is unreliable
+    /// as it may be re-used. This should mostly be used for debugging.
+    ///
+    /// oneway transactions do not receive PID. Even if you expect
     /// a transaction to be synchronous, a misbehaving client could send it
     /// as a synchronous call and result in a 0 PID here. Additionally, if
     /// there is a race and the calling process dies, the PID may still be
diff --git a/libs/input/AccelerationCurve.cpp b/libs/input/AccelerationCurve.cpp
index 0a92a71..0b47f3e 100644
--- a/libs/input/AccelerationCurve.cpp
+++ b/libs/input/AccelerationCurve.cpp
@@ -40,6 +40,18 @@
 constexpr std::array<double, 15> kSensitivityFactors = {1,  2,  4,  6,  7,  8,  9, 10,
                                                         11, 12, 13, 14, 16, 18, 20};
 
+// Calculates the base gain for a given pointer sensitivity value.
+//
+// The base gain is a scaling factor that is applied to the pointer movement.
+// Higher sensitivity values result in larger base gains, which in turn result
+// in faster pointer movements.
+//
+// The base gain is calculated using a linear mapping function that maps the
+// sensitivity range [-7, 7] to a base gain range [0.5, 2.0].
+double calculateBaseGain(int32_t sensitivity) {
+    return 0.5 + (sensitivity + 7) * (2.0 - 0.5) / (7 + 7);
+}
+
 } // namespace
 
 std::vector<AccelerationCurveSegment> createAccelerationCurveForPointerSensitivity(
@@ -60,4 +72,13 @@
     return output;
 }
 
+std::vector<AccelerationCurveSegment> createFlatAccelerationCurve(int32_t sensitivity) {
+    LOG_ALWAYS_FATAL_IF(sensitivity < -7 || sensitivity > 7, "Invalid pointer sensitivity value");
+    std::vector<AccelerationCurveSegment> output = {
+            AccelerationCurveSegment{std::numeric_limits<double>::infinity(),
+                                     calculateBaseGain(sensitivity),
+                                     /* reciprocal = */ 0}};
+    return output;
+}
+
 } // namespace android
\ No newline at end of file
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 6a55726..56ccaab 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -327,8 +327,8 @@
                                                    android::base::unique_fd fd, sp<IBinder> token) {
     const int result = fcntl(fd, F_SETFL, O_NONBLOCK);
     if (result != 0) {
-        LOG_ALWAYS_FATAL("channel '%s' ~ Could not make socket non-blocking: %s", name.c_str(),
-                         strerror(errno));
+        LOG_ALWAYS_FATAL("channel '%s' ~ Could not make socket (%d) non-blocking: %s", name.c_str(),
+                         fd.get(), strerror(errno));
         return nullptr;
     }
     // using 'new' to access a non-public constructor
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index 31592cd..6ce3fba 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -76,6 +76,9 @@
     /* The default pointer acceleration value. */
     const int DEFAULT_POINTER_ACCELERATION = 3;
 
+    /* The default mouse wheel acceleration value. */
+    const int DEFAULT_MOUSE_WHEEL_ACCELERATION = 4;
+
     /**
      * Use the default Velocity Tracker Strategy. Different axes may use different default
      * strategies.
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index fd77048..6cdd249 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -109,13 +109,6 @@
 }
 
 flag {
-  name: "enable_touchpad_fling_stop"
-  namespace: "input"
-  description: "Enable fling scrolling to be stopped by putting a finger on the touchpad again"
-  bug: "281106755"
-}
-
-flag {
   name: "enable_prediction_pruning_via_jerk_thresholding"
   namespace: "input"
   description: "Enable prediction pruning based on jerk thresholds."
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 0167c43..85a37fe 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -58,11 +58,19 @@
         "-Wno-unused-parameter",
     ],
     sanitize: {
+        address: true,
         hwaddress: true,
         undefined: true,
         all_undefined: true,
         diag: {
+            cfi: true,
+            integer_overflow: true,
+            memtag_heap: true,
             undefined: true,
+            misc_undefined: [
+                "bounds",
+                "all",
+            ],
         },
     },
     shared_libs: [
@@ -92,11 +100,6 @@
                 "libstatssocket_lazy",
             ],
         },
-        host: {
-            sanitize: {
-                address: true,
-            },
-        },
     },
     native_coverage: false,
 }
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index 7e8ccef..14d08ee 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -544,9 +544,18 @@
     }
 
     if (graphicBuffer && parameters.layer.luts) {
+        const bool dimInLinearSpace = parameters.display.dimmingStage !=
+                aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF;
+        const ui::Dataspace runtimeEffectDataspace = !dimInLinearSpace
+                ? static_cast<ui::Dataspace>(
+                          (parameters.outputDataSpace & ui::Dataspace::STANDARD_MASK) |
+                          ui::Dataspace::TRANSFER_GAMMA2_2 |
+                          (parameters.outputDataSpace & ui::Dataspace::RANGE_MASK))
+                : parameters.outputDataSpace;
+
         shader = mLutShader.lutShader(shader, parameters.layer.luts,
                                       parameters.layer.sourceDataspace,
-                                      toSkColorSpace(parameters.outputDataSpace));
+                                      toSkColorSpace(runtimeEffectDataspace));
     }
 
     if (parameters.requiresLinearEffect) {
diff --git a/libs/renderengine/skia/VulkanInterface.cpp b/libs/renderengine/skia/VulkanInterface.cpp
index 37b69f6..7331bbc 100644
--- a/libs/renderengine/skia/VulkanInterface.cpp
+++ b/libs/renderengine/skia/VulkanInterface.cpp
@@ -204,10 +204,10 @@
         BAIL("[%s] null", #expr); \
     }
 
-#define VK_CHECK(expr)                              \
-    if ((expr) != VK_SUCCESS) {                     \
-        BAIL("[%s] failed. err = %d", #expr, expr); \
-        return;                                     \
+#define VK_CHECK(expr)                                    \
+    if (VkResult result = (expr); result != VK_SUCCESS) { \
+        BAIL("[%s] failed. err = %d", #expr, result);     \
+        return;                                           \
     }
 
 #define VK_GET_PROC(F)                                                           \
diff --git a/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp
index da47aae..750e08f 100644
--- a/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp
+++ b/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp
@@ -74,13 +74,6 @@
     mBlurEffect = std::move(blurEffect);
 }
 
-static sk_sp<SkSurface> makeSurface(SkiaGpuContext* context, const SkRect& origRect, int scale) {
-    SkImageInfo scaledInfo =
-            SkImageInfo::MakeN32Premul(ceil(static_cast<float>(origRect.width()) / scale),
-                                       ceil(static_cast<float>(origRect.height()) / scale));
-    return context->createRenderTarget(scaledInfo);
-}
-
 void KawaseBlurDualFilter::blurInto(const sk_sp<SkSurface>& drawSurface,
                                     const sk_sp<SkImage>& readImage, const float radius,
                                     const float alpha) const {
@@ -124,11 +117,17 @@
     const float filterDepth = std::min(kMaxSurfaces - 1.0f, radius * kInputScale / 2.5f);
     const int filterPasses = std::min(kMaxSurfaces - 1, static_cast<int>(ceil(filterDepth)));
 
+    auto makeSurface = [&](float scale) -> sk_sp<SkSurface> {
+        const auto newW = static_cast<float>(blurRect.width() / scale);
+        const auto newH = static_cast<float>(blurRect.height() / scale);
+        return context->createRenderTarget(input->imageInfo().makeWH(newW, newH));
+    };
+
     // Render into surfaces downscaled by 1x, 2x, and 4x from the initial downscale.
     sk_sp<SkSurface> surfaces[kMaxSurfaces] =
-            {filterPasses >= 0 ? makeSurface(context, blurRect, 1 * kInverseInputScale) : nullptr,
-             filterPasses >= 1 ? makeSurface(context, blurRect, 2 * kInverseInputScale) : nullptr,
-             filterPasses >= 2 ? makeSurface(context, blurRect, 4 * kInverseInputScale) : nullptr};
+            {filterPasses >= 0 ? makeSurface(1 * kInverseInputScale) : nullptr,
+             filterPasses >= 1 ? makeSurface(2 * kInverseInputScale) : nullptr,
+             filterPasses >= 2 ? makeSurface(4 * kInverseInputScale) : nullptr};
 
     // These weights for scaling offsets per-pass are handpicked to look good at 1 <= radius <= 250.
     static const float kWeights[5] = {
diff --git a/libs/tracing_perfetto/Android.bp b/libs/tracing_perfetto/Android.bp
index 8bd0d0f..1ef83a4 100644
--- a/libs/tracing_perfetto/Android.bp
+++ b/libs/tracing_perfetto/Android.bp
@@ -21,7 +21,7 @@
     default_applicable_licenses: ["frameworks_native_license"],
 }
 
-cc_library_shared {
+cc_library {
     name: "libtracing_perfetto",
     export_include_dirs: [
         "include",
@@ -37,6 +37,7 @@
     srcs: [
         "tracing_perfetto.cpp",
         "tracing_perfetto_internal.cpp",
+        "tracing_sdk.cpp",
     ],
 
     shared_libs: [
@@ -45,6 +46,10 @@
         "libperfetto_c",
     ],
 
+    export_shared_lib_headers: [
+        "libperfetto_c",
+    ],
+
     host_supported: true,
     // for vndbinder
     vendor_available: true,
diff --git a/libs/tracing_perfetto/include/tracing_sdk.h b/libs/tracing_perfetto/include/tracing_sdk.h
new file mode 100644
index 0000000..4a6e849
--- /dev/null
+++ b/libs/tracing_perfetto/include/tracing_sdk.h
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <stdint.h>
+
+#include <optional>
+#include <vector>
+
+#include "perfetto/public/producer.h"
+#include "perfetto/public/te_category_macros.h"
+#include "perfetto/public/te_macros.h"
+#include "perfetto/public/track_event.h"
+
+/**
+ * The objects declared here are intended to be managed by Java.
+ * This means the Java Garbage Collector is responsible for freeing the
+ * underlying native resources.
+ *
+ * The static methods prefixed with `delete_` are special. They are designed to be
+ * invoked by Java through the `NativeAllocationRegistry` when the
+ * corresponding Java object becomes unreachable.  These methods act as
+ * callbacks to ensure proper deallocation of native resources.
+ */
+namespace tracing_perfetto {
+/**
+ * @brief Represents extra data associated with a trace event.
+ * This class manages a collection of PerfettoTeHlExtra pointers.
+ */
+class Extra;
+
+/**
+ * @brief Emits a trace event.
+ * @param type The type of the event.
+ * @param cat The category of the event.
+ * @param name The name of the event.
+ * @param arg_ptr Pointer to Extra data.
+ */
+void trace_event(int type, const PerfettoTeCategory* cat, const char* name,
+                 Extra* extra);
+
+/**
+ * @brief Gets the process track UUID.
+ */
+uint64_t get_process_track_uuid();
+
+/**
+ * @brief Gets the thread track UUID for a given PID.
+ */
+uint64_t get_thread_track_uuid(pid_t tid);
+
+/**
+ * @brief Holder for all the other classes in the file.
+ */
+class Extra {
+ public:
+  Extra();
+  void push_extra(PerfettoTeHlExtra* extra);
+  void pop_extra();
+  void clear_extras();
+  static void delete_extra(Extra* extra);
+
+  PerfettoTeHlExtra* const* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Extra);
+
+  // These PerfettoTeHlExtra pointers are really pointers to all the other
+  // types of extras: Category, DebugArg, Counter etc. Those objects are
+  // individually managed by Java.
+  std::vector<PerfettoTeHlExtra*> extras_;
+};
+
+/**
+ * @brief Represents a trace event category.
+ */
+class Category {
+ public:
+  Category(const std::string& name, const std::string& tag,
+           const std::string& severity);
+
+  ~Category();
+
+  void register_category();
+
+  void unregister_category();
+
+  bool is_category_enabled();
+
+  static void delete_category(Category* category);
+
+  const PerfettoTeCategory* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Category);
+  PerfettoTeCategory category_;
+  const std::string name_;
+  const std::string tag_;
+  const std::string severity_;
+};
+
+/**
+ * @brief Represents one end of a flow between two events.
+ */
+class Flow {
+ public:
+  Flow();
+
+  void set_process_flow(uint64_t id);
+  void set_process_terminating_flow(uint64_t id);
+  static void delete_flow(Flow* flow);
+
+  const PerfettoTeHlExtraFlow* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Flow);
+  PerfettoTeHlExtraFlow flow_;
+};
+
+/**
+ * @brief Represents a named track.
+ */
+class NamedTrack {
+ public:
+  NamedTrack(uint64_t id, uint64_t parent_uuid, const std::string& name);
+
+  static void delete_track(NamedTrack* track);
+
+  const PerfettoTeHlExtraNamedTrack* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NamedTrack);
+  const std::string name_;
+  PerfettoTeHlExtraNamedTrack track_;
+};
+
+/**
+ * @brief Represents a registered track.
+ */
+class RegisteredTrack {
+ public:
+  RegisteredTrack(uint64_t id, uint64_t parent_uuid, const std::string& name,
+                  bool is_counter);
+  ~RegisteredTrack();
+
+  void register_track();
+  void unregister_track();
+  static void delete_track(RegisteredTrack* track);
+
+  const PerfettoTeHlExtraRegisteredTrack* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RegisteredTrack);
+  PerfettoTeRegisteredTrack registered_track_;
+  PerfettoTeHlExtraRegisteredTrack track_;
+  const std::string name_;
+  const uint64_t id_;
+  const uint64_t parent_uuid_;
+  const bool is_counter_;
+};
+
+/**
+ * @brief Represents a counter track event.
+ * @tparam T The data type of the counter (int64_t or double).
+ */
+template <typename T>
+class Counter {
+ public:
+  template <typename>
+  struct always_false : std::false_type {};
+
+  struct TypeMap {
+    using type = std::invoke_result_t<decltype([]() {
+      if constexpr (std::is_same_v<T, int64_t>) {
+        return std::type_identity<PerfettoTeHlExtraCounterInt64>{};
+      } else if constexpr (std::is_same_v<T, double>) {
+        return std::type_identity<PerfettoTeHlExtraCounterDouble>{};
+      } else {
+        return std::type_identity<void>{};
+      }
+    })>::type;
+
+    static constexpr int enum_value = []() {
+      if constexpr (std::is_same_v<T, int64_t>) {
+        return PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_INT64;
+      } else if constexpr (std::is_same_v<T, double>) {
+        return PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_DOUBLE;
+      } else {
+        static_assert(always_false<T>::value, "Unsupported type");
+        return 0;  // Never reached, just to satisfy return type
+      }
+    }();
+  };
+
+  Counter() {
+    static_assert(!std::is_same_v<typename TypeMap::type, void>,
+                  "Unsupported type for Counter");
+
+    typename TypeMap::type counter;
+    counter.header = {TypeMap::enum_value};
+    counter_ = std::move(counter);
+  }
+
+  void set_value(T value) {
+    if constexpr (std::is_same_v<T, int64_t>) {
+      counter_.value = value;
+    } else if constexpr (std::is_same_v<T, double>) {
+      counter_.value = value;
+    }
+  }
+
+  static void delete_counter(Counter* counter) {
+    delete counter;
+  }
+
+  const TypeMap::type* get() const {
+    return &counter_;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Counter);
+  TypeMap::type counter_;
+};
+
+/**
+ * @brief Represents a debug argument for a trace event.
+ * @tparam T The data type of the argument (bool, int64_t, double, const char*).
+ */
+template <typename T>
+class DebugArg {
+ public:
+  template <typename>
+  struct always_false : std::false_type {};
+
+  struct TypeMap {
+    using type = std::invoke_result_t<decltype([]() {
+      if constexpr (std::is_same_v<T, bool>) {
+        return std::type_identity<PerfettoTeHlExtraDebugArgBool>{};
+      } else if constexpr (std::is_same_v<T, int64_t>) {
+        return std::type_identity<PerfettoTeHlExtraDebugArgInt64>{};
+      } else if constexpr (std::is_same_v<T, double>) {
+        return std::type_identity<PerfettoTeHlExtraDebugArgDouble>{};
+      } else if constexpr (std::is_same_v<T, const char*>) {
+        return std::type_identity<PerfettoTeHlExtraDebugArgString>{};
+      } else {
+        return std::type_identity<void>{};
+      }
+    })>::type;
+
+    static constexpr int enum_value = []() {
+      if constexpr (std::is_same_v<T, bool>) {
+        return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_BOOL;
+      } else if constexpr (std::is_same_v<T, int64_t>) {
+        return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_INT64;
+      } else if constexpr (std::is_same_v<T, double>) {
+        return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_DOUBLE;
+      } else if constexpr (std::is_same_v<T, const char*>) {
+        return PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_STRING;
+      } else {
+        static_assert(always_false<T>::value, "Unsupported type");
+        return 0;  // Never reached, just to satisfy return type
+      }
+    }();
+  };
+
+  DebugArg(const std::string& name) : name_(name) {
+    static_assert(!std::is_same_v<typename TypeMap::type, void>,
+                  "Unsupported type for DebugArg");
+
+    typename TypeMap::type arg;
+    arg.header = {TypeMap::enum_value};
+    arg.name = name_.c_str();
+    arg_ = std::move(arg);
+  }
+
+  ~DebugArg() {
+    free_string_value();
+  }
+
+  void set_value(T value) {
+    if constexpr (std::is_same_v<T, const char*>) {
+      free_string_value();
+      arg_.value = value;
+    } else if constexpr (std::is_same_v<T, int64_t>) {
+      arg_.value = value;
+    } else if constexpr (std::is_same_v<T, bool>) {
+      arg_.value = value;
+    } else if constexpr (std::is_same_v<T, double>) {
+      arg_.value = value;
+    }
+  }
+
+  static void delete_arg(DebugArg* arg) {
+    delete arg;
+  }
+
+  const TypeMap::type* get() const {
+    return &arg_;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DebugArg);
+  TypeMap::type arg_;
+  const std::string name_;
+
+  constexpr void free_string_value() {
+    if constexpr (std::is_same_v<typename TypeMap::type,
+                                 PerfettoTeHlExtraDebugArgString>) {
+      if (arg_.value) {
+        free((void*)arg_.value);
+        arg_.value = nullptr;
+      }
+    }
+  }
+};
+
+template <typename T>
+class ProtoField {
+ public:
+  template <typename>
+  struct always_false : std::false_type {};
+
+  struct TypeMap {
+    using type = std::invoke_result_t<decltype([]() {
+      if constexpr (std::is_same_v<T, int64_t>) {
+        return std::type_identity<PerfettoTeHlProtoFieldVarInt>{};
+      } else if constexpr (std::is_same_v<T, double>) {
+        return std::type_identity<PerfettoTeHlProtoFieldDouble>{};
+      } else if constexpr (std::is_same_v<T, const char*>) {
+        return std::type_identity<PerfettoTeHlProtoFieldCstr>{};
+      } else {
+        return std::type_identity<void>{};
+      }
+    })>::type;
+
+    static constexpr PerfettoTeHlProtoFieldType enum_value = []() {
+      if constexpr (std::is_same_v<T, int64_t>) {
+        return PERFETTO_TE_HL_PROTO_TYPE_VARINT;
+      } else if constexpr (std::is_same_v<T, double>) {
+        return PERFETTO_TE_HL_PROTO_TYPE_DOUBLE;
+      } else if constexpr (std::is_same_v<T, const char*>) {
+        return PERFETTO_TE_HL_PROTO_TYPE_CSTR;
+      } else {
+        static_assert(always_false<T>::value, "Unsupported type");
+        return 0;  // Never reached, just to satisfy return type
+      }
+    }();
+  };
+
+  ProtoField() {
+    static_assert(!std::is_same_v<typename TypeMap::type, void>,
+                  "Unsupported type for ProtoField");
+
+    typename TypeMap::type arg;
+    arg.header.type = TypeMap::enum_value;
+    arg_ = std::move(arg);
+  }
+
+  ~ProtoField() {
+    free_string_value();
+  }
+
+  void set_value(uint32_t id, T value) {
+    if constexpr (std::is_same_v<T, int64_t>) {
+      arg_.header.id = id;
+      arg_.value = value;
+    } else if constexpr (std::is_same_v<T, double>) {
+      arg_.header.id = id;
+      arg_.value = value;
+    } else if constexpr (std::is_same_v<T, const char*>) {
+      free_string_value();
+      arg_.header.id = id;
+      arg_.str = value;
+    }
+  }
+
+  static void delete_field(ProtoField* field) {
+    delete field;
+  }
+
+  const TypeMap::type* get() const {
+    return &arg_;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ProtoField);
+  TypeMap::type arg_;
+
+  constexpr void free_string_value() {
+    if constexpr (std::is_same_v<typename TypeMap::type,
+                                 PerfettoTeHlProtoFieldCstr>) {
+      if (arg_.str) {
+        free((void*)arg_.str);
+        arg_.str = nullptr;
+      }
+    }
+  }
+};
+
+class ProtoFieldNested {
+ public:
+  ProtoFieldNested();
+
+  void add_field(PerfettoTeHlProtoField* field);
+  void set_id(uint32_t id);
+  static void delete_field(ProtoFieldNested* field);
+
+  const PerfettoTeHlProtoFieldNested* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ProtoFieldNested);
+  PerfettoTeHlProtoFieldNested field_;
+  // These PerfettoTeHlProtoField pointers are really pointers to all the other
+  // types of protos: PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldVarInt,
+  // PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldNested. Those objects are
+  // individually managed by Java.
+  std::vector<PerfettoTeHlProtoField*> fields_;
+};
+
+class Proto {
+ public:
+  Proto();
+
+  void add_field(PerfettoTeHlProtoField* field);
+  void clear_fields();
+  static void delete_proto(Proto* proto);
+
+  const PerfettoTeHlExtraProtoFields* get() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Proto);
+  PerfettoTeHlExtraProtoFields proto_;
+  // These PerfettoTeHlProtoField pointers are really pointers to all the other
+  // types of protos: PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldVarInt,
+  // PerfettoTeHlProtoFieldVarInt, PerfettoTeHlProtoFieldNested. Those objects are
+  // individually managed by Java.
+  std::vector<PerfettoTeHlProtoField*> fields_;
+};
+
+/**
+ * @brief Activates a trigger.
+ * @param name The name of the trigger.
+ * @param ttl_ms The time-to-live of the trigger in milliseconds.
+ */
+void activate_trigger(const char* name, uint32_t ttl_ms);
+}  // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tests/Android.bp b/libs/tracing_perfetto/tests/Android.bp
index d203467..0dab517 100644
--- a/libs/tracing_perfetto/tests/Android.bp
+++ b/libs/tracing_perfetto/tests/Android.bp
@@ -21,12 +21,44 @@
     default_applicable_licenses: ["frameworks_native_license"],
 }
 
+cc_library_static {
+    name: "libtracing_perfetto_test_utils",
+    export_include_dirs: [
+        "include",
+    ],
+    static_libs: [
+        "libflagtest",
+        "libgmock",
+        "perfetto_trace_protos",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-enum-compare",
+        "-Wno-unused-function",
+    ],
+
+    srcs: [
+        "utils.cpp",
+    ],
+
+    shared_libs: [
+        "libperfetto_c",
+        "liblog",
+        "libprotobuf-cpp-lite",
+    ],
+    export_shared_lib_headers: [
+        "libperfetto_c",
+    ],
+}
+
 cc_test {
     name: "libtracing_perfetto_tests",
     static_libs: [
         "libflagtest",
         "libgmock",
         "perfetto_trace_protos",
+        "libtracing_perfetto_test_utils",
     ],
     cflags: [
         "-Wall",
@@ -42,7 +74,6 @@
     ],
     srcs: [
         "tracing_perfetto_test.cpp",
-        "utils.cpp",
     ],
     test_suites: ["device-tests"],
 }
diff --git a/libs/tracing_perfetto/tests/include/utils.h b/libs/tracing_perfetto/tests/include/utils.h
new file mode 100644
index 0000000..b2630e1
--- /dev/null
+++ b/libs/tracing_perfetto/tests/include/utils.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2024 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.
+ */
+
+// Copied from //external/perfetto/src/shared_lib/test/utils.h
+
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <cassert>
+#include <condition_variable>
+#include <cstdint>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <mutex>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "perfetto/public/abi/pb_decoder_abi.h"
+#include "perfetto/public/pb_utils.h"
+#include "perfetto/public/tracing_session.h"
+
+// Pretty printer for gtest
+void PrintTo(const PerfettoPbDecoderField& field, std::ostream*);
+
+namespace perfetto {
+namespace shlib {
+namespace test_utils {
+
+class WaitableEvent {
+ public:
+  WaitableEvent() = default;
+  void Notify() {
+    std::unique_lock<std::mutex> lock(m_);
+    notified_ = true;
+    cv_.notify_one();
+  }
+  bool WaitForNotification() {
+    std::unique_lock<std::mutex> lock(m_);
+    cv_.wait(lock, [this] { return notified_; });
+    return notified_;
+  }
+  bool IsNotified() {
+    std::unique_lock<std::mutex> lock(m_);
+    return notified_;
+  }
+
+ private:
+  std::mutex m_;
+  std::condition_variable cv_;
+  bool notified_ = false;
+};
+
+class TracingSession {
+ public:
+  class Builder {
+   public:
+    Builder() = default;
+    Builder& add_enabled_category(std::string category) {
+      enabled_categories_.push_back(std::move(category));
+      return *this;
+    }
+    Builder& add_disabled_category(std::string category) {
+      disabled_categories_.push_back(std::move(category));
+      return *this;
+    }
+    Builder& add_atrace_category(std::string category) {
+      atrace_categories_.push_back(std::move(category));
+      return *this;
+    }
+    Builder& add_atrace_category_prefer_sdk(std::string category) {
+      atrace_categories_prefer_sdk_.push_back(std::move(category));
+      return *this;
+    }
+    TracingSession Build();
+
+   private:
+    std::vector<std::string> enabled_categories_;
+    std::vector<std::string> disabled_categories_;
+    std::vector<std::string> atrace_categories_;
+    std::vector<std::string> atrace_categories_prefer_sdk_;
+  };
+
+  static TracingSession Adopt(struct PerfettoTracingSessionImpl*);
+  static TracingSession FromBytes(void *buf, size_t len);
+
+  TracingSession(TracingSession&&) noexcept;
+
+  ~TracingSession();
+
+  struct PerfettoTracingSessionImpl* session() const {
+    return session_;
+  }
+
+  bool FlushBlocking(uint32_t timeout_ms);
+  void WaitForStopped();
+  void StopBlocking();
+  std::vector<uint8_t> ReadBlocking();
+
+ private:
+  TracingSession() = default;
+  struct PerfettoTracingSessionImpl* session_;
+  std::unique_ptr<WaitableEvent> stopped_;
+};
+
+}  // namespace test_utils
+}  // namespace shlib
+}  // namespace perfetto
+
+#endif  // UTILS_H
diff --git a/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
index e9fee2e..b21a090 100644
--- a/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
+++ b/libs/tracing_perfetto/tests/tracing_perfetto_test.cpp
@@ -22,6 +22,7 @@
 #include <unistd.h>
 
 #include "gtest/gtest.h"
+
 #include "perfetto/public/abi/data_source_abi.h"
 #include "perfetto/public/abi/heap_buffer.h"
 #include "perfetto/public/abi/pb_decoder_abi.h"
diff --git a/libs/tracing_perfetto/tests/utils.cpp b/libs/tracing_perfetto/tests/utils.cpp
index 8c4d4a8..af61bc2 100644
--- a/libs/tracing_perfetto/tests/utils.cpp
+++ b/libs/tracing_perfetto/tests/utils.cpp
@@ -34,36 +34,17 @@
 namespace perfetto {
 namespace shlib {
 namespace test_utils {
-namespace {
-
-std::string ToHexChars(uint8_t val) {
-  std::string ret;
-  uint8_t high_nibble = (val & 0xF0) >> 4;
-  uint8_t low_nibble = (val & 0xF);
-  static const char hex_chars[] = "0123456789ABCDEF";
-  ret.push_back(hex_chars[high_nibble]);
-  ret.push_back(hex_chars[low_nibble]);
-  return ret;
-}
-
-}  // namespace
-
 TracingSession TracingSession::Builder::Build() {
   perfetto::protos::TraceConfig trace_config;
   trace_config.add_buffers()->set_size_kb(1024);
 
-  auto* track_event_ds_config = trace_config.add_data_sources()->mutable_config();
-  auto* ftrace_ds_config = trace_config.add_data_sources()->mutable_config();
-
-  track_event_ds_config->set_name("track_event");
-  track_event_ds_config->set_target_buffer(0);
-
-  ftrace_ds_config->set_name("linux.ftrace");
-  ftrace_ds_config->set_target_buffer(0);
-
   {
-    auto* ftrace_config = ftrace_ds_config->mutable_ftrace_config();
     if (!atrace_categories_.empty()) {
+      auto* ftrace_ds_config = trace_config.add_data_sources()->mutable_config();
+      ftrace_ds_config->set_name("linux.ftrace");
+      ftrace_ds_config->set_target_buffer(0);
+
+      auto* ftrace_config = ftrace_ds_config->mutable_ftrace_config();
       ftrace_config->add_ftrace_events("ftrace/print");
       for (const std::string& cat : atrace_categories_) {
         ftrace_config->add_atrace_categories(cat);
@@ -76,8 +57,14 @@
   }
 
   {
-    auto* track_event_config = track_event_ds_config->mutable_track_event_config();
     if (!enabled_categories_.empty() || !disabled_categories_.empty()) {
+      auto* track_event_ds_config = trace_config.add_data_sources()->mutable_config();
+
+      track_event_ds_config->set_name("track_event");
+      track_event_ds_config->set_target_buffer(0);
+
+      auto* track_event_config = track_event_ds_config->mutable_track_event_config();
+
       for (const std::string& cat : enabled_categories_) {
         track_event_config->add_enabled_categories(cat);
       }
@@ -88,13 +75,17 @@
     }
   }
 
-  struct PerfettoTracingSessionImpl* ts =
-      PerfettoTracingSessionCreate(PERFETTO_BACKEND_SYSTEM);
-
   std::string trace_config_string;
   trace_config.SerializeToString(&trace_config_string);
 
-  PerfettoTracingSessionSetup(ts, trace_config_string.data(), trace_config_string.length());
+  return TracingSession::FromBytes(trace_config_string.data(), trace_config_string.length());
+}
+
+TracingSession TracingSession::FromBytes(void *buf, size_t len) {
+  struct PerfettoTracingSessionImpl* ts =
+      PerfettoTracingSessionCreate(PERFETTO_BACKEND_SYSTEM);
+
+  PerfettoTracingSessionSetup(ts, buf, len);
 
   // Fails to start here
   PerfettoTracingSessionStartBlocking(ts);
@@ -177,39 +168,3 @@
 }  // namespace test_utils
 }  // namespace shlib
 }  // namespace perfetto
-
-void PrintTo(const PerfettoPbDecoderField& field, std::ostream* pos) {
-  std::ostream& os = *pos;
-  PerfettoPbDecoderStatus status =
-      static_cast<PerfettoPbDecoderStatus>(field.status);
-  switch (status) {
-    case PERFETTO_PB_DECODER_ERROR:
-      os << "MALFORMED PROTOBUF";
-      break;
-    case PERFETTO_PB_DECODER_DONE:
-      os << "DECODER DONE";
-      break;
-    case PERFETTO_PB_DECODER_OK:
-      switch (field.wire_type) {
-        case PERFETTO_PB_WIRE_TYPE_DELIMITED:
-          os << "\"";
-          for (size_t i = 0; i < field.value.delimited.len; i++) {
-            os << perfetto::shlib::test_utils::ToHexChars(
-                      field.value.delimited.start[i])
-               << " ";
-          }
-          os << "\"";
-          break;
-        case PERFETTO_PB_WIRE_TYPE_VARINT:
-          os << "varint: " << field.value.integer64;
-          break;
-        case PERFETTO_PB_WIRE_TYPE_FIXED32:
-          os << "fixed32: " << field.value.integer32;
-          break;
-        case PERFETTO_PB_WIRE_TYPE_FIXED64:
-          os << "fixed64: " << field.value.integer64;
-          break;
-      }
-      break;
-  }
-}
diff --git a/libs/tracing_perfetto/tests/utils.h b/libs/tracing_perfetto/tests/utils.h
deleted file mode 100644
index 8edb414..0000000
--- a/libs/tracing_perfetto/tests/utils.h
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright 2024 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.
- */
-
-// Copied from //external/perfetto/src/shared_lib/test/utils.h
-
-#ifndef UTILS_H
-#define UTILS_H
-
-#include <cassert>
-#include <condition_variable>
-#include <cstdint>
-#include <functional>
-#include <iterator>
-#include <memory>
-#include <mutex>
-#include <ostream>
-#include <string>
-#include <vector>
-
-#include "gmock/gmock-matchers.h"
-#include "gmock/gmock-more-matchers.h"
-#include "gtest/gtest-matchers.h"
-#include "gtest/gtest.h"
-#include "perfetto/public/abi/pb_decoder_abi.h"
-#include "perfetto/public/pb_utils.h"
-#include "perfetto/public/tracing_session.h"
-
-// Pretty printer for gtest
-void PrintTo(const PerfettoPbDecoderField& field, std::ostream*);
-
-namespace perfetto {
-namespace shlib {
-namespace test_utils {
-
-class WaitableEvent {
- public:
-  WaitableEvent() = default;
-  void Notify() {
-    std::unique_lock<std::mutex> lock(m_);
-    notified_ = true;
-    cv_.notify_one();
-  }
-  bool WaitForNotification() {
-    std::unique_lock<std::mutex> lock(m_);
-    cv_.wait(lock, [this] { return notified_; });
-    return notified_;
-  }
-  bool IsNotified() {
-    std::unique_lock<std::mutex> lock(m_);
-    return notified_;
-  }
-
- private:
-  std::mutex m_;
-  std::condition_variable cv_;
-  bool notified_ = false;
-};
-
-class TracingSession {
- public:
-  class Builder {
-   public:
-    Builder() = default;
-    Builder& add_enabled_category(std::string category) {
-      enabled_categories_.push_back(std::move(category));
-      return *this;
-    }
-    Builder& add_disabled_category(std::string category) {
-      disabled_categories_.push_back(std::move(category));
-      return *this;
-    }
-    Builder& add_atrace_category(std::string category) {
-      atrace_categories_.push_back(std::move(category));
-      return *this;
-    }
-    Builder& add_atrace_category_prefer_sdk(std::string category) {
-      atrace_categories_prefer_sdk_.push_back(std::move(category));
-      return *this;
-    }
-    TracingSession Build();
-
-   private:
-    std::vector<std::string> enabled_categories_;
-    std::vector<std::string> disabled_categories_;
-    std::vector<std::string> atrace_categories_;
-    std::vector<std::string> atrace_categories_prefer_sdk_;
-  };
-
-  static TracingSession Adopt(struct PerfettoTracingSessionImpl*);
-
-  TracingSession(TracingSession&&) noexcept;
-
-  ~TracingSession();
-
-  struct PerfettoTracingSessionImpl* session() const {
-    return session_;
-  }
-
-  bool FlushBlocking(uint32_t timeout_ms);
-  void WaitForStopped();
-  void StopBlocking();
-  std::vector<uint8_t> ReadBlocking();
-
- private:
-  TracingSession() = default;
-  struct PerfettoTracingSessionImpl* session_;
-  std::unique_ptr<WaitableEvent> stopped_;
-};
-
-template <typename FieldSkipper>
-class FieldViewBase {
- public:
-  class Iterator {
-   public:
-    using iterator_category = std::input_iterator_tag;
-    using value_type = const PerfettoPbDecoderField;
-    using pointer = value_type;
-    using reference = value_type;
-    reference operator*() const {
-      struct PerfettoPbDecoder decoder;
-      decoder.read_ptr = read_ptr_;
-      decoder.end_ptr = end_ptr_;
-      struct PerfettoPbDecoderField field;
-      do {
-        field = PerfettoPbDecoderParseField(&decoder);
-      } while (field.status == PERFETTO_PB_DECODER_OK &&
-               skipper_.ShouldSkip(field));
-      return field;
-    }
-    Iterator& operator++() {
-      struct PerfettoPbDecoder decoder;
-      decoder.read_ptr = read_ptr_;
-      decoder.end_ptr = end_ptr_;
-      PerfettoPbDecoderSkipField(&decoder);
-      read_ptr_ = decoder.read_ptr;
-      AdvanceToFirstInterestingField();
-      return *this;
-    }
-    Iterator operator++(int) {
-      Iterator tmp = *this;
-      ++(*this);
-      return tmp;
-    }
-
-    friend bool operator==(const Iterator& a, const Iterator& b) {
-      return a.read_ptr_ == b.read_ptr_;
-    }
-    friend bool operator!=(const Iterator& a, const Iterator& b) {
-      return a.read_ptr_ != b.read_ptr_;
-    }
-
-   private:
-    Iterator(const uint8_t* read_ptr, const uint8_t* end_ptr,
-             const FieldSkipper& skipper)
-        : read_ptr_(read_ptr), end_ptr_(end_ptr), skipper_(skipper) {
-      AdvanceToFirstInterestingField();
-    }
-    void AdvanceToFirstInterestingField() {
-      struct PerfettoPbDecoder decoder;
-      decoder.read_ptr = read_ptr_;
-      decoder.end_ptr = end_ptr_;
-      struct PerfettoPbDecoderField field;
-      const uint8_t* prev_read_ptr;
-      do {
-        prev_read_ptr = decoder.read_ptr;
-        field = PerfettoPbDecoderParseField(&decoder);
-      } while (field.status == PERFETTO_PB_DECODER_OK &&
-               skipper_.ShouldSkip(field));
-      if (field.status == PERFETTO_PB_DECODER_OK) {
-        read_ptr_ = prev_read_ptr;
-      } else {
-        read_ptr_ = decoder.read_ptr;
-      }
-    }
-    friend class FieldViewBase<FieldSkipper>;
-    const uint8_t* read_ptr_;
-    const uint8_t* end_ptr_;
-    const FieldSkipper& skipper_;
-  };
-  using value_type = const PerfettoPbDecoderField;
-  using const_iterator = Iterator;
-  template <typename... Args>
-  explicit FieldViewBase(const uint8_t* begin, const uint8_t* end, Args... args)
-      : begin_(begin), end_(end), s_(args...) {
-  }
-  template <typename... Args>
-  explicit FieldViewBase(const std::vector<uint8_t>& data, Args... args)
-      : FieldViewBase(data.data(), data.data() + data.size(), args...) {
-  }
-  template <typename... Args>
-  explicit FieldViewBase(const struct PerfettoPbDecoderField& field,
-                         Args... args)
-      : s_(args...) {
-    if (field.wire_type != PERFETTO_PB_WIRE_TYPE_DELIMITED) {
-      abort();
-    }
-    begin_ = field.value.delimited.start;
-    end_ = begin_ + field.value.delimited.len;
-  }
-  Iterator begin() const {
-    return Iterator(begin_, end_, s_);
-  }
-  Iterator end() const {
-    return Iterator(end_, end_, s_);
-  }
-  PerfettoPbDecoderField front() const {
-    return *begin();
-  }
-
-  size_t size() const {
-    size_t count = 0;
-    for (auto field : *this) {
-      (void)field;
-      count++;
-    }
-    return count;
-  }
-
-  bool ok() const {
-    for (auto field : *this) {
-      if (field.status != PERFETTO_PB_DECODER_OK) {
-        return false;
-      }
-    }
-    return true;
-  }
-
- private:
-  const uint8_t* begin_;
-  const uint8_t* end_;
-  FieldSkipper s_;
-};
-
-// Pretty printer for gtest
-template <typename FieldSkipper>
-void PrintTo(const FieldViewBase<FieldSkipper>& field_view, std::ostream* pos) {
-  std::ostream& os = *pos;
-  os << "{";
-  for (PerfettoPbDecoderField f : field_view) {
-    PrintTo(f, pos);
-    os << ", ";
-  }
-  os << "}";
-}
-
-class IdFieldSkipper {
- public:
-  explicit IdFieldSkipper(uint32_t id) : id_(id) {
-  }
-  explicit IdFieldSkipper(int32_t id) : id_(static_cast<uint32_t>(id)) {
-  }
-  bool ShouldSkip(const struct PerfettoPbDecoderField& field) const {
-    return field.id != id_;
-  }
-
- private:
-  uint32_t id_;
-};
-
-class NoFieldSkipper {
- public:
-  NoFieldSkipper() = default;
-  bool ShouldSkip(const struct PerfettoPbDecoderField&) const {
-    return false;
-  }
-};
-
-// View over all the fields of a contiguous serialized protobuf message.
-//
-// Examples:
-//
-// for (struct PerfettoPbDecoderField field : FieldView(msg_begin, msg_end)) {
-//   //...
-// }
-// FieldView fields2(/*PerfettoPbDecoderField*/ nested_field);
-// FieldView fields3(/*std::vector<uint8_t>*/ data);
-// size_t num = fields1.size(); // The number of fields.
-// bool ok = fields1.ok(); // Checks that the message is not malformed.
-using FieldView = FieldViewBase<NoFieldSkipper>;
-
-// Like `FieldView`, but only considers fields with a specific id.
-//
-// Examples:
-//
-// IdFieldView fields(msg_begin, msg_end, id)
-using IdFieldView = FieldViewBase<IdFieldSkipper>;
-
-// Matches a PerfettoPbDecoderField with the specified id. Accepts another
-// matcher to match the contents of the field.
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, PbField(900, VarIntField(5)));
-template <typename M>
-auto PbField(int32_t id, M m) {
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::id, id), m);
-}
-
-// Matches a PerfettoPbDecoderField submessage field. Accepts a container
-// matcher for the subfields.
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, MsgField(ElementsAre(...)));
-template <typename M>
-auto MsgField(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) { return FieldView(field); };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_DELIMITED),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField length delimited field. Accepts a string
-// matcher.
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, StringField("string"));
-template <typename M>
-auto StringField(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) {
-    return std::string(
-        reinterpret_cast<const char*>(field.value.delimited.start),
-        field.value.delimited.len);
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_DELIMITED),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField VarInt field. Accepts an integer matcher
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, VarIntField(1)));
-template <typename M>
-auto VarIntField(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) {
-    return field.value.integer64;
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_VARINT),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField fixed64 field. Accepts an integer matcher
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, Fixed64Field(1)));
-template <typename M>
-auto Fixed64Field(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) {
-    return field.value.integer64;
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_FIXED64),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField fixed32 field. Accepts an integer matcher
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, Fixed32Field(1)));
-template <typename M>
-auto Fixed32Field(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) {
-    return field.value.integer32;
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_FIXED32),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField double field. Accepts a double matcher
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, DoubleField(1.0)));
-template <typename M>
-auto DoubleField(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) {
-    return field.value.double_val;
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_FIXED64),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField float field. Accepts a float matcher
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, FloatField(1.0)));
-template <typename M>
-auto FloatField(M m) {
-  auto f = [](const PerfettoPbDecoderField& field) {
-    return field.value.float_val;
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_FIXED32),
-      testing::ResultOf(f, m));
-}
-
-// Matches a PerfettoPbDecoderField submessage field. Accepts a container
-// matcher for the subfields.
-//
-// Example:
-// PerfettoPbDecoderField field = ...
-// EXPECT_THAT(field, AllFieldsWithId(900, ElementsAre(...)));
-template <typename M>
-auto AllFieldsWithId(int32_t id, M m) {
-  auto f = [id](const PerfettoPbDecoderField& field) {
-    return IdFieldView(field, id);
-  };
-  return testing::AllOf(
-      testing::Field(&PerfettoPbDecoderField::status, PERFETTO_PB_DECODER_OK),
-      testing::Field(&PerfettoPbDecoderField::wire_type,
-                     PERFETTO_PB_WIRE_TYPE_DELIMITED),
-      testing::ResultOf(f, m));
-}
-
-}  // namespace test_utils
-}  // namespace shlib
-}  // namespace perfetto
-
-#endif  // UTILS_H
diff --git a/libs/tracing_perfetto/tracing_perfetto.cpp b/libs/tracing_perfetto/tracing_perfetto.cpp
index c35e078..4b70213 100644
--- a/libs/tracing_perfetto/tracing_perfetto.cpp
+++ b/libs/tracing_perfetto/tracing_perfetto.cpp
@@ -17,6 +17,7 @@
 #include "tracing_perfetto.h"
 
 #include <cutils/trace.h>
+
 #include <cstdarg>
 
 #include "perfetto/public/te_category_macros.h"
@@ -43,8 +44,10 @@
 void traceFormatBegin(uint64_t category, const char* fmt, ...) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  const bool preferAtrace = internal::shouldPreferAtrace(perfettoTeCategory, category);
-  const bool preferPerfetto = internal::isPerfettoCategoryEnabled(perfettoTeCategory);
+  const bool preferAtrace =
+      internal::shouldPreferAtrace(perfettoTeCategory, category);
+  const bool preferPerfetto =
+      internal::isPerfettoCategoryEnabled(perfettoTeCategory);
   if (CC_LIKELY(!(preferAtrace || preferPerfetto))) {
     return;
   }
@@ -57,7 +60,6 @@
   vsnprintf(buf, BUFFER_SIZE, fmt, ap);
   va_end(ap);
 
-
   if (preferAtrace) {
     atrace_begin(category, buf);
   } else if (preferPerfetto) {
@@ -99,26 +101,28 @@
 }
 
 void traceAsyncBeginForTrack(uint64_t category, const char* name,
-                               const char* trackName, int32_t cookie) {
+                             const char* trackName, int32_t cookie) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
 
   if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_async_for_track_begin(category, trackName, name, cookie);
   } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
-    internal::perfettoTraceAsyncBeginForTrack(*perfettoTeCategory, name, trackName, cookie);
+    internal::perfettoTraceAsyncBeginForTrack(*perfettoTeCategory, name,
+                                              trackName, cookie);
   }
 }
 
 void traceAsyncEndForTrack(uint64_t category, const char* trackName,
-                             int32_t cookie) {
+                           int32_t cookie) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
 
   if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_async_for_track_end(category, trackName, cookie);
   } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
-    internal::perfettoTraceAsyncEndForTrack(*perfettoTeCategory, trackName, cookie);
+    internal::perfettoTraceAsyncEndForTrack(*perfettoTeCategory, trackName,
+                                            cookie);
   }
 }
 
@@ -136,8 +140,10 @@
 void traceFormatInstant(uint64_t category, const char* fmt, ...) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  const bool preferAtrace = internal::shouldPreferAtrace(perfettoTeCategory, category);
-  const bool preferPerfetto = internal::isPerfettoCategoryEnabled(perfettoTeCategory);
+  const bool preferAtrace =
+      internal::shouldPreferAtrace(perfettoTeCategory, category);
+  const bool preferPerfetto =
+      internal::isPerfettoCategoryEnabled(perfettoTeCategory);
   if (CC_LIKELY(!(preferAtrace || preferPerfetto))) {
     return;
   }
@@ -158,7 +164,7 @@
 }
 
 void traceInstantForTrack(uint64_t category, const char* trackName,
-                            const char* name) {
+                          const char* name) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
 
@@ -181,20 +187,21 @@
 }
 
 void traceCounter32(uint64_t category, const char* name, int32_t value) {
-  struct PerfettoTeCategory* perfettoTeCategory = internal::toPerfettoCategory(category);
+  struct PerfettoTeCategory* perfettoTeCategory =
+      internal::toPerfettoCategory(category);
   if (internal::shouldPreferAtrace(perfettoTeCategory, category)) {
     atrace_int(category, name, value);
   } else if (internal::isPerfettoCategoryEnabled(perfettoTeCategory)) {
     internal::perfettoTraceCounter(*perfettoTeCategory, name,
-                                          static_cast<int64_t>(value));
+                                   static_cast<int64_t>(value));
   }
 }
 
 bool isTagEnabled(uint64_t category) {
   struct PerfettoTeCategory* perfettoTeCategory =
       internal::toPerfettoCategory(category);
-  return internal::isPerfettoCategoryEnabled(perfettoTeCategory)
-      || atrace_is_tag_enabled(category);
+  return internal::isPerfettoCategoryEnabled(perfettoTeCategory) ||
+         atrace_is_tag_enabled(category);
 }
 
 }  // namespace tracing_perfetto
diff --git a/libs/tracing_perfetto/tracing_sdk.cpp b/libs/tracing_perfetto/tracing_sdk.cpp
new file mode 100644
index 0000000..02e8d10
--- /dev/null
+++ b/libs/tracing_perfetto/tracing_sdk.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2024 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 "tracing_sdk.h"
+
+#include <android-base/logging.h>
+#include <cutils/trace.h>
+
+#include <cstdarg>
+#include <cstdlib>
+
+#include "perfetto/public/abi/producer_abi.h"
+#include "perfetto/public/te_category_macros.h"
+#include "perfetto/public/te_macros.h"
+#include "perfetto/public/track_event.h"
+#include "tracing_perfetto.h"
+
+namespace tracing_perfetto {
+void trace_event(int type, const PerfettoTeCategory* perfettoTeCategory,
+                 const char* name, tracing_perfetto::Extra* extra) {
+  bool enabled = PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
+      perfettoTeCategory->enabled, PERFETTO_MEMORY_ORDER_RELAXED));
+  if (enabled) {
+    extra->push_extra(nullptr);
+    PerfettoTeHlEmitImpl(perfettoTeCategory->impl, type,
+                         type == PERFETTO_TE_TYPE_COUNTER ? nullptr : name,
+                         extra->get());
+    extra->pop_extra();
+  }
+}
+
+uint64_t get_process_track_uuid() {
+  return PerfettoTeProcessTrackUuid();
+}
+
+uint64_t get_thread_track_uuid(pid_t tid) {
+  // Cating a signed pid_t to unsigned
+  return PerfettoTeProcessTrackUuid() ^ PERFETTO_STATIC_CAST(uint64_t, tid);
+}
+
+Extra::Extra() {
+}
+
+void Extra::push_extra(PerfettoTeHlExtra* ptr) {
+  extras_.push_back(ptr);
+}
+
+void Extra::pop_extra() {
+  extras_.pop_back();
+}
+
+void Extra::clear_extras() {
+  extras_.clear();
+}
+
+void Extra::delete_extra(Extra* ptr) {
+  delete ptr;
+}
+
+PerfettoTeHlExtra* const* Extra::get() const {
+  return extras_.data();
+}
+
+Category::Category(const std::string& name, const std::string& tag,
+                   const std::string& severity)
+    : category_({.enabled = &perfetto_atomic_false}),
+      name_(name),
+      tag_(tag),
+      severity_(severity) {
+}
+
+Category::~Category() {
+  unregister_category();
+}
+
+void Category::register_category() {
+  if (category_.impl) return;
+
+  std::vector<const char*> tags;
+  if (!tag_.empty()) tags.push_back(tag_.data());
+  if (!severity_.empty()) tags.push_back(severity_.data());
+
+  category_.desc = {name_.c_str(), name_.c_str(), tags.data(), tags.size()};
+
+  PerfettoTeCategoryRegister(&category_);
+  PerfettoTePublishCategories();
+}
+
+void Category::unregister_category() {
+  if (!category_.impl) return;
+
+  PerfettoTeCategoryUnregister(&category_);
+  PerfettoTePublishCategories();
+}
+
+bool Category::is_category_enabled() {
+  return PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT(
+      (category_).enabled, PERFETTO_MEMORY_ORDER_RELAXED));
+}
+
+const PerfettoTeCategory* Category::get() const {
+  return &category_;
+}
+
+void Category::delete_category(Category* ptr) {
+  delete ptr;
+}
+
+Flow::Flow() : flow_{} {
+}
+
+void Flow::set_process_flow(uint64_t id) {
+  flow_.header.type = PERFETTO_TE_HL_EXTRA_TYPE_FLOW;
+  PerfettoTeFlow ret = PerfettoTeProcessScopedFlow(id);
+  flow_.id = ret.id;
+}
+
+void Flow::set_process_terminating_flow(uint64_t id) {
+  flow_.header.type = PERFETTO_TE_HL_EXTRA_TYPE_TERMINATING_FLOW;
+  PerfettoTeFlow ret = PerfettoTeProcessScopedFlow(id);
+  flow_.id = ret.id;
+}
+
+const PerfettoTeHlExtraFlow* Flow::get() const {
+  return &flow_;
+}
+
+void Flow::delete_flow(Flow* ptr) {
+  delete ptr;
+}
+
+NamedTrack::NamedTrack(uint64_t id, uint64_t parent_uuid,
+                       const std::string& name)
+    : name_(name),
+      track_{{PERFETTO_TE_HL_EXTRA_TYPE_NAMED_TRACK},
+             name_.data(),
+             id,
+             parent_uuid} {
+}
+
+const PerfettoTeHlExtraNamedTrack* NamedTrack::get() const {
+  return &track_;
+}
+
+void NamedTrack::delete_track(NamedTrack* ptr) {
+  delete ptr;
+}
+
+RegisteredTrack::RegisteredTrack(uint64_t id, uint64_t parent_uuid,
+                                 const std::string& name, bool is_counter)
+    : registered_track_{},
+      track_{{PERFETTO_TE_HL_EXTRA_TYPE_REGISTERED_TRACK},
+             &(registered_track_.impl)},
+      name_(name),
+      id_(id),
+      parent_uuid_(parent_uuid),
+      is_counter_(is_counter) {
+  register_track();
+}
+
+RegisteredTrack::~RegisteredTrack() {
+  unregister_track();
+}
+
+void RegisteredTrack::register_track() {
+  if (registered_track_.impl.descriptor) return;
+
+  if (is_counter_) {
+    PerfettoTeCounterTrackRegister(&registered_track_, name_.data(),
+                                   parent_uuid_);
+  } else {
+    PerfettoTeNamedTrackRegister(&registered_track_, name_.data(), id_,
+                                 parent_uuid_);
+  }
+}
+
+void RegisteredTrack::unregister_track() {
+  if (!registered_track_.impl.descriptor) return;
+  PerfettoTeRegisteredTrackUnregister(&registered_track_);
+}
+
+const PerfettoTeHlExtraRegisteredTrack* RegisteredTrack::get() const {
+  return &track_;
+}
+
+void RegisteredTrack::delete_track(RegisteredTrack* ptr) {
+  delete ptr;
+}
+
+Proto::Proto() : proto_({PERFETTO_TE_HL_EXTRA_TYPE_PROTO_FIELDS}, nullptr) {
+}
+
+void Proto::add_field(PerfettoTeHlProtoField* ptr) {
+  if (!fields_.empty()) {
+    fields_.pop_back();
+  }
+
+  fields_.push_back(ptr);
+  fields_.push_back(nullptr);
+  proto_.fields = fields_.data();
+}
+
+void Proto::clear_fields() {
+  fields_.clear();
+  proto_.fields = nullptr;
+}
+
+void Proto::delete_proto(Proto* ptr) {
+  delete ptr;
+}
+
+const PerfettoTeHlExtraProtoFields* Proto::get() const {
+  return &proto_;
+}
+
+ProtoFieldNested::ProtoFieldNested()
+    : field_({PERFETTO_TE_HL_PROTO_TYPE_NESTED}, nullptr) {
+}
+
+void ProtoFieldNested::add_field(PerfettoTeHlProtoField* ptr) {
+  if (!fields_.empty()) {
+    fields_.pop_back();
+  }
+
+  fields_.push_back(ptr);
+  fields_.push_back(nullptr);
+  field_.fields = fields_.data();
+}
+
+void ProtoFieldNested::set_id(uint32_t id) {
+  fields_.clear();
+  field_.header.id = id;
+  field_.fields = nullptr;
+}
+
+void ProtoFieldNested::delete_field(ProtoFieldNested* ptr) {
+  delete ptr;
+}
+
+const PerfettoTeHlProtoFieldNested* ProtoFieldNested::get() const {
+  return &field_;
+}
+
+void activate_trigger(const char* name, uint32_t ttl_ms) {
+  const char* names[] = {name, nullptr};
+  PerfettoProducerActivateTriggers(names, ttl_ms);
+}
+}  // namespace tracing_perfetto
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index cd4ed5c..e6221f6 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1128,7 +1128,7 @@
     if (connection->monitor) {
         return mMonitorDispatchingTimeout;
     }
-    const sp<WindowInfoHandle> window = getWindowHandleLocked(connection->getToken());
+    const sp<WindowInfoHandle> window = mWindowInfos.findWindowHandle(connection->getToken());
     if (window != nullptr) {
         return window->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
     }
@@ -1333,7 +1333,7 @@
         const bool isStylus = isPointerFromStylus(motionEntry, /*pointerIndex=*/0);
 
         sp<WindowInfoHandle> touchedWindowHandle =
-                findTouchedWindowAtLocked(displayId, x, y, isStylus);
+                mWindowInfos.findTouchedWindowAt(displayId, x, y, isStylus);
         if (touchedWindowHandle != nullptr &&
             touchedWindowHandle->getApplicationToken() !=
                     mAwaitedFocusedApplication->getApplicationToken()) {
@@ -1452,19 +1452,19 @@
     }
 }
 
-sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(ui::LogicalDisplayId displayId,
-                                                                float x, float y, bool isStylus,
-                                                                bool ignoreDragWindow) const {
+sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findTouchedWindowAt(
+        ui::LogicalDisplayId displayId, float x, float y, bool isStylus,
+        const sp<android::gui::WindowInfoHandle> ignoreWindow) const {
     // Traverse windows from front to back to find touched window.
-    const auto& windowHandles = getWindowHandlesLocked(displayId);
+    const auto& windowHandles = getWindowHandlesForDisplay(displayId);
     for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
-        if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) {
+        if (ignoreWindow && haveSameToken(windowHandle, ignoreWindow)) {
             continue;
         }
 
         const WindowInfo& info = *windowHandle->getInfo();
         if (!info.isSpy() &&
-            windowAcceptsTouchAt(info, displayId, x, y, isStylus, getTransformLocked(displayId))) {
+            windowAcceptsTouchAt(info, displayId, x, y, isStylus, getDisplayTransform(displayId))) {
             return windowHandle;
         }
     }
@@ -1479,7 +1479,7 @@
     }
     // Traverse windows from front to back until we encounter the touched window.
     std::vector<InputTarget> outsideTargets;
-    const auto& windowHandles = getWindowHandlesLocked(displayId);
+    const auto& windowHandles = mWindowInfos.getWindowHandlesForDisplay(displayId);
     for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
         if (windowHandle == touchedWindow) {
             // Stop iterating once we found a touched window. Any WATCH_OUTSIDE_TOUCH window
@@ -1503,10 +1503,11 @@
         ui::LogicalDisplayId displayId, float x, float y, bool isStylus, DeviceId deviceId) const {
     // Traverse windows from front to back and gather the touched spy windows.
     std::vector<sp<WindowInfoHandle>> spyWindows;
-    const auto& windowHandles = getWindowHandlesLocked(displayId);
+    const auto& windowHandles = mWindowInfos.getWindowHandlesForDisplay(displayId);
     for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
         const WindowInfo& info = *windowHandle->getInfo();
-        if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus, getTransformLocked(displayId))) {
+        if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus,
+                                  mWindowInfos.getDisplayTransform(displayId))) {
             // Generally, we would skip any pointer that's outside of the window. However, if the
             // spy prevents splitting, and already has some of the pointers from this device, then
             // it should get more pointers from the same device, even if they are outside of that
@@ -1828,7 +1829,7 @@
 void InputDispatcher::dispatchTouchModeChangeLocked(
         nsecs_t currentTime, const std::shared_ptr<const TouchModeEntry>& entry) {
     const std::vector<sp<WindowInfoHandle>>& windowHandles =
-            getWindowHandlesLocked(entry->displayId);
+            mWindowInfos.getWindowHandlesForDisplay(entry->displayId);
     if (windowHandles.empty()) {
         return;
     }
@@ -2216,7 +2217,7 @@
 
     sp<WindowInfoHandle> windowHandle;
     if (!connection->monitor) {
-        windowHandle = getWindowHandleLocked(connection->getToken());
+        windowHandle = mWindowInfos.findWindowHandle(connection->getToken());
         if (windowHandle == nullptr) {
             // The window that is receiving this ANR was removed, so there is no need to generate
             // cancellations, because the cancellations would have already been generated when
@@ -2472,7 +2473,7 @@
         // be a pointer that would generate ACTION_DOWN, *and* touch should not already be down.
         const bool isStylus = isPointerFromStylus(entry, pointerIndex);
         sp<WindowInfoHandle> newTouchedWindowHandle =
-                findTouchedWindowAtLocked(displayId, x, y, isStylus);
+                mWindowInfos.findTouchedWindowAt(displayId, x, y, isStylus);
 
         if (isDown) {
             targets += findOutsideTargetsLocked(displayId, newTouchedWindowHandle, pointer.id);
@@ -2655,7 +2656,7 @@
                     tempTouchState.getFirstForegroundWindowHandle(entry.deviceId);
             LOG_ALWAYS_FATAL_IF(oldTouchedWindowHandle == nullptr);
             sp<WindowInfoHandle> newTouchedWindowHandle =
-                    findTouchedWindowAtLocked(displayId, x, y, isStylus);
+                    mWindowInfos.findTouchedWindowAt(displayId, x, y, isStylus);
 
             // Verify targeted injection.
             if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
@@ -2779,7 +2780,7 @@
             for (InputTarget& target : targets) {
                 if (target.dispatchMode == InputTarget::DispatchMode::OUTSIDE) {
                     sp<WindowInfoHandle> targetWindow =
-                            getWindowHandleLocked(target.connection->getToken());
+                            mWindowInfos.findWindowHandle(target.connection->getToken());
                     if (targetWindow->getInfo()->ownerUid != foregroundWindowUid) {
                         target.flags |= InputTarget::Flags::ZERO_COORDS;
                     }
@@ -2879,7 +2880,8 @@
     constexpr bool isStylus = false;
 
     sp<WindowInfoHandle> dropWindow =
-            findTouchedWindowAtLocked(displayId, x, y, isStylus, /*ignoreDragWindow=*/true);
+            mWindowInfos.findTouchedWindowAt(displayId, x, y, isStylus, /*ignoreWindow=*/
+                                             mDragState->dragWindow);
     if (dropWindow) {
         vec2 local = dropWindow->getInfo()->transform.transform(x, y);
         sendDropWindowCommandLocked(dropWindow->getToken(), local.x, local.y);
@@ -2934,8 +2936,8 @@
             constexpr bool isStylus = false;
 
             sp<WindowInfoHandle> hoverWindowHandle =
-                    findTouchedWindowAtLocked(entry.displayId, x, y, isStylus,
-                                              /*ignoreDragWindow=*/true);
+                    mWindowInfos.findTouchedWindowAt(entry.displayId, x, y, isStylus,
+                                                     /*ignoreWindow=*/mDragState->dragWindow);
             // enqueue drag exit if needed.
             if (hoverWindowHandle != mDragState->dragHoverWindowHandle &&
                 !haveSameToken(hoverWindowHandle, mDragState->dragHoverWindowHandle)) {
@@ -2985,13 +2987,8 @@
     inputTarget.flags = targetFlags;
     inputTarget.globalScaleFactor = windowHandle->getInfo()->globalScaleFactor;
     inputTarget.firstDownTimeInTarget = firstDownTimeInTarget;
-    const auto& displayInfoIt = mDisplayInfos.find(windowHandle->getInfo()->displayId);
-    if (displayInfoIt != mDisplayInfos.end()) {
-        inputTarget.displayTransform = displayInfoIt->second.transform;
-    } else {
-        // DisplayInfo not found for this window on display windowHandle->getInfo()->displayId.
-        // TODO(b/198444055): Make this an error message after 'setInputWindows' API is removed.
-    }
+    inputTarget.displayTransform =
+            mWindowInfos.getDisplayTransform(windowHandle->getInfo()->displayId);
     return inputTarget;
 }
 
@@ -3099,9 +3096,7 @@
         InputTarget target{monitor.connection};
         // target.firstDownTimeInTarget is not set for global monitors. It is only required in split
         // touch and global monitoring works as intended even without setting firstDownTimeInTarget
-        if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
-            target.displayTransform = it->second.transform;
-        }
+        target.displayTransform = mWindowInfos.getDisplayTransform(displayId);
         target.setDefaultPointerTransform(target.displayTransform);
         inputTargets.push_back(target);
     }
@@ -3164,7 +3159,8 @@
         const sp<WindowInfoHandle>& windowHandle, float x, float y) const {
     const WindowInfo* windowInfo = windowHandle->getInfo();
     ui::LogicalDisplayId displayId = windowInfo->displayId;
-    const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
+    const std::vector<sp<WindowInfoHandle>>& windowHandles =
+            mWindowInfos.getWindowHandlesForDisplay(displayId);
     TouchOcclusionInfo info;
     info.hasBlockingOcclusion = false;
     info.obscuringOpacity = 0;
@@ -3176,7 +3172,8 @@
         }
         const WindowInfo* otherInfo = otherHandle->getInfo();
         if (canBeObscuredBy(windowHandle, otherHandle) &&
-            windowOccludesTouchAt(*otherInfo, displayId, x, y, getTransformLocked(displayId)) &&
+            windowOccludesTouchAt(*otherInfo, displayId, x, y,
+                                  mWindowInfos.getDisplayTransform(displayId)) &&
             !haveSameApplicationToken(windowInfo, otherInfo)) {
             if (DEBUG_TOUCH_OCCLUSION) {
                 info.debugInfo.push_back(
@@ -3248,14 +3245,16 @@
 bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<WindowInfoHandle>& windowHandle,
                                                     float x, float y) const {
     ui::LogicalDisplayId displayId = windowHandle->getInfo()->displayId;
-    const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
+    const std::vector<sp<WindowInfoHandle>>& windowHandles =
+            mWindowInfos.getWindowHandlesForDisplay(displayId);
     for (const sp<WindowInfoHandle>& otherHandle : windowHandles) {
         if (windowHandle == otherHandle) {
             break; // All future windows are below us. Exit early.
         }
         const WindowInfo* otherInfo = otherHandle->getInfo();
         if (canBeObscuredBy(windowHandle, otherHandle) &&
-            windowOccludesTouchAt(*otherInfo, displayId, x, y, getTransformLocked(displayId))) {
+            windowOccludesTouchAt(*otherInfo, displayId, x, y,
+                                  mWindowInfos.getDisplayTransform(displayId))) {
             return true;
         }
     }
@@ -3264,7 +3263,8 @@
 
 bool InputDispatcher::isWindowObscuredLocked(const sp<WindowInfoHandle>& windowHandle) const {
     ui::LogicalDisplayId displayId = windowHandle->getInfo()->displayId;
-    const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
+    const std::vector<sp<WindowInfoHandle>>& windowHandles =
+            mWindowInfos.getWindowHandlesForDisplay(displayId);
     const WindowInfo* windowInfo = windowHandle->getInfo();
     for (const sp<WindowInfoHandle>& otherHandle : windowHandles) {
         if (windowHandle == otherHandle) {
@@ -4118,7 +4118,8 @@
     } else {
         // Monitor channels are never explicitly unregistered.
         // We do it automatically when the remote endpoint is closed so don't warn about them.
-        const bool stillHaveWindowHandle = getWindowHandleLocked(connection->getToken()) != nullptr;
+        const bool stillHaveWindowHandle =
+                mWindowInfos.findWindowHandle(connection->getToken()) != nullptr;
         notify = !connection->monitor && stillHaveWindowHandle;
         if (notify) {
             ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred.  events=0x%x",
@@ -4153,11 +4154,11 @@
     // Follow up by generating cancellations for all windows, because we don't explicitly track
     // the windows that have an ongoing focus event stream.
     if (cancelNonPointers) {
-        for (const auto& [_, handles] : mWindowHandlesByDisplay) {
-            for (const auto& windowHandle : handles) {
-                synthesizeCancelationEventsForWindowLocked(windowHandle, options);
-            }
-        }
+        mWindowInfos.forEachWindowHandle(
+                [&](const sp<android::gui::WindowInfoHandle>& windowHandle) {
+                    base::ScopedLockAssertion assumeLocked(mLock);
+                    synthesizeCancelationEventsForWindowLocked(windowHandle, options);
+                });
     }
 
     // Cancel monitors.
@@ -4281,11 +4282,10 @@
                                                  motionEntry.downTime, targets);
                 } else {
                     targets.emplace_back(fallbackTarget);
-                    const auto it = mDisplayInfos.find(motionEntry.displayId);
-                    if (it != mDisplayInfos.end()) {
-                        targets.back().displayTransform = it->second.transform;
-                        targets.back().setDefaultPointerTransform(it->second.transform);
-                    }
+                    const ui::Transform displayTransform =
+                            mWindowInfos.getDisplayTransform(motionEntry.displayId);
+                    targets.back().displayTransform = displayTransform;
+                    targets.back().setDefaultPointerTransform(displayTransform);
                 }
                 logOutboundMotionDetails("cancel - ", motionEntry);
                 break;
@@ -4367,11 +4367,10 @@
                                                  targets);
                 } else {
                     targets.emplace_back(connection, targetFlags);
-                    const auto it = mDisplayInfos.find(motionEntry.displayId);
-                    if (it != mDisplayInfos.end()) {
-                        targets.back().displayTransform = it->second.transform;
-                        targets.back().setDefaultPointerTransform(it->second.transform);
-                    }
+                    const ui::Transform displayTransform =
+                            mWindowInfos.getDisplayTransform(motionEntry.displayId);
+                    targets.back().displayTransform = displayTransform;
+                    targets.back().setDefaultPointerTransform(displayTransform);
                 }
                 logOutboundMotionDetails("down - ", motionEntry);
                 break;
@@ -4642,10 +4641,7 @@
         }
 
         if (shouldSendMotionToInputFilterLocked(args)) {
-            ui::Transform displayTransform;
-            if (const auto it = mDisplayInfos.find(args.displayId); it != mDisplayInfos.end()) {
-                displayTransform = it->second.transform;
-            }
+            ui::Transform displayTransform = mWindowInfos.getDisplayTransform(args.displayId);
 
             mLock.unlock();
 
@@ -5149,9 +5145,8 @@
         MotionEntry& entry, const ui::Transform& injectedTransform) const {
     // Input injection works in the logical display coordinate space, but the input pipeline works
     // display space, so we need to transform the injected events accordingly.
-    const auto it = mDisplayInfos.find(entry.displayId);
-    if (it == mDisplayInfos.end()) return;
-    const auto& transformToDisplay = it->second.transform.inverse() * injectedTransform;
+    const ui::Transform displayTransform = mWindowInfos.getDisplayTransform(entry.displayId);
+    const auto& transformToDisplay = displayTransform.inverse() * injectedTransform;
 
     if (entry.xCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION &&
         entry.yCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION) {
@@ -5184,14 +5179,7 @@
     }
 }
 
-const std::vector<sp<WindowInfoHandle>>& InputDispatcher::getWindowHandlesLocked(
-        ui::LogicalDisplayId displayId) const {
-    static const std::vector<sp<WindowInfoHandle>> EMPTY_WINDOW_HANDLES;
-    auto it = mWindowHandlesByDisplay.find(displayId);
-    return it != mWindowHandlesByDisplay.end() ? it->second : EMPTY_WINDOW_HANDLES;
-}
-
-sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked(
+sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findWindowHandle(
         const sp<IBinder>& windowHandleToken, std::optional<ui::LogicalDisplayId> displayId) const {
     if (windowHandleToken == nullptr) {
         return nullptr;
@@ -5210,7 +5198,7 @@
     }
 
     // Only look through the requested display.
-    for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesLocked(*displayId)) {
+    for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesForDisplay(*displayId)) {
         if (windowHandle->getToken() == windowHandleToken) {
             return windowHandle;
         }
@@ -5218,7 +5206,7 @@
     return nullptr;
 }
 
-sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked(
+bool InputDispatcher::DispatcherWindowInfo::isWindowPresent(
         const sp<WindowInfoHandle>& windowHandle) const {
     for (const auto& [displayId, windowHandles] : mWindowHandlesByDisplay) {
         for (const sp<WindowInfoHandle>& handle : windowHandles) {
@@ -5230,25 +5218,98 @@
                           windowHandle->getName().c_str(), displayId.toString().c_str(),
                           windowHandle->getInfo()->displayId.toString().c_str());
                 }
-                return handle;
+                return true;
             }
         }
     }
-    return nullptr;
+    return false;
 }
 
 sp<WindowInfoHandle> InputDispatcher::getFocusedWindowHandleLocked(
         ui::LogicalDisplayId displayId) const {
     sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(displayId);
-    return getWindowHandleLocked(focusedToken, displayId);
+    return mWindowInfos.findWindowHandle(focusedToken, displayId);
 }
 
-ui::Transform InputDispatcher::getTransformLocked(ui::LogicalDisplayId displayId) const {
+void InputDispatcher::DispatcherWindowInfo::setWindowHandlesForDisplay(
+        ui::LogicalDisplayId displayId, std::vector<sp<WindowInfoHandle>>&& windowHandles) {
+    // Insert or replace
+    mWindowHandlesByDisplay[displayId] = std::move(windowHandles);
+}
+
+void InputDispatcher::DispatcherWindowInfo::setDisplayInfos(
+        const std::vector<android::gui::DisplayInfo>& displayInfos) {
+    mDisplayInfos.clear();
+    for (const auto& displayInfo : displayInfos) {
+        mDisplayInfos.emplace(displayInfo.displayId, displayInfo);
+    }
+}
+
+void InputDispatcher::DispatcherWindowInfo::removeDisplay(ui::LogicalDisplayId displayId) {
+    mWindowHandlesByDisplay.erase(displayId);
+}
+
+const std::vector<sp<android::gui::WindowInfoHandle>>&
+InputDispatcher::DispatcherWindowInfo::getWindowHandlesForDisplay(
+        ui::LogicalDisplayId displayId) const {
+    static const std::vector<sp<WindowInfoHandle>> EMPTY_WINDOW_HANDLES;
+    const auto it = mWindowHandlesByDisplay.find(displayId);
+    return it != mWindowHandlesByDisplay.end() ? it->second : EMPTY_WINDOW_HANDLES;
+}
+
+void InputDispatcher::DispatcherWindowInfo::forEachWindowHandle(
+        std::function<void(const sp<android::gui::WindowInfoHandle>&)> f) const {
+    for (const auto& [_, windowHandles] : mWindowHandlesByDisplay) {
+        for (const auto& windowHandle : windowHandles) {
+            f(windowHandle);
+        }
+    }
+}
+
+void InputDispatcher::DispatcherWindowInfo::forEachDisplayId(
+        std::function<void(ui::LogicalDisplayId)> f) const {
+    for (const auto& [displayId, _] : mWindowHandlesByDisplay) {
+        f(displayId);
+    }
+}
+
+ui::Transform InputDispatcher::DispatcherWindowInfo::getDisplayTransform(
+        ui::LogicalDisplayId displayId) const {
     auto displayInfoIt = mDisplayInfos.find(displayId);
     return displayInfoIt != mDisplayInfos.end() ? displayInfoIt->second.transform
                                                 : kIdentityTransform;
 }
 
+std::string InputDispatcher::DispatcherWindowInfo::dumpDisplayAndWindowInfo() const {
+    std::string dump;
+    if (!mWindowHandlesByDisplay.empty()) {
+        for (const auto& [displayId, windowHandles] : mWindowHandlesByDisplay) {
+            dump += StringPrintf("Display: %s\n", displayId.toString().c_str());
+            if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
+                const auto& displayInfo = it->second;
+                dump += StringPrintf(INDENT "logicalSize=%dx%d\n", displayInfo.logicalWidth,
+                                     displayInfo.logicalHeight);
+                displayInfo.transform.dump(dump, "transform", INDENT3);
+            } else {
+                dump += INDENT "No DisplayInfo found!\n";
+            }
+
+            if (!windowHandles.empty()) {
+                dump += INDENT "Windows:\n";
+                for (size_t i = 0; i < windowHandles.size(); i++) {
+                    dump += StringPrintf(INDENT2 "%zu: %s", i,
+                                         streamableToString(*windowHandles[i]).c_str());
+                }
+            } else {
+                dump += INDENT "Windows: <none>\n";
+            }
+        }
+    } else {
+        dump += "Displays: <none>\n";
+    }
+    return dump;
+}
+
 bool InputDispatcher::canWindowReceiveMotionLocked(const sp<WindowInfoHandle>& window,
                                                    const MotionEntry& motionEntry) const {
     const WindowInfo& info = *window->getInfo();
@@ -5316,13 +5377,14 @@
         ui::LogicalDisplayId displayId) {
     if (windowInfoHandles.empty()) {
         // Remove all handles on a display if there are no windows left.
-        mWindowHandlesByDisplay.erase(displayId);
+        mWindowInfos.removeDisplay(displayId);
         return;
     }
 
     // Since we compare the pointer of input window handles across window updates, we need
     // to make sure the handle object for the same window stays unchanged across updates.
-    const std::vector<sp<WindowInfoHandle>>& oldHandles = getWindowHandlesLocked(displayId);
+    const std::vector<sp<WindowInfoHandle>>& oldHandles =
+            mWindowInfos.getWindowHandlesForDisplay(displayId);
     std::unordered_map<int32_t /*id*/, sp<WindowInfoHandle>> oldHandlesById;
     for (const sp<WindowInfoHandle>& handle : oldHandles) {
         oldHandlesById[handle->getId()] = handle;
@@ -5361,8 +5423,7 @@
         }
     }
 
-    // Insert or replace
-    mWindowHandlesByDisplay[displayId] = newHandles;
+    mWindowInfos.setWindowHandlesForDisplay(displayId, std::move(newHandles));
 }
 
 /**
@@ -5412,12 +5473,14 @@
     }
 
     // Copy old handles for release if they are no longer present.
-    const std::vector<sp<WindowInfoHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
+    const std::vector<sp<WindowInfoHandle>> oldWindowHandles =
+            mWindowInfos.getWindowHandlesForDisplay(displayId);
     const sp<WindowInfoHandle> removedFocusedWindowHandle = getFocusedWindowHandleLocked(displayId);
 
     updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId);
 
-    const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
+    const std::vector<sp<WindowInfoHandle>>& windowHandles =
+            mWindowInfos.getWindowHandlesForDisplay(displayId);
 
     std::optional<FocusResolver::FocusChanges> changes =
             mFocusResolver.setInputWindows(displayId, windowHandles);
@@ -5429,7 +5492,7 @@
         TouchState& state = it->second;
         for (size_t i = 0; i < state.windows.size();) {
             TouchedWindow& touchedWindow = state.windows[i];
-            if (getWindowHandleLocked(touchedWindow.windowHandle) != nullptr) {
+            if (mWindowInfos.isWindowPresent(touchedWindow.windowHandle)) {
                 i++;
                 continue;
             }
@@ -5473,7 +5536,8 @@
                     [this, displayId, &touchedWindow](const PointerProperties& properties, float x,
                                                       float y) REQUIRES(mLock) {
                         const bool isStylus = properties.toolType == ToolType::STYLUS;
-                        const ui::Transform displayTransform = getTransformLocked(displayId);
+                        const ui::Transform displayTransform =
+                                mWindowInfos.getDisplayTransform(displayId);
                         const bool stillAcceptsTouch =
                                 windowAcceptsTouchAt(*touchedWindow.windowHandle->getInfo(),
                                                      displayId, x, y, isStylus, displayTransform);
@@ -5495,7 +5559,7 @@
     // Otherwise, they might stick around until the window handle is destroyed
     // which might not happen until the next GC.
     for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) {
-        if (getWindowHandleLocked(oldWindowHandle) == nullptr) {
+        if (!mWindowInfos.isWindowPresent(oldWindowHandle)) {
             if (DEBUG_FOCUS) {
                 ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
             }
@@ -5572,7 +5636,7 @@
                     mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
             if (oldFocusedWindowToken != nullptr) {
                 const auto windowHandle =
-                        getWindowHandleLocked(oldFocusedWindowToken, mFocusedDisplayId);
+                        mWindowInfos.findWindowHandle(oldFocusedWindowToken, mFocusedDisplayId);
                 if (windowHandle == nullptr) {
                     LOG(FATAL) << __func__ << ": Previously focused token did not have a window";
                 }
@@ -5711,7 +5775,7 @@
     if (focusedToken == nullptr) {
         return false;
     }
-    sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken);
+    sp<WindowInfoHandle> windowHandle = mWindowInfos.findWindowHandle(focusedToken);
     return isWindowOwnedBy(windowHandle, pid, uid);
 }
 
@@ -5719,7 +5783,7 @@
     return std::find_if(mInteractionConnectionTokens.begin(), mInteractionConnectionTokens.end(),
                         [&](const sp<IBinder>& connectionToken) REQUIRES(mLock) {
                             const sp<WindowInfoHandle> windowHandle =
-                                    getWindowHandleLocked(connectionToken);
+                                    mWindowInfos.findWindowHandle(connectionToken);
                             return isWindowOwnedBy(windowHandle, pid, uid);
                         }) != mInteractionConnectionTokens.end();
 }
@@ -5790,7 +5854,8 @@
         const DeviceId deviceId = *deviceIds.begin();
 
         const sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle;
-        const sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(toToken, displayId);
+        const sp<WindowInfoHandle> toWindowHandle =
+                mWindowInfos.findWindowHandle(toToken, displayId);
         if (!toWindowHandle) {
             ALOGW("Cannot transfer touch because the transfer target window was not found.");
             return false;
@@ -5866,10 +5931,11 @@
  * Return null if there are no windows touched on that display, or if more than one foreground
  * window is being touched.
  */
-sp<WindowInfoHandle> InputDispatcher::findTouchedForegroundWindowLocked(
-        ui::LogicalDisplayId displayId) const {
-    auto stateIt = mTouchStatesByDisplay.find(displayId);
-    if (stateIt == mTouchStatesByDisplay.end()) {
+sp<WindowInfoHandle> InputDispatcher::findTouchedForegroundWindow(
+        const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay,
+        ui::LogicalDisplayId displayId) {
+    const auto stateIt = touchStatesByDisplay.find(displayId);
+    if (stateIt == touchStatesByDisplay.end()) {
         ALOGI("No touch state on display %s", displayId.toString().c_str());
         return nullptr;
     }
@@ -5897,14 +5963,15 @@
     sp<IBinder> fromToken;
     { // acquire lock
         std::scoped_lock _l(mLock);
-        sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(destChannelToken, displayId);
+        sp<WindowInfoHandle> toWindowHandle =
+                mWindowInfos.findWindowHandle(destChannelToken, displayId);
         if (toWindowHandle == nullptr) {
             ALOGW("Could not find window associated with token=%p on display %s",
                   destChannelToken.get(), displayId.toString().c_str());
             return false;
         }
 
-        sp<WindowInfoHandle> from = findTouchedForegroundWindowLocked(displayId);
+        sp<WindowInfoHandle> from = findTouchedForegroundWindow(mTouchStatesByDisplay, displayId);
         if (from == nullptr) {
             ALOGE("Could not find a source window in %s for %p", __func__, destChannelToken.get());
             return false;
@@ -5956,7 +6023,7 @@
     std::string windowName = "None";
     if (mWindowTokenWithPointerCapture) {
         const sp<WindowInfoHandle> captureWindowHandle =
-                getWindowHandleLocked(mWindowTokenWithPointerCapture);
+                mWindowInfos.findWindowHandle(mWindowTokenWithPointerCapture);
         windowName = captureWindowHandle ? captureWindowHandle->getName().c_str()
                                          : "token has capture without window";
     }
@@ -6005,31 +6072,7 @@
         mDragState->dump(dump, INDENT2);
     }
 
-    if (!mWindowHandlesByDisplay.empty()) {
-        for (const auto& [displayId, windowHandles] : mWindowHandlesByDisplay) {
-            dump += StringPrintf(INDENT "Display: %s\n", displayId.toString().c_str());
-            if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
-                const auto& displayInfo = it->second;
-                dump += StringPrintf(INDENT2 "logicalSize=%dx%d\n", displayInfo.logicalWidth,
-                                     displayInfo.logicalHeight);
-                displayInfo.transform.dump(dump, "transform", INDENT4);
-            } else {
-                dump += INDENT2 "No DisplayInfo found!\n";
-            }
-
-            if (!windowHandles.empty()) {
-                dump += INDENT2 "Windows:\n";
-                for (size_t i = 0; i < windowHandles.size(); i++) {
-                    dump += StringPrintf(INDENT3 "%zu: %s", i,
-                                         streamableToString(*windowHandles[i]).c_str());
-                }
-            } else {
-                dump += INDENT2 "Windows: <none>\n";
-            }
-        }
-    } else {
-        dump += INDENT "Displays: <none>\n";
-    }
+    dump += addLinePrefix(mWindowInfos.dumpDisplayAndWindowInfo(), INDENT);
 
     if (!mGlobalMonitorsByDisplay.empty()) {
         for (const auto& [displayId, monitors] : mGlobalMonitorsByDisplay) {
@@ -6353,7 +6396,7 @@
     { // acquire lock
         std::scoped_lock _l(mLock);
         if (DEBUG_FOCUS) {
-            const sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(windowToken);
+            const sp<WindowInfoHandle> windowHandle = mWindowInfos.findWindowHandle(windowToken);
             ALOGI("Request to %s Pointer Capture from: %s.", enabled ? "enable" : "disable",
                   windowHandle != nullptr ? windowHandle->getName().c_str()
                                           : "token without window");
@@ -6493,7 +6536,7 @@
         }
         traceWaitQueueLength(*connection);
         if (fallbackKeyEntry && connection->status == Connection::Status::NORMAL) {
-            const auto windowHandle = getWindowHandleLocked(connection->getToken());
+            const auto windowHandle = mWindowInfos.findWindowHandle(connection->getToken());
             // Only dispatch fallbacks if there is a window for the connection.
             if (windowHandle != nullptr) {
                 const auto inputTarget =
@@ -6557,7 +6600,7 @@
                                         ns2ms(currentWait),
                                         oldestEntry.eventEntry->getDescription().c_str());
     sp<IBinder> connectionToken = connection->getToken();
-    updateLastAnrStateLocked(getWindowHandleLocked(connectionToken), reason);
+    updateLastAnrStateLocked(mWindowInfos.findWindowHandle(connectionToken), reason);
 
     processConnectionUnresponsiveLocked(*connection, std::move(reason));
 
@@ -6665,7 +6708,7 @@
         // The connection is a window
         ALOGW("Window %s is unresponsive: %s", connection.getInputChannelName().c_str(),
               reason.c_str());
-        const sp<WindowInfoHandle> handle = getWindowHandleLocked(connectionToken);
+        const sp<WindowInfoHandle> handle = mWindowInfos.findWindowHandle(connectionToken);
         if (handle != nullptr) {
             pid = handle->getInfo()->ownerPid;
         }
@@ -6683,7 +6726,7 @@
         pid = findMonitorPidByTokenLocked(connectionToken);
     } else {
         // The connection is a window
-        const sp<WindowInfoHandle> handle = getWindowHandleLocked(connectionToken);
+        const sp<WindowInfoHandle> handle = mWindowInfos.findWindowHandle(connectionToken);
         if (handle != nullptr) {
             pid = handle->getInfo()->ownerPid;
         }
@@ -6748,7 +6791,7 @@
             // Cancel the fallback key, but only if we still have a window for the channel.
             // It could have been removed during the policy call.
             if (*fallbackKeyCode != AKEYCODE_UNKNOWN) {
-                const auto windowHandle = getWindowHandleLocked(connection->getToken());
+                const auto windowHandle = mWindowInfos.findWindowHandle(connection->getToken());
                 if (windowHandle != nullptr) {
                     CancelationOptions options(CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS,
                                                "application handled the original non-fallback key "
@@ -6834,7 +6877,7 @@
                 }
             }
 
-            const auto windowHandle = getWindowHandleLocked(connection->getToken());
+            const auto windowHandle = mWindowInfos.findWindowHandle(connection->getToken());
             if (windowHandle != nullptr) {
                 CancelationOptions options(CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS,
                                            "canceling fallback, policy no longer desires it",
@@ -6976,7 +7019,7 @@
         std::scoped_lock _l(mLock);
         std::optional<FocusResolver::FocusChanges> changes =
                 mFocusResolver.setFocusedWindow(request,
-                                                getWindowHandlesLocked(
+                                                mWindowInfos.getWindowHandlesForDisplay(
                                                         ui::LogicalDisplayId{request.displayId}));
         ScopedSyntheticEventTracer traceContext(mTracer);
         if (changes) {
@@ -6994,7 +7037,7 @@
     if (changes.oldFocus) {
         const auto resolvedWindow = removedFocusedWindowHandle != nullptr
                 ? removedFocusedWindowHandle
-                : getWindowHandleLocked(changes.oldFocus, changes.displayId);
+                : mWindowInfos.findWindowHandle(changes.oldFocus, changes.displayId);
         if (resolvedWindow == nullptr) {
             LOG(FATAL) << __func__ << ": Previously focused token did not have a window";
         }
@@ -7112,14 +7155,10 @@
 
         // Ensure that we have an entry created for all existing displays so that if a displayId has
         // no windows, we can tell that the windows were removed from the display.
-        for (const auto& [displayId, _] : mWindowHandlesByDisplay) {
-            handlesPerDisplay[displayId];
-        }
+        mWindowInfos.forEachDisplayId(
+                [&](ui::LogicalDisplayId displayId) { handlesPerDisplay[displayId]; });
 
-        mDisplayInfos.clear();
-        for (const auto& displayInfo : update.displayInfos) {
-            mDisplayInfos.emplace(displayInfo.displayId, displayInfo);
-        }
+        mWindowInfos.setDisplayInfos(update.displayInfos);
 
         for (const auto& [displayId, handles] : handlesPerDisplay) {
             setInputWindowsLocked(handles, displayId);
@@ -7266,7 +7305,7 @@
 sp<WindowInfoHandle> InputDispatcher::findWallpaperWindowBelow(
         const sp<WindowInfoHandle>& windowHandle) const {
     const std::vector<sp<WindowInfoHandle>>& windowHandles =
-            getWindowHandlesLocked(windowHandle->getInfo()->displayId);
+            mWindowInfos.getWindowHandlesForDisplay(windowHandle->getInfo()->displayId);
     bool foundWindow = false;
     for (const sp<WindowInfoHandle>& otherHandle : windowHandles) {
         if (!foundWindow && otherHandle != windowHandle) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index fade853..b3e19f0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -252,9 +252,6 @@
     // to transfer focus to a new application.
     std::shared_ptr<const EventEntry> mNextUnblockedEvent GUARDED_BY(mLock);
 
-    sp<android::gui::WindowInfoHandle> findTouchedWindowAtLocked(
-            ui::LogicalDisplayId displayId, float x, float y, bool isStylus = false,
-            bool ignoreDragWindow = false) const REQUIRES(mLock);
     std::vector<InputTarget> findOutsideTargetsLocked(
             ui::LogicalDisplayId displayId, const sp<android::gui::WindowInfoHandle>& touchedWindow,
             int32_t pointerId) const REQUIRES(mLock);
@@ -263,8 +260,9 @@
             ui::LogicalDisplayId displayId, float x, float y, bool isStylus,
             DeviceId deviceId) const REQUIRES(mLock);
 
-    sp<android::gui::WindowInfoHandle> findTouchedForegroundWindowLocked(
-            ui::LogicalDisplayId displayId) const REQUIRES(mLock);
+    static sp<android::gui::WindowInfoHandle> findTouchedForegroundWindow(
+            const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay,
+            ui::LogicalDisplayId displayId);
 
     std::shared_ptr<Connection> getConnectionLocked(const sp<IBinder>& inputConnectionToken) const
             REQUIRES(mLock);
@@ -368,24 +366,57 @@
     };
     sp<gui::WindowInfosListener> mWindowInfoListener;
 
-    std::unordered_map<ui::LogicalDisplayId /*displayId*/,
-                       std::vector<sp<android::gui::WindowInfoHandle>>>
-            mWindowHandlesByDisplay GUARDED_BY(mLock);
-    std::unordered_map<ui::LogicalDisplayId /*displayId*/, android::gui::DisplayInfo> mDisplayInfos
-            GUARDED_BY(mLock);
+    class DispatcherWindowInfo {
+    public:
+        void setWindowHandlesForDisplay(
+                ui::LogicalDisplayId displayId,
+                std::vector<sp<android::gui::WindowInfoHandle>>&& windowHandles);
+
+        void setDisplayInfos(const std::vector<android::gui::DisplayInfo>& displayInfos);
+
+        void removeDisplay(ui::LogicalDisplayId displayId);
+
+        // Get a reference to window handles by display, return an empty vector if not found.
+        const std::vector<sp<android::gui::WindowInfoHandle>>& getWindowHandlesForDisplay(
+                ui::LogicalDisplayId displayId) const;
+
+        void forEachWindowHandle(
+                std::function<void(const sp<android::gui::WindowInfoHandle>&)> f) const;
+
+        void forEachDisplayId(std::function<void(ui::LogicalDisplayId)> f) const;
+
+        // Get the transform for display, returns Identity-transform if display is missing.
+        ui::Transform getDisplayTransform(ui::LogicalDisplayId displayId) const;
+
+        // Lookup for WindowInfoHandle from token and optionally a display-id. In cases where
+        // display-id is not provided lookup is done for all displays.
+        sp<android::gui::WindowInfoHandle> findWindowHandle(
+                const sp<IBinder>& windowHandleToken,
+                std::optional<ui::LogicalDisplayId> displayId = {}) const;
+
+        bool isWindowPresent(const sp<android::gui::WindowInfoHandle>& windowHandle) const;
+
+        // Returns the touched window at the given location, excluding the ignoreWindow if provided.
+        sp<android::gui::WindowInfoHandle> findTouchedWindowAt(
+                ui::LogicalDisplayId displayId, float x, float y, bool isStylus = false,
+                const sp<android::gui::WindowInfoHandle> ignoreWindow = nullptr) const;
+
+        std::string dumpDisplayAndWindowInfo() const;
+
+    private:
+        std::unordered_map<ui::LogicalDisplayId /*displayId*/,
+                           std::vector<sp<android::gui::WindowInfoHandle>>>
+                mWindowHandlesByDisplay;
+        std::unordered_map<ui::LogicalDisplayId /*displayId*/, android::gui::DisplayInfo>
+                mDisplayInfos;
+    };
+
+    DispatcherWindowInfo mWindowInfos GUARDED_BY(mLock);
+
     void setInputWindowsLocked(
             const std::vector<sp<android::gui::WindowInfoHandle>>& inputWindowHandles,
             ui::LogicalDisplayId displayId) REQUIRES(mLock);
-    // Get a reference to window handles by display, return an empty vector if not found.
-    const std::vector<sp<android::gui::WindowInfoHandle>>& getWindowHandlesLocked(
-            ui::LogicalDisplayId displayId) const REQUIRES(mLock);
-    ui::Transform getTransformLocked(ui::LogicalDisplayId displayId) const REQUIRES(mLock);
 
-    sp<android::gui::WindowInfoHandle> getWindowHandleLocked(
-            const sp<IBinder>& windowHandleToken,
-            std::optional<ui::LogicalDisplayId> displayId = {}) const REQUIRES(mLock);
-    sp<android::gui::WindowInfoHandle> getWindowHandleLocked(
-            const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock);
     sp<android::gui::WindowInfoHandle> getFocusedWindowHandleLocked(
             ui::LogicalDisplayId displayId) const REQUIRES(mLock);
     bool canWindowReceiveMotionLocked(const sp<android::gui::WindowInfoHandle>& window,
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 4d6b6c7..404a509 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -139,9 +139,17 @@
     // The mouse pointer speed, as a number from -7 (slowest) to 7 (fastest).
     int32_t mousePointerSpeed;
 
-    // Displays on which an acceleration curve shouldn't be applied for pointer movements from mice.
+    // Displays on which all pointer scaling, including linear scaling based on the
+    // user's pointer speed setting, should be disabled for mice. This differs from
+    // disabling acceleration via the 'mousePointerAccelerationEnabled' setting, where
+    // the pointer speed setting still influences the scaling factor.
     std::set<ui::LogicalDisplayId> displaysWithMousePointerAccelerationDisabled;
 
+    // True if the connected mouse should exhibit pointer acceleration. If false,
+    // a flat acceleration curve (linear scaling) is used, but the user's pointer
+    // speed setting still affects the scaling factor.
+    bool mousePointerAccelerationEnabled;
+
     // Velocity control parameters for touchpad pointer movements on the old touchpad stack (based
     // on TouchInputMapper).
     //
@@ -275,11 +283,15 @@
             defaultPointerDisplayId(ui::LogicalDisplayId::DEFAULT),
             mousePointerSpeed(0),
             displaysWithMousePointerAccelerationDisabled(),
+            mousePointerAccelerationEnabled(true),
             pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f,
                                              static_cast<float>(
                                                      android::os::IInputConstants::
                                                              DEFAULT_POINTER_ACCELERATION)),
-            wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f),
+            wheelVelocityControlParameters(1.0f, 15.0f, 50.0f,
+                                           static_cast<float>(
+                                                   android::os::IInputConstants::
+                                                           DEFAULT_MOUSE_WHEEL_ACCELERATION)),
             pointerGesturesEnabled(true),
             pointerGestureQuietInterval(100 * 1000000LL),            // 100 ms
             pointerGestureDragMinSwitchSpeed(50),                    // 50 pixels per second
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index b33659c..e9f17e7 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -481,15 +481,21 @@
         mPointerVelocityControl.setAccelerationEnabled(false);
         mWheelXVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
         mWheelYVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
-    } else {
-        mPointerVelocityControl.setAccelerationEnabled(
-                config.displaysWithMousePointerAccelerationDisabled.count(
-                        mDisplayId.value_or(ui::LogicalDisplayId::INVALID)) == 0);
-        mPointerVelocityControl.setCurve(
-                createAccelerationCurveForPointerSensitivity(config.mousePointerSpeed));
-        mWheelXVelocityControl.setParameters(config.wheelVelocityControlParameters);
-        mWheelYVelocityControl.setParameters(config.wheelVelocityControlParameters);
+        return;
     }
+
+    bool disableAllScaling = config.displaysWithMousePointerAccelerationDisabled.count(
+                                     mDisplayId.value_or(ui::LogicalDisplayId::INVALID)) != 0;
+
+    mPointerVelocityControl.setAccelerationEnabled(!disableAllScaling);
+
+    mPointerVelocityControl.setCurve(
+            config.mousePointerAccelerationEnabled
+                    ? createAccelerationCurveForPointerSensitivity(config.mousePointerSpeed)
+                    : createFlatAccelerationCurve(config.mousePointerSpeed));
+
+    mWheelXVelocityControl.setParameters(config.wheelVelocityControlParameters);
+    mWheelYVelocityControl.setParameters(config.wheelVelocityControlParameters);
 }
 
 void CursorInputMapper::configureOnChangeDisplayInfo(const InputReaderConfiguration& config) {
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index 6bd949a..827076a 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -81,7 +81,6 @@
                                    const InputDeviceContext& deviceContext, int32_t deviceId)
       : mDeviceId(deviceId),
         mReaderContext(readerContext),
-        mEnableFlingStop(input_flags::enable_touchpad_fling_stop()),
         mEnableNoFocusChange(input_flags::enable_touchpad_no_focus_change()),
         // We can safely assume that ABS_MT_POSITION_X and _Y axes will be available, as EventHub
         // won't classify a device as a touchpad if they're not present.
@@ -406,7 +405,7 @@
             break;
         case GESTURES_FLING_TAP_DOWN:
             if (mCurrentClassification == MotionClassification::NONE) {
-                if (mEnableFlingStop && mFlingMayBeInProgress) {
+                if (mFlingMayBeInProgress) {
                     // The user has just touched the pad again after ending a two-finger scroll
                     // motion, which might have started a fling. We want to stop the fling, but
                     // unfortunately there's currently no API for doing so. Instead, send and
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
index 8d92ead..be76b61 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
@@ -104,7 +104,6 @@
 
     const int32_t mDeviceId;
     InputReaderContext& mReaderContext;
-    const bool mEnableFlingStop;
     const bool mEnableNoFocusChange;
     bool mEnableSystemGestures{true};
 
diff --git a/services/inputflinger/tests/CursorInputMapper_test.cpp b/services/inputflinger/tests/CursorInputMapper_test.cpp
index d4e8fdf..a31c4e9 100644
--- a/services/inputflinger/tests/CursorInputMapper_test.cpp
+++ b/services/inputflinger/tests/CursorInputMapper_test.cpp
@@ -27,6 +27,7 @@
 #include <com_android_input_flags.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <input/AccelerationCurve.h>
 #include <input/DisplayViewport.h>
 #include <input/InputEventLabels.h>
 #include <linux/input-event-codes.h>
@@ -1028,6 +1029,34 @@
                               WithCoords(0.0f, 0.0f)))));
 }
 
+TEST_F(CursorInputMapperUnitTest, PointerAccelerationDisabled) {
+    mReaderConfiguration.mousePointerAccelerationEnabled = false;
+    mReaderConfiguration.mousePointerSpeed = 3;
+    mPropertyMap.addProperty("cursor.mode", "pointer");
+    createMapper();
+
+    std::list<NotifyArgs> reconfigureArgs;
+
+    reconfigureArgs += mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
+                                            InputReaderConfiguration::Change::POINTER_SPEED);
+
+    std::vector<AccelerationCurveSegment> curve =
+            createFlatAccelerationCurve(mReaderConfiguration.mousePointerSpeed);
+    double baseGain = curve[0].baseGain;
+
+    std::list<NotifyArgs> motionArgs;
+    motionArgs += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
+    motionArgs += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
+    motionArgs += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+    const float expectedRelX = 10 * baseGain;
+    const float expectedRelY = 20 * baseGain;
+    ASSERT_THAT(motionArgs,
+                ElementsAre(VariantWith<NotifyMotionArgs>(
+                        AllOf(WithMotionAction(HOVER_MOVE),
+                              WithRelativeMotion(expectedRelX, expectedRelY)))));
+}
+
 TEST_F(CursorInputMapperUnitTest, ConfigureAccelerationWithAssociatedViewport) {
     mPropertyMap.addProperty("cursor.mode", "pointer");
     DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation0);
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index fe40a5e..8fa439d 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -1297,7 +1297,6 @@
 
 TEST_F(GestureConverterTest, FlingTapDownAfterScrollStopsFling) {
     InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
-    input_flags::enable_touchpad_fling_stop(true);
     GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
     converter.setDisplayId(ui::LogicalDisplayId::DEFAULT);
 
diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h
index 7078e49..7fb8895 100644
--- a/services/inputflinger/tests/TestEventMatchers.h
+++ b/services/inputflinger/tests/TestEventMatchers.h
@@ -32,6 +32,17 @@
 
 namespace android {
 
+namespace {
+
+template <typename T>
+static bool valuesMatch(T value1, T value2) {
+    if constexpr (std::is_floating_point_v<T>) {
+        return std::abs(value1 - value2) < EPSILON;
+    } else {
+        return value1 == value2;
+    }
+}
+
 struct PointF {
     float x;
     float y;
@@ -42,6 +53,8 @@
     return std::string("(") + std::to_string(p.x) + ", " + std::to_string(p.y) + ")";
 }
 
+} // namespace
+
 /// Source
 class WithSourceMatcher {
 public:
@@ -706,8 +719,8 @@
         }
 
         const PointerCoords& coords = event.pointerCoords[mPointerIndex];
-        bool matches = mRelX == coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X) &&
-                mRelY == coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
+        bool matches = valuesMatch(mRelX, coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X)) &&
+                valuesMatch(mRelY, coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
         if (!matches) {
             *os << "expected relative motion (" << mRelX << ", " << mRelY << ") at pointer index "
                 << mPointerIndex << ", but got ("
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 99a67e4..e63a14b 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -629,7 +629,7 @@
         auto layer = getLayerById(layerIds[i]);
         if (layer) {
             auto& layerLut = tmpLuts[i];
-            if (layerLut.luts.pfd.get() > 0 && layerLut.luts.offsets.has_value()) {
+            if (layerLut.luts.pfd.get() >= 0 && layerLut.luts.offsets.has_value()) {
                 const auto& offsets = layerLut.luts.offsets.value();
                 std::vector<std::pair<int32_t, LutProperties>> lutOffsetsAndProperties;
                 lutOffsetsAndProperties.reserve(offsets.size());
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
index f1091a6..d369403 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
@@ -182,8 +182,8 @@
     }
 }
 
-void LayerLifecycleManager::applyTransactions(const std::vector<TransactionState>& transactions,
-                                              bool ignoreUnknownLayers) {
+void LayerLifecycleManager::applyTransactions(
+        const std::vector<QueuedTransactionState>& transactions, bool ignoreUnknownLayers) {
     for (const auto& transaction : transactions) {
         for (const auto& resolvedComposerState : transaction.states) {
             const auto& clientState = resolvedComposerState.state;
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
index 330da9a..072be35 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
@@ -16,8 +16,8 @@
 
 #pragma once
 
+#include "QueuedTransactionState.h"
 #include "RequestedLayerState.h"
-#include "TransactionState.h"
 
 namespace android::surfaceflinger::frontend {
 
@@ -43,7 +43,8 @@
     // the layers it is unreachable. When using the LayerLifecycleManager for layer trace
     // generation we may encounter layers which are known because we don't have an explicit
     // lifecycle. Ignore these errors while we have to interop with legacy.
-    void applyTransactions(const std::vector<TransactionState>&, bool ignoreUnknownLayers = false);
+    void applyTransactions(const std::vector<QueuedTransactionState>&,
+                           bool ignoreUnknownLayers = false);
     // Ignore unknown handles when iteroping with legacy front end. In the old world, we
     // would create child layers which are not necessary with the new front end. This means
     // we will get notified for handle changes that don't exist in the new front end.
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
index 7ddd7ba..dd861a7 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
@@ -23,7 +23,7 @@
 #include "Scheduler/LayerInfo.h"
 
 #include "LayerCreationArgs.h"
-#include "TransactionState.h"
+#include "QueuedTransactionState.h"
 
 namespace android::surfaceflinger::frontend {
 using namespace ftl::flag_operators;
diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
index a1e8213..5bf86e5 100644
--- a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
+++ b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
@@ -28,7 +28,7 @@
 
 namespace android::surfaceflinger::frontend {
 
-void TransactionHandler::queueTransaction(TransactionState&& state) {
+void TransactionHandler::queueTransaction(QueuedTransactionState&& state) {
     mLocklessTransactionQueue.push(std::move(state));
     mPendingTransactionCount.fetch_add(1);
     SFTRACE_INT("TransactionQueue", static_cast<int>(mPendingTransactionCount.load()));
@@ -45,9 +45,9 @@
     }
 }
 
-std::vector<TransactionState> TransactionHandler::flushTransactions() {
+std::vector<QueuedTransactionState> TransactionHandler::flushTransactions() {
     // Collect transaction that are ready to be applied.
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     TransactionFlushState flushState;
     flushState.queueProcessTime = systemTime();
     // Transactions with a buffer pending on a barrier may be on a different applyToken
@@ -76,7 +76,7 @@
 }
 
 void TransactionHandler::applyUnsignaledBufferTransaction(
-        std::vector<TransactionState>& transactions, TransactionFlushState& flushState) {
+        std::vector<QueuedTransactionState>& transactions, TransactionFlushState& flushState) {
     if (!flushState.queueWithUnsignaledBuffer) {
         return;
     }
@@ -98,9 +98,9 @@
     }
 }
 
-void TransactionHandler::popTransactionFromPending(std::vector<TransactionState>& transactions,
-                                                   TransactionFlushState& flushState,
-                                                   std::queue<TransactionState>& queue) {
+void TransactionHandler::popTransactionFromPending(
+        std::vector<QueuedTransactionState>& transactions, TransactionFlushState& flushState,
+        std::queue<QueuedTransactionState>& queue) {
     auto& transaction = queue.front();
     // Transaction is ready move it from the pending queue.
     flushState.firstTransaction = false;
@@ -146,8 +146,8 @@
     return ready;
 }
 
-int TransactionHandler::flushPendingTransactionQueues(std::vector<TransactionState>& transactions,
-                                                      TransactionFlushState& flushState) {
+int TransactionHandler::flushPendingTransactionQueues(
+        std::vector<QueuedTransactionState>& transactions, TransactionFlushState& flushState) {
     int transactionsPendingBarrier = 0;
     auto it = mPendingTransactionQueues.begin();
     while (it != mPendingTransactionQueues.end()) {
diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.h b/services/surfaceflinger/FrontEnd/TransactionHandler.h
index 00f6bce..e78dd88 100644
--- a/services/surfaceflinger/FrontEnd/TransactionHandler.h
+++ b/services/surfaceflinger/FrontEnd/TransactionHandler.h
@@ -22,7 +22,7 @@
 #include <vector>
 
 #include <LocklessQueue.h>
-#include <TransactionState.h>
+#include <QueuedTransactionState.h>
 #include <android-base/thread_annotations.h>
 #include <ftl/small_map.h>
 #include <ftl/small_vector.h>
@@ -35,7 +35,7 @@
 class TransactionHandler {
 public:
     struct TransactionFlushState {
-        TransactionState* transaction;
+        QueuedTransactionState* transaction;
         bool firstTransaction = true;
         nsecs_t queueProcessTime = 0;
         // Layer handles that have transactions with buffers that are ready to be applied.
@@ -61,9 +61,9 @@
     bool hasPendingTransactions();
     // Moves transactions from the lockless queue.
     void collectTransactions();
-    std::vector<TransactionState> flushTransactions();
+    std::vector<QueuedTransactionState> flushTransactions();
     void addTransactionReadyFilter(TransactionFilter&&);
-    void queueTransaction(TransactionState&&);
+    void queueTransaction(QueuedTransactionState&&);
 
     struct StalledTransactionInfo {
         pid_t pid;
@@ -81,14 +81,15 @@
     // For unit tests
     friend class ::android::TestableSurfaceFlinger;
 
-    int flushPendingTransactionQueues(std::vector<TransactionState>&, TransactionFlushState&);
-    void applyUnsignaledBufferTransaction(std::vector<TransactionState>&, TransactionFlushState&);
-    void popTransactionFromPending(std::vector<TransactionState>&, TransactionFlushState&,
-                                   std::queue<TransactionState>&);
+    int flushPendingTransactionQueues(std::vector<QueuedTransactionState>&, TransactionFlushState&);
+    void applyUnsignaledBufferTransaction(std::vector<QueuedTransactionState>&,
+                                          TransactionFlushState&);
+    void popTransactionFromPending(std::vector<QueuedTransactionState>&, TransactionFlushState&,
+                                   std::queue<QueuedTransactionState>&);
     TransactionReadiness applyFilters(TransactionFlushState&);
-    std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash>
+    std::unordered_map<sp<IBinder>, std::queue<QueuedTransactionState>, IListenerHash>
             mPendingTransactionQueues;
-    LocklessQueue<TransactionState> mLocklessTransactionQueue;
+    LocklessQueue<QueuedTransactionState> mLocklessTransactionQueue;
     std::atomic<size_t> mPendingTransactionCount = 0;
     ftl::SmallVector<TransactionFilter, 2> mTransactionReadyFilters;
 
diff --git a/services/surfaceflinger/FrontEnd/Update.h b/services/surfaceflinger/FrontEnd/Update.h
index 4af27ab..f7dfeb8 100644
--- a/services/surfaceflinger/FrontEnd/Update.h
+++ b/services/surfaceflinger/FrontEnd/Update.h
@@ -19,15 +19,15 @@
 #include <gui/DisplayInfo.h>
 
 #include "FrontEnd/LayerCreationArgs.h"
+#include "QueuedTransactionState.h"
 #include "RequestedLayerState.h"
-#include "TransactionState.h"
 
 namespace android::surfaceflinger::frontend {
 
 // Atomic set of changes affecting layer state. These changes are queued in binder threads and
 // applied every vsync.
 struct Update {
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     std::vector<sp<Layer>> legacyLayers;
     std::vector<std::unique_ptr<frontend::RequestedLayerState>> newLayers;
     std::vector<LayerCreationArgs> layerCreationArgs;
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/QueuedTransactionState.h
similarity index 85%
rename from services/surfaceflinger/TransactionState.h
rename to services/surfaceflinger/QueuedTransactionState.h
index e5d6481..af40c02 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/QueuedTransactionState.h
@@ -16,9 +16,7 @@
 
 #pragma once
 
-#include <condition_variable>
 #include <memory>
-#include <mutex>
 #include <vector>
 #include "FrontEnd/LayerCreationArgs.h"
 #include "renderengine/ExternalTexture.h"
@@ -47,18 +45,20 @@
     uint32_t touchCropId = UNASSIGNED_LAYER_ID;
 };
 
-struct TransactionState {
-    TransactionState() = default;
+struct QueuedTransactionState {
+    QueuedTransactionState() = default;
 
-    TransactionState(const FrameTimelineInfo& frameTimelineInfo,
-                     std::vector<ResolvedComposerState>& composerStates,
-                     const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
-                     const sp<IBinder>& applyToken, const InputWindowCommands& inputWindowCommands,
-                     int64_t desiredPresentTime, bool isAutoTimestamp,
-                     std::vector<uint64_t> uncacheBufferIds, int64_t postTime,
-                     bool hasListenerCallbacks, std::vector<ListenerCallbacks> listenerCallbacks,
-                     int originPid, int originUid, uint64_t transactionId,
-                     std::vector<uint64_t> mergedTransactionIds)
+    QueuedTransactionState(const FrameTimelineInfo& frameTimelineInfo,
+                           std::vector<ResolvedComposerState>& composerStates,
+                           const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
+                           const sp<IBinder>& applyToken,
+                           const InputWindowCommands& inputWindowCommands,
+                           int64_t desiredPresentTime, bool isAutoTimestamp,
+                           std::vector<uint64_t> uncacheBufferIds, int64_t postTime,
+                           bool hasListenerCallbacks,
+                           std::vector<ListenerCallbacks> listenerCallbacks, int originPid,
+                           int originUid, uint64_t transactionId,
+                           std::vector<uint64_t> mergedTransactionIds)
           : frameTimelineInfo(frameTimelineInfo),
             states(std::move(composerStates)),
             displays(displayStates),
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e05c5bd9..dd1119a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4774,16 +4774,16 @@
 // For tests only
 bool SurfaceFlinger::flushTransactionQueues() {
     mTransactionHandler.collectTransactions();
-    std::vector<TransactionState> transactions = mTransactionHandler.flushTransactions();
+    std::vector<QueuedTransactionState> transactions = mTransactionHandler.flushTransactions();
     return applyTransactions(transactions);
 }
 
-bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions) {
+bool SurfaceFlinger::applyTransactions(std::vector<QueuedTransactionState>& transactions) {
     Mutex::Autolock lock(mStateLock);
     return applyTransactionsLocked(transactions);
 }
 
-bool SurfaceFlinger::applyTransactionsLocked(std::vector<TransactionState>& transactions) {
+bool SurfaceFlinger::applyTransactionsLocked(std::vector<QueuedTransactionState>& transactions) {
     bool needsTraversal = false;
     // Now apply all transactions.
     for (auto& transaction : transactions) {
@@ -4944,22 +4944,22 @@
         }
     }
 
-    TransactionState state{frameTimelineInfo,
-                           resolvedStates,
-                           displays,
-                           flags,
-                           applyToken,
-                           std::move(inputWindowCommands),
-                           desiredPresentTime,
-                           isAutoTimestamp,
-                           std::move(uncacheBufferIds),
-                           postTime,
-                           hasListenerCallbacks,
-                           listenerCallbacks,
-                           originPid,
-                           originUid,
-                           transactionId,
-                           mergedTransactionIds};
+    QueuedTransactionState state{frameTimelineInfo,
+                                 resolvedStates,
+                                 displays,
+                                 flags,
+                                 applyToken,
+                                 std::move(inputWindowCommands),
+                                 desiredPresentTime,
+                                 isAutoTimestamp,
+                                 std::move(uncacheBufferIds),
+                                 postTime,
+                                 hasListenerCallbacks,
+                                 listenerCallbacks,
+                                 originPid,
+                                 originUid,
+                                 transactionId,
+                                 mergedTransactionIds};
 
     if (mTransactionTracing) {
         mTransactionTracing->addQueuedTransaction(state);
@@ -5044,7 +5044,7 @@
 }
 
 bool SurfaceFlinger::applyAndCommitDisplayTransactionStatesLocked(
-        std::vector<TransactionState>& transactions) {
+        std::vector<QueuedTransactionState>& transactions) {
     bool needsTraversal = false;
     uint32_t transactionFlags = 0;
     for (auto& transaction : transactions) {
@@ -5438,7 +5438,7 @@
 }
 
 void SurfaceFlinger::initializeDisplays() {
-    TransactionState state;
+    QueuedTransactionState state;
     state.inputWindowCommands = mInputWindowCommands;
     const nsecs_t now = systemTime();
     state.desiredPresentTime = now;
@@ -5453,7 +5453,7 @@
         state.displays.push(DisplayState(display.token(), ui::LayerStack::fromValue(layerStack++)));
     }
 
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     transactions.emplace_back(state);
 
     {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c85c084..c2e687f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -87,6 +87,7 @@
 #include "LayerVector.h"
 #include "MutexUtils.h"
 #include "PowerAdvisor/PowerAdvisor.h"
+#include "QueuedTransactionState.h"
 #include "Scheduler/ISchedulerCallback.h"
 #include "Scheduler/RefreshRateSelector.h"
 #include "Scheduler/Scheduler.h"
@@ -95,7 +96,6 @@
 #include "Tracing/LayerTracing.h"
 #include "Tracing/TransactionTracing.h"
 #include "TransactionCallbackInvoker.h"
-#include "TransactionState.h"
 #include "Utils/OnceFuture.h"
 
 #include <algorithm>
@@ -803,8 +803,9 @@
     // For test only
     bool flushTransactionQueues() REQUIRES(kMainThreadContext);
 
-    bool applyTransactions(std::vector<TransactionState>&) REQUIRES(kMainThreadContext);
-    bool applyAndCommitDisplayTransactionStatesLocked(std::vector<TransactionState>& transactions)
+    bool applyTransactions(std::vector<QueuedTransactionState>&) REQUIRES(kMainThreadContext);
+    bool applyAndCommitDisplayTransactionStatesLocked(
+            std::vector<QueuedTransactionState>& transactions)
             REQUIRES(kMainThreadContext, mStateLock);
 
     // Returns true if there is at least one transaction that needs to be flushed
@@ -833,7 +834,7 @@
 
     static LatchUnsignaledConfig getLatchUnsignaledConfig();
     bool shouldLatchUnsignaled(const layer_state_t&, size_t numStates, bool firstTransaction) const;
-    bool applyTransactionsLocked(std::vector<TransactionState>& transactions)
+    bool applyTransactionsLocked(std::vector<QueuedTransactionState>& transactions)
             REQUIRES(mStateLock, kMainThreadContext);
     uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
     uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index f39a4d2..2676ca6 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -20,8 +20,8 @@
 
 #include "FrontEnd/LayerCreationArgs.h"
 #include "LayerProtoHelper.h"
+#include "QueuedTransactionState.h"
 #include "TransactionProtoParser.h"
-#include "TransactionState.h"
 #include "gui/LayerState.h"
 
 namespace android::surfaceflinger {
@@ -51,7 +51,8 @@
     ~FakeExternalTexture() = default;
 };
 
-perfetto::protos::TransactionState TransactionProtoParser::toProto(const TransactionState& t) {
+perfetto::protos::TransactionState TransactionProtoParser::toProto(
+        const QueuedTransactionState& t) {
     perfetto::protos::TransactionState proto;
     proto.set_pid(t.originPid);
     proto.set_uid(t.originUid);
@@ -300,9 +301,9 @@
     return proto;
 }
 
-TransactionState TransactionProtoParser::fromProto(
+QueuedTransactionState TransactionProtoParser::fromProto(
         const perfetto::protos::TransactionState& proto) {
-    TransactionState t;
+    QueuedTransactionState t;
     t.originPid = proto.pid();
     t.originUid = proto.uid();
     t.frameTimelineInfo.vsyncId = proto.vsync_id();
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index b3ab71c..a02e231 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -21,7 +21,7 @@
 
 #include "FrontEnd/DisplayInfo.h"
 #include "FrontEnd/LayerCreationArgs.h"
-#include "TransactionState.h"
+#include "QueuedTransactionState.h"
 
 namespace android::surfaceflinger {
 
@@ -44,14 +44,14 @@
     TransactionProtoParser(std::unique_ptr<FlingerDataMapper> provider)
           : mMapper(std::move(provider)) {}
 
-    perfetto::protos::TransactionState toProto(const TransactionState&);
+    perfetto::protos::TransactionState toProto(const QueuedTransactionState&);
     perfetto::protos::TransactionState toProto(
             const std::map<uint32_t /* layerId */, TracingLayerState>&);
     perfetto::protos::LayerCreationArgs toProto(const LayerCreationArgs& args);
     perfetto::protos::LayerState toProto(const ResolvedComposerState&);
     static perfetto::protos::DisplayInfo toProto(const frontend::DisplayInfo&, uint32_t layerStack);
 
-    TransactionState fromProto(const perfetto::protos::TransactionState&);
+    QueuedTransactionState fromProto(const perfetto::protos::TransactionState&);
     void mergeFromProto(const perfetto::protos::LayerState&, TracingLayerState& outState);
     void fromProto(const perfetto::protos::LayerCreationArgs&, LayerCreationArgs& outArgs);
     std::unique_ptr<FlingerDataMapper> mMapper;
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index bc9f809..1cd7517 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -166,7 +166,7 @@
     mBuffer.dump(result);
 }
 
-void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
+void TransactionTracing::addQueuedTransaction(const QueuedTransactionState& transaction) {
     perfetto::protos::TransactionState* state =
             new perfetto::protos::TransactionState(mProtoParser.toProto(transaction));
     mTransactionQueue.push(state);
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
index 7a0fb5e..d784168 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.h
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -134,7 +134,7 @@
     // Flush event from perfetto data source
     void onFlush(Mode mode);
 
-    void addQueuedTransaction(const TransactionState&);
+    void addQueuedTransaction(const QueuedTransactionState&);
     void addCommittedTransactions(int64_t vsyncId, nsecs_t commitTime, frontend::Update& update,
                                   const frontend::DisplayInfos&, bool displayInfoChanged);
     status_t writeToFile(const std::string& filename = FILE_PATH);
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index 1dba175..5cf4244 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -31,8 +31,8 @@
 #include "FrontEnd/LayerCreationArgs.h"
 #include "FrontEnd/RequestedLayerState.h"
 #include "LayerProtoHelper.h"
+#include "QueuedTransactionState.h"
 #include "Tracing/LayerTracing.h"
-#include "TransactionState.h"
 #include "cutils/properties.h"
 
 #include "LayerTraceGenerator.h"
@@ -95,11 +95,11 @@
             addedLayers.emplace_back(std::make_unique<frontend::RequestedLayerState>(args));
         }
 
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.reserve((size_t)entry.transactions_size());
         for (int j = 0; j < entry.transactions_size(); j++) {
             // apply transactions
-            TransactionState transaction = parser.fromProto(entry.transactions(j));
+            QueuedTransactionState transaction = parser.fromProto(entry.transactions(j));
             for (auto& resolvedComposerState : transaction.states) {
                 if (resolvedComposerState.state.what & layer_state_t::eInputInfoChanged) {
                     if (!resolvedComposerState.state.windowInfoHandle->getInfo()->inputConfig.test(
diff --git a/services/surfaceflinger/tests/benchmarks/LayerLifecycleManager_benchmarks.cpp b/services/surfaceflinger/tests/benchmarks/LayerLifecycleManager_benchmarks.cpp
index 7641a45..0925118 100644
--- a/services/surfaceflinger/tests/benchmarks/LayerLifecycleManager_benchmarks.cpp
+++ b/services/surfaceflinger/tests/benchmarks/LayerLifecycleManager_benchmarks.cpp
@@ -50,7 +50,7 @@
     layers.emplace_back(LayerLifecycleManagerHelper::rootLayer(1));
     lifecycleManager.addLayers(std::move(layers));
     lifecycleManager.commitChanges();
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     transactions.emplace_back();
     transactions.back().states.push_back({});
     auto& transactionState = transactions.back().states.front();
@@ -74,7 +74,7 @@
     std::vector<std::unique_ptr<RequestedLayerState>> layers;
     layers.emplace_back(LayerLifecycleManagerHelper::rootLayer(1));
     lifecycleManager.addLayers(std::move(layers));
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     transactions.emplace_back();
     transactions.back().states.push_back({});
     auto& transactionState = transactions.back().states.front();
diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
index 9794620..a894c41 100644
--- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
+++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
@@ -66,8 +66,8 @@
                                                                 /*mirror=*/UNASSIGNED_LAYER_ID));
     }
 
-    static std::vector<TransactionState> setZTransaction(uint32_t id, int32_t z) {
-        std::vector<TransactionState> transactions;
+    static std::vector<QueuedTransactionState> setZTransaction(uint32_t id, int32_t z) {
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -109,8 +109,9 @@
         mLifecycleManager.addLayers(std::move(layers));
     }
 
-    std::vector<TransactionState> reparentLayerTransaction(uint32_t id, uint32_t newParentId) {
-        std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> reparentLayerTransaction(uint32_t id,
+                                                                 uint32_t newParentId) {
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
         transactions.back().states.front().parentId = newParentId;
@@ -124,8 +125,9 @@
         mLifecycleManager.applyTransactions(reparentLayerTransaction(id, newParentId));
     }
 
-    std::vector<TransactionState> relativeLayerTransaction(uint32_t id, uint32_t relativeParentId) {
-        std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> relativeLayerTransaction(uint32_t id,
+                                                                 uint32_t relativeParentId) {
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
         transactions.back().states.front().relativeParentId = relativeParentId;
@@ -139,7 +141,7 @@
     }
 
     void removeRelativeZ(uint32_t id) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
         transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
@@ -148,7 +150,7 @@
     }
 
     void setPosition(uint32_t id, float x, float y) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
         transactions.back().states.front().state.what = layer_state_t::ePositionChanged;
@@ -167,7 +169,7 @@
     }
 
     void updateBackgroundColor(uint32_t id, half alpha) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
         transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
@@ -183,7 +185,7 @@
     }
 
     void setCrop(uint32_t id, const FloatRect& crop) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -196,7 +198,7 @@
     void setCrop(uint32_t id, const Rect& crop) { setCrop(id, crop.toFloatRect()); }
 
     void setFlags(uint32_t id, uint32_t mask, uint32_t flags) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -208,7 +210,7 @@
     }
 
     void setAlpha(uint32_t id, float alpha) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -219,7 +221,7 @@
     }
 
     void setAutoRefresh(uint32_t id, bool autoRefresh) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -236,7 +238,7 @@
     void showLayer(uint32_t id) { setFlags(id, layer_state_t::eLayerHidden, 0); }
 
     void setColor(uint32_t id, half3 rgb = half3(1._hf, 1._hf, 1._hf)) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
         transactions.back().states.front().state.what = layer_state_t::eColorChanged;
@@ -246,7 +248,7 @@
     }
 
     void setLayerStack(uint32_t id, int32_t layerStack) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -257,7 +259,7 @@
     }
 
     void setTouchableRegion(uint32_t id, Region region) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -272,7 +274,7 @@
     }
 
     void setInputInfo(uint32_t id, std::function<void(gui::WindowInfo&)> configureInput) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -291,7 +293,7 @@
 
     void setTouchableRegionCrop(uint32_t id, Region region, uint32_t touchCropId,
                                 bool replaceTouchableRegionWithCrop) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -309,7 +311,7 @@
     }
 
     void setBackgroundBlurRadius(uint32_t id, uint32_t backgroundBlurRadius) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -320,7 +322,7 @@
     }
 
     void setFrameRateSelectionPriority(uint32_t id, int32_t priority) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -332,7 +334,7 @@
 
     void setFrameRate(uint32_t id, float frameRate, int8_t compatibility,
                       int8_t changeFrameRateStrategy) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -345,7 +347,7 @@
     }
 
     void setFrameRate(uint32_t id, Layer::FrameRate framerate) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -358,7 +360,7 @@
     }
 
     void setFrameRateCategory(uint32_t id, int8_t frameRateCategory) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -369,7 +371,7 @@
     }
 
     void setFrameRateSelectionStrategy(uint32_t id, int8_t strategy) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -381,7 +383,7 @@
     }
 
     void setDefaultFrameRateCompatibility(uint32_t id, int8_t defaultFrameRateCompatibility) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -394,7 +396,7 @@
     }
 
     void setRoundedCorners(uint32_t id, float radius) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -405,7 +407,7 @@
     }
 
     void setBuffer(uint32_t id, std::shared_ptr<renderengine::ExternalTexture> texture) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -438,7 +440,7 @@
     }
 
     void setBufferCrop(uint32_t id, const Rect& bufferCrop) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -449,7 +451,7 @@
     }
 
     void setDamageRegion(uint32_t id, const Region& damageRegion) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -460,7 +462,7 @@
     }
 
     void setDataspace(uint32_t id, ui::Dataspace dataspace) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -473,7 +475,7 @@
     void setMatrix(uint32_t id, float dsdx, float dtdx, float dtdy, float dsdy) {
         layer_state_t::matrix22_t matrix{dsdx, dtdx, dtdy, dsdy};
 
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -484,7 +486,7 @@
     }
 
     void setShadowRadius(uint32_t id, float shadowRadius) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -495,7 +497,7 @@
     }
 
     void setTrustedOverlay(uint32_t id, gui::TrustedOverlay trustedOverlay) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -506,7 +508,7 @@
     }
 
     void setDropInputMode(uint32_t id, gui::DropInputMode dropInputMode) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
@@ -517,7 +519,7 @@
     }
 
     void setGameMode(uint32_t id, gui::GameMode gameMode) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
         transactions.back().states.front().state.what = layer_state_t::eMetadataChanged;
@@ -529,7 +531,7 @@
     }
 
     void setEdgeExtensionEffect(uint32_t id, int edge) {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
 
diff --git a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
index c7cc21c..976cecb 100644
--- a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
@@ -21,7 +21,7 @@
 
 #include "FrontEnd/LayerLifecycleManager.h"
 #include "LayerHierarchyTest.h"
-#include "TransactionState.h"
+#include "QueuedTransactionState.h"
 
 using namespace android::surfaceflinger;
 
@@ -104,7 +104,7 @@
     EXPECT_FALSE(managedLayers.front()->changes.test(RequestedLayerState::Changes::Z));
 
     // apply transactions that do not affect the hierarchy
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     transactions.emplace_back();
     transactions.back().states.push_back({});
     transactions.back().states.front().state.backgroundBlurRadius = 22;
@@ -297,7 +297,7 @@
     layers.emplace_back(rootLayer(1));
     lifecycleManager.addLayers(std::move(layers));
 
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     transactions.emplace_back();
     transactions.back().states.push_back({});
     transactions.back().states.front().state.bgColor.a = 0.5;
@@ -326,7 +326,7 @@
     layers.emplace_back(rootLayer(1));
     lifecycleManager.addLayers(std::move(layers));
 
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     transactions.emplace_back();
     transactions.back().states.push_back({});
     transactions.back().states.front().state.bgColor.a = 0.5;
@@ -360,7 +360,7 @@
     layers.emplace_back(rootLayer(1));
     lifecycleManager.addLayers(std::move(layers));
 
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     transactions.emplace_back();
     transactions.back().states.push_back({});
     transactions.back().states.front().state.bgColor.a = 0.5;
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 4d322ef..1177d16 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -329,7 +329,7 @@
 }
 
 TEST_F(LayerSnapshotTest, UpdateMetadata) {
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     transactions.emplace_back();
     transactions.back().states.push_back({});
     transactions.back().states.front().state.what = layer_state_t::eMetadataChanged;
@@ -374,7 +374,7 @@
 TEST_F(LayerSnapshotTest, UpdateMetadataOfHiddenLayers) {
     hideLayer(1);
 
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     transactions.emplace_back();
     transactions.back().states.push_back({});
     transactions.back().states.front().state.what = layer_state_t::eMetadataChanged;
@@ -1557,7 +1557,7 @@
     setColor(3, {-1._hf, -1._hf, -1._hf});
     UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
 
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     transactions.emplace_back();
     transactions.back().states.push_back({});
     transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
@@ -1586,7 +1586,7 @@
     setColor(3, {-1._hf, -1._hf, -1._hf});
     UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
 
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     transactions.emplace_back();
     transactions.back().states.push_back({});
     transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
@@ -2021,7 +2021,7 @@
     EXPECT_FALSE(getSnapshot(1)->contentDirty);
 }
 TEST_F(LayerSnapshotTest, shouldUpdatePictureProfileHandle) {
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     transactions.emplace_back();
     transactions.back().states.push_back({});
     transactions.back().states.back().layerId = 1;
@@ -2040,7 +2040,7 @@
 
 TEST_F(LayerSnapshotTest, shouldUpdatePictureProfilePriorityFromAppContentPriority) {
     {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
         transactions.back().states.back().layerId = 1;
@@ -2063,7 +2063,7 @@
                   2);
     }
     {
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
         transactions.back().states.push_back({});
         transactions.back().states.back().layerId = 1;
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index bd1382e..3455c13 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -514,7 +514,7 @@
                                              mergedTransactionIds);
     }
 
-    auto setTransactionStateInternal(TransactionState& transaction) {
+    auto setTransactionStateInternal(QueuedTransactionState& transaction) {
         return FTL_FAKE_GUARD(kMainThreadContext,
                               mFlinger->mTransactionHandler.queueTransaction(
                                       std::move(transaction)));
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 1e8cd0a..69dfcc4 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -33,8 +33,8 @@
 #include <vector>
 
 #include "FrontEnd/TransactionHandler.h"
+#include "QueuedTransactionState.h"
 #include "TestableSurfaceFlinger.h"
-#include "TransactionState.h"
 
 #include <com_android_graphics_surfaceflinger_flags.h>
 
@@ -84,7 +84,7 @@
         static_assert(0xffffffffffffffff == static_cast<uint64_t>(-1));
     };
 
-    void checkEqual(TransactionInfo info, TransactionState state) {
+    void checkEqual(TransactionInfo info, QueuedTransactionState state) {
         EXPECT_EQ(0u, info.states.size());
         EXPECT_EQ(0u, state.states.size());
 
@@ -318,7 +318,7 @@
     auto applyToken2 = sp<BBinder>::make();
 
     // Transaction 1 has a buffer with an unfired fence. It should not be ready to be applied.
-    TransactionState transaction1;
+    QueuedTransactionState transaction1;
     transaction1.applyToken = applyToken1;
     transaction1.id = 42069;
     transaction1.states.emplace_back();
@@ -340,7 +340,7 @@
     transaction1.isAutoTimestamp = true;
 
     // Transaction 2 should be ready to be applied.
-    TransactionState transaction2;
+    QueuedTransactionState transaction2;
     transaction2.applyToken = applyToken2;
     transaction2.id = 2;
     transaction2.isAutoTimestamp = true;
@@ -446,15 +446,15 @@
                 resolvedStates.emplace_back(resolvedState);
             }
 
-            TransactionState transactionState(transaction.frameTimelineInfo, resolvedStates,
-                                              transaction.displays, transaction.flags,
-                                              transaction.applyToken,
-                                              transaction.inputWindowCommands,
-                                              transaction.desiredPresentTime,
-                                              transaction.isAutoTimestamp, {}, systemTime(),
-                                              mHasListenerCallbacks, mCallbacks, getpid(),
-                                              static_cast<int>(getuid()), transaction.id,
-                                              transaction.mergedTransactionIds);
+            QueuedTransactionState transactionState(transaction.frameTimelineInfo, resolvedStates,
+                                                    transaction.displays, transaction.flags,
+                                                    transaction.applyToken,
+                                                    transaction.inputWindowCommands,
+                                                    transaction.desiredPresentTime,
+                                                    transaction.isAutoTimestamp, {}, systemTime(),
+                                                    mHasListenerCallbacks, mCallbacks, getpid(),
+                                                    static_cast<int>(getuid()), transaction.id,
+                                                    transaction.mergedTransactionIds);
             mFlinger.setTransactionStateInternal(transactionState);
         }
         mFlinger.flushTransactionQueues();
@@ -955,12 +955,12 @@
 
 TEST(TransactionHandlerTest, QueueTransaction) {
     TransactionHandler handler;
-    TransactionState transaction;
+    QueuedTransactionState transaction;
     transaction.applyToken = sp<BBinder>::make();
     transaction.id = 42;
     handler.queueTransaction(std::move(transaction));
     handler.collectTransactions();
-    std::vector<TransactionState> transactionsReadyToBeApplied = handler.flushTransactions();
+    std::vector<QueuedTransactionState> transactionsReadyToBeApplied = handler.flushTransactions();
 
     EXPECT_EQ(transactionsReadyToBeApplied.size(), 1u);
     EXPECT_EQ(transactionsReadyToBeApplied.front().id, 42u);
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index af02330..d3eec5c 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -30,7 +30,7 @@
 
 TEST(TransactionProtoParserTest, parse) {
     const sp<IBinder> displayHandle = sp<BBinder>::make();
-    TransactionState t1;
+    QueuedTransactionState t1;
     t1.originPid = 1;
     t1.originUid = 2;
     t1.frameTimelineInfo.vsyncId = 3;
@@ -86,7 +86,7 @@
     TransactionProtoParser parser(std::make_unique<TestMapper>(displayHandle));
 
     perfetto::protos::TransactionState proto = parser.toProto(t1);
-    TransactionState t2 = parser.fromProto(proto);
+    QueuedTransactionState 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 f8f08c7..036d8c4 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -49,19 +49,19 @@
 
     void queueAndCommitTransaction(int64_t vsyncId) {
         frontend::Update update;
-        TransactionState transaction;
+        QueuedTransactionState transaction;
         transaction.id = static_cast<uint64_t>(vsyncId * 3);
         transaction.originUid = 1;
         transaction.originPid = 2;
         mTracing.addQueuedTransaction(transaction);
-        std::vector<TransactionState> transactions;
+        std::vector<QueuedTransactionState> transactions;
         update.transactions.emplace_back(transaction);
         mTracing.addCommittedTransactions(vsyncId, 0, update, {}, false);
         flush();
     }
 
     void verifyEntry(const perfetto::protos::TransactionTraceEntry& actualProto,
-                     const std::vector<TransactionState>& expectedTransactions,
+                     const std::vector<QueuedTransactionState>& expectedTransactions,
                      int64_t expectedVsyncId) {
         EXPECT_EQ(actualProto.vsync_id(), expectedVsyncId);
         ASSERT_EQ(actualProto.transactions().size(),
@@ -92,10 +92,10 @@
 };
 
 TEST_F(TransactionTracingTest, addTransactions) {
-    std::vector<TransactionState> transactions;
+    std::vector<QueuedTransactionState> transactions;
     transactions.reserve(100);
     for (uint64_t i = 0; i < 100; i++) {
-        TransactionState transaction;
+        QueuedTransactionState transaction;
         transaction.id = i;
         transaction.originPid = static_cast<int32_t>(i);
         transaction.mergedTransactionIds = std::vector<uint64_t>{i + 100, i + 102};
@@ -108,13 +108,13 @@
     int64_t firstTransactionSetVsyncId = 42;
     frontend::Update firstUpdate;
     firstUpdate.transactions =
-            std::vector<TransactionState>(transactions.begin() + 50, transactions.end());
+            std::vector<QueuedTransactionState>(transactions.begin() + 50, transactions.end());
     mTracing.addCommittedTransactions(firstTransactionSetVsyncId, 0, firstUpdate, {}, false);
 
     int64_t secondTransactionSetVsyncId = 43;
     frontend::Update secondUpdate;
     secondUpdate.transactions =
-            std::vector<TransactionState>(transactions.begin(), transactions.begin() + 50);
+            std::vector<QueuedTransactionState>(transactions.begin(), transactions.begin() + 50);
     mTracing.addCommittedTransactions(secondTransactionSetVsyncId, 0, secondUpdate, {}, false);
     flush();
 
@@ -140,7 +140,7 @@
                     getLayerCreationArgs(mChildLayerId, mParentLayerId,
                                          /*layerIdToMirror=*/UNASSIGNED_LAYER_ID, /*flags=*/456,
                                          /*addToRoot=*/true));
-            TransactionState transaction;
+            QueuedTransactionState transaction;
             transaction.id = 50;
             ResolvedComposerState layerState;
             layerState.layerId = mParentLayerId;
@@ -164,7 +164,7 @@
         // add transactions that modify the layer state further so we can test that layer state
         // gets merged
         {
-            TransactionState transaction;
+            QueuedTransactionState transaction;
             transaction.id = 51;
             ResolvedComposerState layerState;
             layerState.layerId = mParentLayerId;
@@ -278,7 +278,7 @@
                                          /*layerIdToMirror=*/mLayerId, /*flags=*/0,
                                          /*addToRoot=*/false));
 
-            TransactionState transaction;
+            QueuedTransactionState transaction;
             transaction.id = 50;
             ResolvedComposerState layerState;
             layerState.layerId = mLayerId;