Merge changes from topics "GL_screen_decor", "VK_screen_decor"

* changes:
  Expose VK_FORMAT_R8_UNORM swapchain format if supported by underlying system
  Interpret the new R8 EGLConfig properly
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 34ccb21..8da1352 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -11,6 +11,286 @@
 
 # Grant unix world read/write permissions to kernel tracepoints.
 # Access control to these files is now entirely in selinux policy.
+    chmod 0755 /sys/kernel/debug/tracing/events
+    chmod 0755 /sys/kernel/debug/tracing/events/binder
+    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_lock
+    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_locked
+    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_set_priority
+    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_transaction
+    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_transaction_alloc_buf
+    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_transaction_received
+    chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_unlock
+    chmod 0755 /sys/kernel/debug/tracing/events/block
+    chmod 0755 /sys/kernel/debug/tracing/events/block/block_rq_complete
+    chmod 0755 /sys/kernel/debug/tracing/events/block/block_rq_issue
+    chmod 0755 /sys/kernel/debug/tracing/events/cgroup
+    chmod 0755 /sys/kernel/debug/tracing/events/clk
+    chmod 0755 /sys/kernel/debug/tracing/events/clk/clk_disable
+    chmod 0755 /sys/kernel/debug/tracing/events/clk/clk_enable
+    chmod 0755 /sys/kernel/debug/tracing/events/clk/clk_set_rate
+    chmod 0755 /sys/kernel/debug/tracing/events/cpufreq_interactive
+    chmod 0755 /sys/kernel/debug/tracing/events/cpuhp
+    chmod 0755 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_enter
+    chmod 0755 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_exit
+    chmod 0755 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_pause
+    chmod 0755 /sys/kernel/debug/tracing/events/dma_fence
+    chmod 0755 /sys/kernel/debug/tracing/events/ext4
+    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin
+    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end
+    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_es_lookup_extent_enter
+    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_es_lookup_extent_exit
+    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_load_inode
+    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter
+    chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit
+    chmod 0755 /sys/kernel/debug/tracing/events/f2fs
+    chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_get_data_block
+    chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_iget
+    chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter
+    chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit
+    chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin
+    chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end
+    chmod 0755 /sys/kernel/debug/tracing/events/fence
+    chmod 0755 /sys/kernel/debug/tracing/events/filemap
+    chmod 0755 /sys/kernel/debug/tracing/events/filemap/mm_filemap_add_to_page_cache
+    chmod 0755 /sys/kernel/debug/tracing/events/filemap/mm_filemap_delete_from_page_cache
+    chmod 0755 /sys/kernel/debug/tracing/events/gpu_mem
+    chmod 0755 /sys/kernel/debug/tracing/events/gpu_mem/gpu_mem_total
+    chmod 0755 /sys/kernel/debug/tracing/events/i2c
+    chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_read
+    chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_reply
+    chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_result
+    chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_write
+    chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_read
+    chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_reply
+    chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_result
+    chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_write
+    chmod 0755 /sys/kernel/debug/tracing/events/ion
+    chmod 0755 /sys/kernel/debug/tracing/events/ion/ion_stat
+    chmod 0755 /sys/kernel/debug/tracing/events/ipi
+    chmod 0755 /sys/kernel/debug/tracing/events/ipi/ipi_entry
+    chmod 0755 /sys/kernel/debug/tracing/events/ipi/ipi_exit
+    chmod 0755 /sys/kernel/debug/tracing/events/ipi/ipi_raise
+    chmod 0755 /sys/kernel/debug/tracing/events/irq
+    chmod 0755 /sys/kernel/debug/tracing/events/irq/irq_handler_entry
+    chmod 0755 /sys/kernel/debug/tracing/events/irq/irq_handler_exit
+    chmod 0755 /sys/kernel/debug/tracing/events/irq/softirq_entry
+    chmod 0755 /sys/kernel/debug/tracing/events/irq/softirq_exit
+    chmod 0755 /sys/kernel/debug/tracing/events/irq/softirq_raise
+    chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_entry
+    chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_exit
+    chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_hi_entry
+    chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_hi_exit
+    chmod 0755 /sys/kernel/debug/tracing/events/kmem
+    chmod 0755 /sys/kernel/debug/tracing/events/kmem/ion_heap_grow
+    chmod 0755 /sys/kernel/debug/tracing/events/kmem/ion_heap_shrink
+    chmod 0755 /sys/kernel/debug/tracing/events/kmem/rss_stat
+    chmod 0755 /sys/kernel/debug/tracing/events/lowmemorykiller
+    chmod 0755 /sys/kernel/debug/tracing/events/lowmemorykiller/lowmemory_kill
+    chmod 0755 /sys/kernel/debug/tracing/events/mm_event
+    chmod 0755 /sys/kernel/debug/tracing/events/mm_event/mm_event_record
+    chmod 0755 /sys/kernel/debug/tracing/events/oom
+    chmod 0755 /sys/kernel/debug/tracing/events/oom/mark_victim
+    chmod 0755 /sys/kernel/debug/tracing/events/oom/oom_score_adj_update
+    chmod 0755 /sys/kernel/debug/tracing/events/power
+    chmod 0755 /sys/kernel/debug/tracing/events/power/clock_disable
+    chmod 0755 /sys/kernel/debug/tracing/events/power/clock_enable
+    chmod 0755 /sys/kernel/debug/tracing/events/power/clock_set_rate
+    chmod 0755 /sys/kernel/debug/tracing/events/power/cpu_frequency
+    chmod 0755 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits
+    chmod 0755 /sys/kernel/debug/tracing/events/power/cpu_idle
+    chmod 0755 /sys/kernel/debug/tracing/events/power/gpu_frequency
+    chmod 0755 /sys/kernel/debug/tracing/events/power/suspend_resume
+    chmod 0755 /sys/kernel/debug/tracing/events/sched
+    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_blocked_reason
+    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug
+    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_pi_setprio
+    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_process_exit
+    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_process_free
+    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_switch
+    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_wakeup
+    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_wakeup_new
+    chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_waking
+    chmod 0755 /sys/kernel/debug/tracing/events/signal
+    chmod 0755 /sys/kernel/debug/tracing/events/signal/signal_deliver
+    chmod 0755 /sys/kernel/debug/tracing/events/signal/signal_generate
+    chmod 0755 /sys/kernel/debug/tracing/events/sync
+    chmod 0755 /sys/kernel/debug/tracing/events/task
+    chmod 0755 /sys/kernel/debug/tracing/events/task/task_newtask
+    chmod 0755 /sys/kernel/debug/tracing/events/task/task_rename
+    chmod 0755 /sys/kernel/debug/tracing/events/thermal
+    chmod 0755 /sys/kernel/debug/tracing/events/thermal/cdev_update
+    chmod 0755 /sys/kernel/debug/tracing/events/thermal/thermal_temperature
+    chmod 0755 /sys/kernel/debug/tracing/events/vmscan
+    chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin
+    chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end
+    chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep
+    chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake
+    chmod 0755 /sys/kernel/debug/tracing/options
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu0
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu1
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu2
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu3
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu4
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu5
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu6
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu7
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu8
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu9
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu10
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu11
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu12
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu13
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu14
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu15
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu16
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu17
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu18
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu19
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu20
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu21
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu22
+    chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu23
+    chmod 0755 /sys/kernel/tracing/events
+    chmod 0755 /sys/kernel/tracing/events/binder
+    chmod 0755 /sys/kernel/tracing/events/binder/binder_lock
+    chmod 0755 /sys/kernel/tracing/events/binder/binder_locked
+    chmod 0755 /sys/kernel/tracing/events/binder/binder_set_priority
+    chmod 0755 /sys/kernel/tracing/events/binder/binder_transaction
+    chmod 0755 /sys/kernel/tracing/events/binder/binder_transaction_alloc_buf
+    chmod 0755 /sys/kernel/tracing/events/binder/binder_transaction_received
+    chmod 0755 /sys/kernel/tracing/events/binder/binder_unlock
+    chmod 0755 /sys/kernel/tracing/events/block
+    chmod 0755 /sys/kernel/tracing/events/block/block_rq_complete
+    chmod 0755 /sys/kernel/tracing/events/block/block_rq_issue
+    chmod 0755 /sys/kernel/tracing/events/cgroup
+    chmod 0755 /sys/kernel/tracing/events/clk
+    chmod 0755 /sys/kernel/tracing/events/clk/clk_disable
+    chmod 0755 /sys/kernel/tracing/events/clk/clk_enable
+    chmod 0755 /sys/kernel/tracing/events/clk/clk_set_rate
+    chmod 0755 /sys/kernel/tracing/events/cpufreq_interactive
+    chmod 0755 /sys/kernel/tracing/events/cpuhp
+    chmod 0755 /sys/kernel/tracing/events/cpuhp/cpuhp_enter
+    chmod 0755 /sys/kernel/tracing/events/cpuhp/cpuhp_exit
+    chmod 0755 /sys/kernel/tracing/events/cpuhp/cpuhp_pause
+    chmod 0755 /sys/kernel/tracing/events/dma_fence
+    chmod 0755 /sys/kernel/tracing/events/ext4
+    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_da_write_begin
+    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_da_write_end
+    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_es_lookup_extent_enter
+    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_es_lookup_extent_exit
+    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_load_inode
+    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_sync_file_enter
+    chmod 0755 /sys/kernel/tracing/events/ext4/ext4_sync_file_exit
+    chmod 0755 /sys/kernel/tracing/events/f2fs
+    chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block
+    chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_iget
+    chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_enter
+    chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_exit
+    chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_write_begin
+    chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_write_end
+    chmod 0755 /sys/kernel/tracing/events/fence
+    chmod 0755 /sys/kernel/tracing/events/filemap
+    chmod 0755 /sys/kernel/tracing/events/filemap/mm_filemap_add_to_page_cache
+    chmod 0755 /sys/kernel/tracing/events/filemap/mm_filemap_delete_from_page_cache
+    chmod 0755 /sys/kernel/tracing/events/gpu_mem
+    chmod 0755 /sys/kernel/tracing/events/gpu_mem/gpu_mem_total
+    chmod 0755 /sys/kernel/tracing/events/i2c
+    chmod 0755 /sys/kernel/tracing/events/i2c/i2c_read
+    chmod 0755 /sys/kernel/tracing/events/i2c/i2c_reply
+    chmod 0755 /sys/kernel/tracing/events/i2c/i2c_result
+    chmod 0755 /sys/kernel/tracing/events/i2c/i2c_write
+    chmod 0755 /sys/kernel/tracing/events/i2c/smbus_read
+    chmod 0755 /sys/kernel/tracing/events/i2c/smbus_reply
+    chmod 0755 /sys/kernel/tracing/events/i2c/smbus_result
+    chmod 0755 /sys/kernel/tracing/events/i2c/smbus_write
+    chmod 0755 /sys/kernel/tracing/events/ion
+    chmod 0755 /sys/kernel/tracing/events/ion/ion_stat
+    chmod 0755 /sys/kernel/tracing/events/ipi
+    chmod 0755 /sys/kernel/tracing/events/ipi/ipi_entry
+    chmod 0755 /sys/kernel/tracing/events/ipi/ipi_exit
+    chmod 0755 /sys/kernel/tracing/events/ipi/ipi_raise
+    chmod 0755 /sys/kernel/tracing/events/irq
+    chmod 0755 /sys/kernel/tracing/events/irq/irq_handler_entry
+    chmod 0755 /sys/kernel/tracing/events/irq/irq_handler_exit
+    chmod 0755 /sys/kernel/tracing/events/irq/softirq_entry
+    chmod 0755 /sys/kernel/tracing/events/irq/softirq_exit
+    chmod 0755 /sys/kernel/tracing/events/irq/softirq_raise
+    chmod 0755 /sys/kernel/tracing/events/irq/tasklet_entry
+    chmod 0755 /sys/kernel/tracing/events/irq/tasklet_exit
+    chmod 0755 /sys/kernel/tracing/events/irq/tasklet_hi_entry
+    chmod 0755 /sys/kernel/tracing/events/irq/tasklet_hi_exit
+    chmod 0755 /sys/kernel/tracing/events/kmem
+    chmod 0755 /sys/kernel/tracing/events/kmem/ion_heap_grow
+    chmod 0755 /sys/kernel/tracing/events/kmem/ion_heap_shrink
+    chmod 0755 /sys/kernel/tracing/events/kmem/rss_stat
+    chmod 0755 /sys/kernel/tracing/events/lowmemorykiller
+    chmod 0755 /sys/kernel/tracing/events/lowmemorykiller/lowmemory_kill
+    chmod 0755 /sys/kernel/tracing/events/mm_event
+    chmod 0755 /sys/kernel/tracing/events/mm_event/mm_event_record
+    chmod 0755 /sys/kernel/tracing/events/oom
+    chmod 0755 /sys/kernel/tracing/events/oom/mark_victim
+    chmod 0755 /sys/kernel/tracing/events/oom/oom_score_adj_update
+    chmod 0755 /sys/kernel/tracing/events/power
+    chmod 0755 /sys/kernel/tracing/events/power/clock_disable
+    chmod 0755 /sys/kernel/tracing/events/power/clock_enable
+    chmod 0755 /sys/kernel/tracing/events/power/clock_set_rate
+    chmod 0755 /sys/kernel/tracing/events/power/cpu_frequency
+    chmod 0755 /sys/kernel/tracing/events/power/cpu_frequency_limits
+    chmod 0755 /sys/kernel/tracing/events/power/cpu_idle
+    chmod 0755 /sys/kernel/tracing/events/power/gpu_frequency
+    chmod 0755 /sys/kernel/tracing/events/power/suspend_resume
+    chmod 0755 /sys/kernel/tracing/events/sched
+    chmod 0755 /sys/kernel/tracing/events/sched/sched_blocked_reason
+    chmod 0755 /sys/kernel/tracing/events/sched/sched_cpu_hotplug
+    chmod 0755 /sys/kernel/tracing/events/sched/sched_pi_setprio
+    chmod 0755 /sys/kernel/tracing/events/sched/sched_process_exit
+    chmod 0755 /sys/kernel/tracing/events/sched/sched_process_free
+    chmod 0755 /sys/kernel/tracing/events/sched/sched_switch
+    chmod 0755 /sys/kernel/tracing/events/sched/sched_wakeup
+    chmod 0755 /sys/kernel/tracing/events/sched/sched_wakeup_new
+    chmod 0755 /sys/kernel/tracing/events/sched/sched_waking
+    chmod 0755 /sys/kernel/tracing/events/signal
+    chmod 0755 /sys/kernel/tracing/events/signal/signal_deliver
+    chmod 0755 /sys/kernel/tracing/events/signal/signal_generate
+    chmod 0755 /sys/kernel/tracing/events/sync
+    chmod 0755 /sys/kernel/tracing/events/task
+    chmod 0755 /sys/kernel/tracing/events/task/task_newtask
+    chmod 0755 /sys/kernel/tracing/events/task/task_rename
+    chmod 0755 /sys/kernel/tracing/events/thermal
+    chmod 0755 /sys/kernel/tracing/events/thermal/cdev_update
+    chmod 0755 /sys/kernel/tracing/events/thermal/thermal_temperature
+    chmod 0755 /sys/kernel/tracing/events/vmscan
+    chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin
+    chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end
+    chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep
+    chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake
+    chmod 0755 /sys/kernel/tracing/options
+    chmod 0755 /sys/kernel/tracing/per_cpu
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu0
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu1
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu2
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu3
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu4
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu5
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu6
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu7
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu8
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu9
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu10
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu11
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu12
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu13
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu14
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu15
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu16
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu17
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu18
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu19
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu20
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu21
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu22
+    chmod 0755 /sys/kernel/tracing/per_cpu/cpu23
     chmod 0666 /sys/kernel/debug/tracing/trace_clock
     chmod 0666 /sys/kernel/tracing/trace_clock
     chmod 0666 /sys/kernel/debug/tracing/buffer_size_kb
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 4561d6e..e2fc18d 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -24,13 +24,15 @@
     target: {
         darwin: {
             enabled: false,
-        }
+        },
     },
     apex_available: [
         "//apex_available:platform",
         "com.android.compos",
+        "com.android.uwb",
         "com.android.virt",
     ],
+    min_sdk_version: "current",
 }
 
 rust_library {
@@ -45,7 +47,7 @@
     target: {
         darwin: {
             enabled: false,
-        }
+        },
     },
     apex_available: [
         "//apex_available:platform",
@@ -69,13 +71,15 @@
     target: {
         darwin: {
             enabled: false,
-        }
+        },
     },
     apex_available: [
         "//apex_available:platform",
         "com.android.compos",
+        "com.android.uwb",
         "com.android.virt",
     ],
+    min_sdk_version: "current",
     lints: "none",
     clippy_lints: "none",
 }
@@ -88,20 +92,31 @@
     bindgen_flags: [
         // Unfortunately the only way to specify the rust_non_exhaustive enum
         // style for a type is to make it the default
-        "--default-enum-style", "rust_non_exhaustive",
+        "--default-enum-style",
+        "rust_non_exhaustive",
         // and then specify constified enums for the enums we don't want
         // rustified
-        "--constified-enum", "android::c_interface::consts::.*",
+        "--constified-enum",
+        "android::c_interface::consts::.*",
 
-        "--allowlist-type", "android::c_interface::.*",
-        "--allowlist-type", "AStatus",
-        "--allowlist-type", "AIBinder_Class",
-        "--allowlist-type", "AIBinder",
-        "--allowlist-type", "AIBinder_Weak",
-        "--allowlist-type", "AIBinder_DeathRecipient",
-        "--allowlist-type", "AParcel",
-        "--allowlist-type", "binder_status_t",
-        "--allowlist-function", ".*",
+        "--allowlist-type",
+        "android::c_interface::.*",
+        "--allowlist-type",
+        "AStatus",
+        "--allowlist-type",
+        "AIBinder_Class",
+        "--allowlist-type",
+        "AIBinder",
+        "--allowlist-type",
+        "AIBinder_Weak",
+        "--allowlist-type",
+        "AIBinder_DeathRecipient",
+        "--allowlist-type",
+        "AParcel",
+        "--allowlist-type",
+        "binder_status_t",
+        "--allowlist-function",
+        ".*",
     ],
     shared_libs: [
         "libbinder_ndk",
@@ -127,8 +142,10 @@
     apex_available: [
         "//apex_available:platform",
         "com.android.compos",
+        "com.android.uwb",
         "com.android.virt",
     ],
+    min_sdk_version: "current",
 }
 
 // TODO(b/184872979): remove once the Rust API is created.
@@ -142,8 +159,10 @@
     ],
     apex_available: [
         "com.android.compos",
+        "com.android.uwb",
         "com.android.virt",
     ],
+    min_sdk_version: "current",
 }
 
 rust_test {
diff --git a/libs/graphicsenv/GpuStatsInfo.cpp b/libs/graphicsenv/GpuStatsInfo.cpp
index f2d0943..858739c 100644
--- a/libs/graphicsenv/GpuStatsInfo.cpp
+++ b/libs/graphicsenv/GpuStatsInfo.cpp
@@ -88,6 +88,7 @@
     if ((status = parcel->writeBool(cpuVulkanInUse)) != OK) return status;
     if ((status = parcel->writeBool(falsePrerotation)) != OK) return status;
     if ((status = parcel->writeBool(gles1InUse)) != OK) return status;
+    if ((status = parcel->writeBool(angleInUse)) != OK) return status;
     return OK;
 }
 
@@ -101,6 +102,7 @@
     if ((status = parcel->readBool(&cpuVulkanInUse)) != OK) return status;
     if ((status = parcel->readBool(&falsePrerotation)) != OK) return status;
     if ((status = parcel->readBool(&gles1InUse)) != OK) return status;
+    if ((status = parcel->readBool(&angleInUse)) != OK) return status;
     return OK;
 }
 
@@ -111,6 +113,7 @@
     StringAppendF(&result, "cpuVulkanInUse = %d\n", cpuVulkanInUse);
     StringAppendF(&result, "falsePrerotation = %d\n", falsePrerotation);
     StringAppendF(&result, "gles1InUse = %d\n", gles1InUse);
+    StringAppendF(&result, "angleInUse = %d\n", angleInUse);
     result.append("glDriverLoadingTime:");
     for (int32_t loadingTime : glDriverLoadingTime) {
         StringAppendF(&result, " %d", loadingTime);
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
index 9aba69f..5b513d2 100644
--- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <chrono>
 #include <string>
 #include <vector>
 
@@ -52,7 +53,7 @@
 };
 
 /*
- * class for transporting gpu app stats from GpuService to authorized recipents.
+ * class for transporting gpu app stats from GpuService to authorized recipients.
  * This class is intended to be a data container.
  */
 class GpuStatsAppInfo : public Parcelable {
@@ -72,6 +73,9 @@
     bool cpuVulkanInUse = false;
     bool falsePrerotation = false;
     bool gles1InUse = false;
+    bool angleInUse = false;
+
+    std::chrono::time_point<std::chrono::system_clock> lastAccessTime;
 };
 
 /*
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index dd50ca7..85a4b67 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -132,12 +132,11 @@
     }
 }
 
-BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
-                                   int width, int height, int32_t format)
-      : mSurfaceControl(surface),
-        mSize(width, height),
+BLASTBufferQueue::BLASTBufferQueue(const std::string& name)
+      : mSurfaceControl(nullptr),
+        mSize(1, 1),
         mRequestedSize(mSize),
-        mFormat(format),
+        mFormat(PIXEL_FORMAT_RGBA_8888),
         mSyncTransaction(nullptr) {
     createBufferQueue(&mProducer, &mConsumer);
     // since the adapter is in the client process, set dequeue timeout
@@ -158,25 +157,21 @@
     mBufferItemConsumer->setName(String8(consumerName.c_str()));
     mBufferItemConsumer->setFrameAvailableListener(this);
     mBufferItemConsumer->setBufferFreedListener(this);
-    mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
-    mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
     mBufferItemConsumer->setBlastBufferQueue(this);
 
     ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
     mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
     mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
-
-    mTransformHint = mSurfaceControl->getTransformHint();
-    mBufferItemConsumer->setTransformHint(mTransformHint);
-    SurfaceComposerClient::Transaction()
-            .setFlags(surface, layer_state_t::eEnableBackpressure,
-                      layer_state_t::eEnableBackpressure)
-            .setApplyToken(mApplyToken)
-            .apply();
     mNumAcquired = 0;
     mNumFrameAvailable = 0;
-    BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", width,
-             height, format, mTransformHint);
+    BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", mSize.width,
+             mSize.height, mFormat, mTransformHint);
+}
+
+BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
+                                   int width, int height, int32_t format)
+      : BLASTBufferQueue(name) {
+    update(surface, width, height, format);
 }
 
 BLASTBufferQueue::~BLASTBufferQueue() {
@@ -228,12 +223,9 @@
             // If the buffer supports scaling, update the frame immediately since the client may
             // want to scale the existing buffer to the new size.
             mSize = mRequestedSize;
-            // We only need to update the scale if we've received at least one buffer. The reason
-            // for this is the scale is calculated based on the requested size and buffer size.
-            // If there's no buffer, the scale will always be 1.
             SurfaceComposerClient::Transaction* destFrameTransaction =
                     (outTransaction) ? outTransaction : &t;
-            if (mSurfaceControl != nullptr && mLastBufferInfo.hasBuffer) {
+            if (mSurfaceControl != nullptr) {
                 destFrameTransaction->setDestinationFrame(mSurfaceControl,
                                                           Rect(0, 0, newSize.getWidth(),
                                                                newSize.getHeight()));
@@ -508,9 +500,8 @@
     // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
     incStrong((void*)transactionCallbackThunk);
 
-    const bool sizeHasChanged = mRequestedSize != mSize;
+    const bool updateDestinationFrame = mRequestedSize != mSize;
     mSize = mRequestedSize;
-    const bool updateDestinationFrame = sizeHasChanged || !mLastBufferInfo.hasBuffer;
     Rect crop = computeCrop(bufferItem);
     mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
                            bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index cd1c810..ec0573a 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -550,9 +550,7 @@
 }
 
 bool InputWindowCommands::empty() const {
-    bool empty = true;
-    empty = focusRequests.empty() && !syncInputWindows;
-    return empty;
+    return focusRequests.empty() && !syncInputWindows;
 }
 
 void InputWindowCommands::clear() {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index e1fe26a..aafa5e4 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -62,6 +62,14 @@
 
 ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService);
 
+namespace {
+// Initialize transaction id counter used to generate transaction ids
+std::atomic<uint32_t> idCounter = 0;
+int64_t generateId() {
+    return (((int64_t)getpid()) << 32) | ++idCounter;
+}
+} // namespace
+
 ComposerService::ComposerService()
 : Singleton<ComposerService>() {
     Mutex::Autolock _l(mLock);
@@ -535,10 +543,6 @@
 
 // ---------------------------------------------------------------------------
 
-// Initialize transaction id counter used to generate transaction ids
-// Transactions will start counting at 1, 0 is used for invalid transactions
-std::atomic<uint32_t> SurfaceComposerClient::Transaction::idCounter = 1;
-
 SurfaceComposerClient::Transaction::Transaction() {
     mId = generateId();
 }
@@ -570,9 +574,6 @@
     return nullptr;
 }
 
-int64_t SurfaceComposerClient::Transaction::generateId() {
-    return (((int64_t)getpid()) << 32) | idCounter++;
-}
 
 status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) {
     const uint32_t forceSynchronous = parcel->readUint32();
@@ -825,7 +826,7 @@
 
     sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
     sf->setTransactionState(FrameTimelineInfo{}, {}, {}, 0, applyToken, {}, systemTime(), true,
-                            uncacheBuffer, false, {}, 0 /* Undefined transactionId */);
+                            uncacheBuffer, false, {}, generateId());
 }
 
 void SurfaceComposerClient::Transaction::cacheBuffers() {
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index d766173..8a2f392 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -74,6 +74,7 @@
     : public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener
 {
 public:
+    BLASTBufferQueue(const std::string& name);
     BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width,
                      int height, int32_t format);
 
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0fe1253..17b4846 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -366,8 +366,6 @@
 
     class Transaction : public Parcelable {
     private:
-        static std::atomic<uint32_t> idCounter;
-        int64_t generateId();
         void releaseBufferIfOverwriting(const layer_state_t& state);
 
     protected:
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index c447d31..18a4b2d 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -176,6 +176,8 @@
         static_cast<int>(HAL_DATASPACE_BT2020_HLG));
     static_assert(static_cast<int>(ADATASPACE_BT2020_ITU_HLG) ==
         static_cast<int>(HAL_DATASPACE_BT2020_ITU_HLG));
+    static_assert(static_cast<int>(DEPTH) == static_cast<int>(HAL_DATASPACE_DEPTH));
+    static_assert(static_cast<int>(DYNAMIC_DEPTH) == static_cast<int>(HAL_DATASPACE_DYNAMIC_DEPTH));
 
     if (!window || !query(window, NATIVE_WINDOW_IS_VALID) ||
             !isDataSpaceValid(window, dataSpace)) {
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 30ac220..771844f 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -541,7 +541,21 @@
      *
      * Use limited range, hybrid log gamma transfer and BT2020 standard.
      */
-    ADATASPACE_BT2020_ITU_HLG = 302383104 // STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED
+    ADATASPACE_BT2020_ITU_HLG = 302383104, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED
+
+    /**
+     * Depth:
+     *
+     * This value is valid with formats HAL_PIXEL_FORMAT_Y16 and HAL_PIXEL_FORMAT_BLOB.
+     */
+    DEPTH = 4096,
+
+    /**
+     * ISO 16684-1:2011(E) Dynamic Depth:
+     *
+     * Embedded depth metadata following the dynamic depth specification.
+     */
+    DYNAMIC_DEPTH = 4098
 };
 
 __END_DECLS
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index d395d06..b4cab39 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -57,8 +57,10 @@
     // orientation.
     uint32_t orientation = ui::Transform::ROT_0;
 
-    // SDR white point, -1f if unknown
-    float sdrWhitePointNits = -1.f;
+    // Target luminance of the display. -1f if unknown.
+    // All layers will be dimmed by (max(layer white points) / targetLuminanceNits).
+    // If the target luminance is unknown, then no display-level dimming occurs.
+    float targetLuminanceNits = -1.f;
 };
 
 static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) {
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 715f3f8..702e8b0 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -171,6 +171,12 @@
 
     // Name associated with the layer for debugging purposes.
     std::string name;
+
+    // Luminance of the white point for this layer. Used for linear dimming.
+    // Individual layers will be dimmed by (whitePointNits / maxWhitePoint).
+    // If white point nits are unknown, then this layer is assumed to have the
+    // same luminance as the brightest layer in the scene.
+    float whitePointNits = -1.f;
 };
 
 // Keep in sync with custom comparison function in
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 376e279..cc90946 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -46,6 +46,7 @@
 #include <cmath>
 #include <cstdint>
 #include <memory>
+#include <numeric>
 
 #include "../gl/GLExtensions.h"
 #include "Cache.h"
@@ -612,33 +613,33 @@
     AutoBackendTexture::CleanupManager& mMgr;
 };
 
-sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp<SkShader> shader,
-                                                              const LayerSettings& layer,
-                                                              const DisplaySettings& display,
-                                                              bool undoPremultipliedAlpha,
-                                                              bool requiresLinearEffect) {
-    const auto stretchEffect = layer.stretchEffect;
+sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(
+        const RuntimeEffectShaderParameters& parameters) {
     // The given surface will be stretched by HWUI via matrix transformation
     // which gets similar results for most surfaces
     // Determine later on if we need to leverage the stertch shader within
     // surface flinger
+    const auto& stretchEffect = parameters.layer.stretchEffect;
+    auto shader = parameters.shader;
     if (stretchEffect.hasEffect()) {
-        const auto targetBuffer = layer.source.buffer.buffer;
+        const auto targetBuffer = parameters.layer.source.buffer.buffer;
         const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
-        if (graphicBuffer && shader) {
+        if (graphicBuffer && parameters.shader) {
             shader = mStretchShaderFactory.createSkShader(shader, stretchEffect);
         }
     }
 
-    if (requiresLinearEffect) {
-        const ui::Dataspace inputDataspace =
-                mUseColorManagement ? layer.sourceDataspace : ui::Dataspace::V0_SRGB_LINEAR;
-        const ui::Dataspace outputDataspace =
-                mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR;
+    if (parameters.requiresLinearEffect) {
+        const ui::Dataspace inputDataspace = mUseColorManagement ? parameters.layer.sourceDataspace
+                                                                 : ui::Dataspace::V0_SRGB_LINEAR;
+        const ui::Dataspace outputDataspace = mUseColorManagement
+                ? parameters.display.outputDataspace
+                : ui::Dataspace::V0_SRGB_LINEAR;
 
-        auto effect = shaders::LinearEffect{.inputDataspace = inputDataspace,
-                                            .outputDataspace = outputDataspace,
-                                            .undoPremultipliedAlpha = undoPremultipliedAlpha};
+        auto effect =
+                shaders::LinearEffect{.inputDataspace = inputDataspace,
+                                      .outputDataspace = outputDataspace,
+                                      .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha};
 
         auto effectIter = mRuntimeEffects.find(effect);
         sk_sp<SkRuntimeEffect> runtimeEffect = nullptr;
@@ -648,16 +649,16 @@
         } else {
             runtimeEffect = effectIter->second;
         }
-        float maxLuminance = layer.source.buffer.maxLuminanceNits;
-        // If the buffer doesn't have a max luminance, treat it as SDR & use the display's SDR
-        // white point
-        if (maxLuminance <= 0.f) {
-            maxLuminance = display.sdrWhitePointNits;
-        }
-        return createLinearEffectShader(shader, effect, runtimeEffect, layer.colorTransform,
-                                        display.maxLuminance, maxLuminance);
+        mat4 colorTransform = parameters.layer.colorTransform;
+
+        colorTransform *=
+                mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio,
+                                 parameters.layerDimmingRatio, 1.f));
+        return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform,
+                                        parameters.display.maxLuminance,
+                                        parameters.layer.source.buffer.maxLuminanceNits);
     }
-    return shader;
+    return parameters.shader;
 }
 
 void SkiaGLRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
@@ -730,6 +731,11 @@
     return roundedRect;
 }
 
+static bool equalsWithinMargin(float expected, float value, float margin) {
+    LOG_ALWAYS_FATAL_IF(margin < 0.f, "Margin is negative!");
+    return std::abs(expected - value) < margin;
+}
+
 void SkiaGLRenderEngine::drawLayersInternal(
         const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
         const DisplaySettings& display, const std::vector<LayerSettings>& layers,
@@ -791,6 +797,18 @@
     const bool ctModifiesAlpha =
             displayColorTransform && !displayColorTransform->isAlphaUnchanged();
 
+    // Find the max layer white point to determine the max luminance of the scene...
+    const float maxLayerWhitePoint = std::transform_reduce(
+            layers.cbegin(), layers.cend(), 0.f,
+            [](float left, float right) { return std::max(left, right); },
+            [&](const auto& l) { return l.whitePointNits; });
+
+    // ...and compute the dimming ratio if dimming is requested
+    const float displayDimmingRatio = display.targetLuminanceNits > 0.f &&
+                    maxLayerWhitePoint > 0.f && display.targetLuminanceNits > maxLayerWhitePoint
+            ? maxLayerWhitePoint / display.targetLuminanceNits
+            : 1.f;
+
     // Find if any layers have requested blur, we'll use that info to decide when to render to an
     // offscreen buffer and when to render to the native buffer.
     sk_sp<SkSurface> activeSurface(dstSurface);
@@ -964,11 +982,14 @@
             drawShadow(canvas, rrect, layer.shadow);
         }
 
+        const float layerDimmingRatio = layer.whitePointNits <= 0.f
+                ? displayDimmingRatio
+                : (layer.whitePointNits / maxLayerWhitePoint) * displayDimmingRatio;
+
         const bool requiresLinearEffect = layer.colorTransform != mat4() ||
                 (mUseColorManagement &&
                  needsToneMapping(layer.sourceDataspace, display.outputDataspace)) ||
-                (display.sdrWhitePointNits > 0.f &&
-                 display.sdrWhitePointNits != display.maxLuminance);
+                !equalsWithinMargin(1.f, layerDimmingRatio, 0.001f);
 
         // quick abort from drawing the remaining portion of the layer
         if (layer.skipContentDraw ||
@@ -1067,9 +1088,20 @@
                                                            toSkColorSpace(layerDataspace)));
             }
 
-            paint.setShader(createRuntimeEffectShader(shader, layer, display,
-                                                      !item.isOpaque && item.usePremultipliedAlpha,
-                                                      requiresLinearEffect));
+            paint.setShader(createRuntimeEffectShader(
+                    RuntimeEffectShaderParameters{.shader = shader,
+                                                  .layer = layer,
+                                                  .display = display,
+                                                  .undoPremultipliedAlpha = !item.isOpaque &&
+                                                          item.usePremultipliedAlpha,
+                                                  .requiresLinearEffect = requiresLinearEffect,
+                                                  .layerDimmingRatio = layerDimmingRatio}));
+
+            // Turn on dithering when dimming beyond this threshold.
+            static constexpr float kDimmingThreshold = 0.2f;
+            if (layerDimmingRatio <= kDimmingThreshold) {
+                paint.setDither(true);
+            }
             paint.setAlphaf(layer.alpha);
         } else {
             ATRACE_NAME("DrawColor");
@@ -1079,9 +1111,13 @@
                                                                 .fB = color.b,
                                                                 .fA = layer.alpha},
                                                       toSkColorSpace(layerDataspace));
-            paint.setShader(createRuntimeEffectShader(shader, layer, display,
-                                                      /* undoPremultipliedAlpha */ false,
-                                                      requiresLinearEffect));
+            paint.setShader(createRuntimeEffectShader(
+                    RuntimeEffectShaderParameters{.shader = shader,
+                                                  .layer = layer,
+                                                  .display = display,
+                                                  .undoPremultipliedAlpha = false,
+                                                  .requiresLinearEffect = requiresLinearEffect,
+                                                  .layerDimmingRatio = layerDimmingRatio}));
         }
 
         if (layer.disableBlending) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 53792f9..a650313 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -106,12 +106,18 @@
     void initCanvas(SkCanvas* canvas, const DisplaySettings& display);
     void drawShadow(SkCanvas* canvas, const SkRRect& casterRRect,
                     const ShadowSettings& shadowSettings);
+
     // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned.
     // Otherwise it returns the input shader.
-    sk_sp<SkShader> createRuntimeEffectShader(sk_sp<SkShader> shader, const LayerSettings& layer,
-                                              const DisplaySettings& display,
-                                              bool undoPremultipliedAlpha,
-                                              bool requiresLinearEffect);
+    struct RuntimeEffectShaderParameters {
+        sk_sp<SkShader> shader;
+        const LayerSettings& layer;
+        const DisplaySettings& display;
+        bool undoPremultipliedAlpha;
+        bool requiresLinearEffect;
+        float layerDimmingRatio;
+    };
+    sk_sp<SkShader> createRuntimeEffectShader(const RuntimeEffectShaderParameters&);
 
     EGLDisplay mEGLDisplay;
     EGLContext mEGLContext;
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 8259063..eb2b2dc 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -208,6 +208,21 @@
                                                  renderengine::ExternalTexture::Usage::WRITEABLE);
     }
 
+    std::shared_ptr<renderengine::ExternalTexture> allocateAndFillSourceBuffer(uint32_t width,
+                                                                               uint32_t height,
+                                                                               ubyte4 color) {
+        const auto buffer = allocateSourceBuffer(width, height);
+        uint8_t* pixels;
+        buffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                  reinterpret_cast<void**>(&pixels));
+        pixels[0] = color.r;
+        pixels[1] = color.g;
+        pixels[2] = color.b;
+        pixels[3] = color.a;
+        buffer->getBuffer()->unlock();
+        return buffer;
+    }
+
     RenderEngineTest() {
         const ::testing::TestInfo* const test_info =
                 ::testing::UnitTest::GetInstance()->current_test_info();
@@ -2195,6 +2210,133 @@
     expectBufferColor(rect, 0, 128, 0, 128);
 }
 
+TEST_P(RenderEngineTest, testDimming) {
+    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+        return;
+    }
+    initializeRenderEngine();
+
+    const auto displayRect = Rect(3, 1);
+    const renderengine::DisplaySettings display{
+            .physicalDisplay = displayRect,
+            .clip = displayRect,
+            .outputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+            .targetLuminanceNits = 1000.f,
+    };
+
+    const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255));
+    const auto blueBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 0, 255, 255));
+    const auto redBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(255, 0, 0, 255));
+
+    const renderengine::LayerSettings greenLayer{
+            .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = greenBuffer,
+                                            .usePremultipliedAlpha = true,
+                                    },
+                    },
+            .alpha = 1.0f,
+            .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+            .whitePointNits = 200.f,
+    };
+
+    const renderengine::LayerSettings blueLayer{
+            .geometry.boundaries = FloatRect(1.f, 0.f, 2.f, 1.f),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = blueBuffer,
+                                            .usePremultipliedAlpha = true,
+                                    },
+                    },
+            .alpha = 1.0f,
+            .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+            .whitePointNits = 1000.f / 51.f,
+    };
+
+    const renderengine::LayerSettings redLayer{
+            .geometry.boundaries = FloatRect(2.f, 0.f, 3.f, 1.f),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = redBuffer,
+                                            .usePremultipliedAlpha = true,
+                                    },
+                    },
+            .alpha = 1.0f,
+            .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+            // When the white point is not set for a layer, just ignore it and treat it as the same
+            // as the max layer
+            .whitePointNits = -1.f,
+    };
+
+    std::vector<renderengine::LayerSettings> layers{greenLayer, blueLayer, redLayer};
+    invokeDraw(display, layers);
+
+    expectBufferColor(Rect(1, 1), 0, 51, 0, 255, 1);
+    expectBufferColor(Rect(1, 0, 2, 1), 0, 0, 5, 255, 1);
+    expectBufferColor(Rect(2, 0, 3, 1), 51, 0, 0, 255, 1);
+}
+
+TEST_P(RenderEngineTest, testDimming_withoutTargetLuminance) {
+    initializeRenderEngine();
+    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+        return;
+    }
+
+    const auto displayRect = Rect(2, 1);
+    const renderengine::DisplaySettings display{
+            .physicalDisplay = displayRect,
+            .clip = displayRect,
+            .outputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+            .targetLuminanceNits = -1.f,
+    };
+
+    const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255));
+    const auto blueBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 0, 255, 255));
+
+    const renderengine::LayerSettings greenLayer{
+            .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = greenBuffer,
+                                            .usePremultipliedAlpha = true,
+                                    },
+                    },
+            .alpha = 1.0f,
+            .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+            .whitePointNits = 200.f,
+    };
+
+    const renderengine::LayerSettings blueLayer{
+            .geometry.boundaries = FloatRect(1.f, 0.f, 2.f, 1.f),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = blueBuffer,
+                                            .usePremultipliedAlpha = true,
+                                    },
+                    },
+            .alpha = 1.0f,
+            .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+            .whitePointNits = 1000.f,
+    };
+
+    std::vector<renderengine::LayerSettings> layers{greenLayer, blueLayer};
+    invokeDraw(display, layers);
+
+    expectBufferColor(Rect(1, 1), 0, 51, 0, 255, 1);
+    expectBufferColor(Rect(1, 0, 2, 1), 0, 0, 255, 255);
+}
+
 TEST_P(RenderEngineTest, test_isOpaque) {
     initializeRenderEngine();
 
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 36d001f..a7b5900 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -225,6 +225,11 @@
         "libui_headers",
     ],
     min_sdk_version: "29",
+
+    pgo: {
+        sampling: true,
+        profile_file: "libui/libui.profdata",
+    },
 }
 
 cc_library_headers {
diff --git a/libs/ui/include_types/ui/DataspaceUtils.h b/libs/ui/include_types/ui/DataspaceUtils.h
new file mode 100644
index 0000000..a461cb4
--- /dev/null
+++ b/libs/ui/include_types/ui/DataspaceUtils.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ui/GraphicTypes.h>
+
+namespace android {
+
+inline bool isHdrDataspace(ui::Dataspace dataspace) {
+    const auto transfer = dataspace & HAL_DATASPACE_TRANSFER_MASK;
+
+    return transfer == HAL_DATASPACE_TRANSFER_ST2084 || transfer == HAL_DATASPACE_TRANSFER_HLG;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 0ee15f2..22fbf45 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -163,3 +163,13 @@
         "-Werror",
     ],
 }
+
+cc_test {
+    name: "DataspaceUtils_test",
+    shared_libs: ["libui"],
+    srcs: ["DataspaceUtils_test.cpp"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/libs/ui/tests/DataspaceUtils_test.cpp b/libs/ui/tests/DataspaceUtils_test.cpp
new file mode 100644
index 0000000..3e09671
--- /dev/null
+++ b/libs/ui/tests/DataspaceUtils_test.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "DataspaceUtilsTest"
+
+#include <gtest/gtest.h>
+#include <ui/DataspaceUtils.h>
+
+namespace android {
+
+class DataspaceUtilsTest : public testing::Test {};
+
+TEST_F(DataspaceUtilsTest, isHdrDataspace) {
+    EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_ITU_HLG));
+    EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_ITU_PQ));
+    EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_PQ));
+    EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_HLG));
+
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SRGB_LINEAR));
+    // scRGB defines a very wide gamut but not an expanded luminance range
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SCRGB_LINEAR));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SRGB));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SCRGB));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_JFIF));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_BT601_625));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_BT601_525));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_BT709));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DCI_P3_LINEAR));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DCI_P3));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DISPLAY_P3_LINEAR));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DISPLAY_P3));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::ADOBE_RGB));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::BT2020_LINEAR));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::BT2020));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::BT2020_ITU));
+    EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DISPLAY_BT2020));
+}
+
+} // namespace android
diff --git a/opengl/libs/EGL/GLES_layers.md b/opengl/libs/EGL/GLES_layers.md
index bfc44db..f6a8f14 100644
--- a/opengl/libs/EGL/GLES_layers.md
+++ b/opengl/libs/EGL/GLES_layers.md
@@ -251,7 +251,7 @@
    - Secondly, if you want to determine from an application that can't call out to ADB for this, you can check for the [EGL_ANDROID_GLES_layers](../../specs/EGL_ANDROID_GLES_layers.txt). It simply indicates support of this layering system:
      ```cpp
      std::string display_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
-     if (display_extension.find("EGL_ANDROID_GLES_layers") != std::string::npos)
+     if (display_extensions.find("EGL_ANDROID_GLES_layers") != std::string::npos)
      {
         // Layers are supported!
      }
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
index 220952d..d033453 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -84,6 +84,38 @@
     }
 }
 
+void GpuStats::purgeOldDriverStats() {
+    ALOG_ASSERT(mAppStats.size() == MAX_NUM_APP_RECORDS);
+
+    struct GpuStatsApp {
+        // Key is <app package name>+<driver version code>.
+        const std::string *appStatsKey = nullptr;
+        const std::chrono::time_point<std::chrono::system_clock> *lastAccessTime = nullptr;
+    };
+    std::vector<GpuStatsApp> gpuStatsApps(MAX_NUM_APP_RECORDS);
+
+    // Create a list of pointers to package names and their last access times.
+    int index = 0;
+    for (const auto & [appStatsKey, gpuStatsAppInfo] : mAppStats) {
+        GpuStatsApp &gpuStatsApp = gpuStatsApps[index];
+        gpuStatsApp.appStatsKey = &appStatsKey;
+        gpuStatsApp.lastAccessTime = &gpuStatsAppInfo.lastAccessTime;
+        ++index;
+    }
+
+    // Sort the list with the oldest access times at the front.
+    std::sort(gpuStatsApps.begin(), gpuStatsApps.end(), [](GpuStatsApp a, GpuStatsApp b) -> bool {
+        return *a.lastAccessTime < *b.lastAccessTime;
+    });
+
+    // Remove the oldest packages from mAppStats to make room for new apps.
+    for (int i = 0; i < APP_RECORD_HEADROOM; ++i) {
+        mAppStats.erase(*gpuStatsApps[i].appStatsKey);
+        gpuStatsApps[i].appStatsKey = nullptr;
+        gpuStatsApps[i].lastAccessTime = nullptr;
+    }
+}
+
 void GpuStats::insertDriverStats(const std::string& driverPackageName,
                                  const std::string& driverVersionName, uint64_t driverVersionCode,
                                  int64_t driverBuildTime, const std::string& appPackageName,
@@ -123,19 +155,22 @@
     const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode);
     if (!mAppStats.count(appStatsKey)) {
         if (mAppStats.size() >= MAX_NUM_APP_RECORDS) {
-            ALOGV("GpuStatsAppInfo has reached maximum size. Ignore new stats.");
-            return;
+            ALOGV("GpuStatsAppInfo has reached maximum size. Removing old stats to make room.");
+            purgeOldDriverStats();
         }
 
         GpuStatsAppInfo appInfo;
         addLoadingTime(driver, driverLoadingTime, &appInfo);
         appInfo.appPackageName = appPackageName;
         appInfo.driverVersionCode = driverVersionCode;
+        appInfo.angleInUse = driverPackageName == "angle";
+        appInfo.lastAccessTime = std::chrono::system_clock::now();
         mAppStats.insert({appStatsKey, appInfo});
-        return;
+    } else {
+        mAppStats[appStatsKey].angleInUse = driverPackageName == "angle";
+        addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]);
+        mAppStats[appStatsKey].lastAccessTime = std::chrono::system_clock::now();
     }
-
-    addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]);
 }
 
 void GpuStats::insertTargetStats(const std::string& appPackageName,
@@ -311,7 +346,8 @@
                                               angleDriverBytes.length()),
                     ele.second.cpuVulkanInUse,
                     ele.second.falsePrerotation,
-                    ele.second.gles1InUse);
+                    ele.second.gles1InUse,
+                    ele.second.angleInUse);
         }
     }
 
diff --git a/services/gpuservice/gpustats/include/gpustats/GpuStats.h b/services/gpuservice/gpustats/include/gpustats/GpuStats.h
index 55f0da1..2aba651 100644
--- a/services/gpuservice/gpustats/include/gpustats/GpuStats.h
+++ b/services/gpuservice/gpustats/include/gpustats/GpuStats.h
@@ -46,6 +46,11 @@
 
     // This limits the worst case number of loading times tracked.
     static const size_t MAX_NUM_LOADING_TIMES = 50;
+    // Below limits the memory usage of GpuStats to be less than 10KB. This is
+    // the preferred number for statsd while maintaining nice data quality.
+    static const size_t MAX_NUM_APP_RECORDS = 100;
+    // The number of apps to remove when mAppStats fills up.
+    static const size_t APP_RECORD_HEADROOM = 10;
 
 private:
     // Friend class for testing.
@@ -55,6 +60,10 @@
     static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atomTag,
                                                                  AStatsEventList* data,
                                                                  void* cookie);
+
+    // Remove old packages from mAppStats.
+    void purgeOldDriverStats();
+
     // Pull global into into global atom.
     AStatsManager_PullAtomCallbackReturn pullGlobalInfoAtom(AStatsEventList* data);
     // Pull app into into app atom.
@@ -68,9 +77,6 @@
     // Registers statsd callbacks if they have not already been registered
     void registerStatsdCallbacksIfNeeded();
 
-    // Below limits the memory usage of GpuStats to be less than 10KB. This is
-    // the preferred number for statsd while maintaining nice data quality.
-    static const size_t MAX_NUM_APP_RECORDS = 100;
     // GpuStats access should be guarded by mLock.
     std::mutex mLock;
     // True if statsd callbacks have been registered.
diff --git a/services/gpuservice/tests/unittests/GpuStatsTest.cpp b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
index 37ebeae..20c8ccf 100644
--- a/services/gpuservice/tests/unittests/GpuStatsTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
@@ -17,6 +17,7 @@
 #undef LOG_TAG
 #define LOG_TAG "gpuservice_unittest"
 
+#include <unistd.h>
 #include <cutils/properties.h>
 #include <gmock/gmock.h>
 #include <gpustats/GpuStats.h>
@@ -221,6 +222,51 @@
     EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("gles1InUse = 1"));
 }
 
+// Verify we always have the most recently used apps in mAppStats, even when we fill it.
+TEST_F(GpuStatsTest, canInsertMoreThanMaxNumAppRecords) {
+    constexpr int kNumExtraApps = 15;
+    static_assert(kNumExtraApps > GpuStats::APP_RECORD_HEADROOM);
+
+    // Insert stats for GpuStats::MAX_NUM_APP_RECORDS so we fill it up.
+    for (int i = 0; i < GpuStats::MAX_NUM_APP_RECORDS + kNumExtraApps; ++i) {
+        std::stringstream nameStream;
+        nameStream << "testapp" << "_" << i;
+        std::string fullPkgName = nameStream.str();
+
+        mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+                                     BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME,
+                                     fullPkgName, VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+                                     DRIVER_LOADING_TIME_1);
+        mGpuStats->insertTargetStats(fullPkgName, BUILTIN_DRIVER_VER_CODE,
+                                     GpuStatsInfo::Stats::CPU_VULKAN_IN_USE, 0);
+        mGpuStats->insertTargetStats(fullPkgName, BUILTIN_DRIVER_VER_CODE,
+                                     GpuStatsInfo::Stats::FALSE_PREROTATION, 0);
+        mGpuStats->insertTargetStats(fullPkgName, BUILTIN_DRIVER_VER_CODE,
+                                     GpuStatsInfo::Stats::GLES_1_IN_USE, 0);
+
+        EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(fullPkgName.c_str()));
+        EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("cpuVulkanInUse = 1"));
+        EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("falsePrerotation = 1"));
+        EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("gles1InUse = 1"));
+    }
+
+    // mAppStats purges GpuStats::APP_RECORD_HEADROOM apps removed everytime it's filled up.
+    int numPurges = kNumExtraApps / GpuStats::APP_RECORD_HEADROOM;
+    numPurges += (kNumExtraApps % GpuStats::APP_RECORD_HEADROOM) == 0 ? 0 : 1;
+
+    // Verify the remaining apps are present.
+    for (int i = numPurges * GpuStats::APP_RECORD_HEADROOM;
+         i < GpuStats::MAX_NUM_APP_RECORDS + kNumExtraApps;
+         ++i) {
+        std::stringstream nameStream;
+        // Add a newline to search for the exact package name.
+        nameStream << "testapp" << "_" << i << "\n";
+        std::string fullPkgName = nameStream.str();
+
+        EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(fullPkgName.c_str()));
+    }
+}
+
 TEST_F(GpuStatsTest, canDumpAllBeforeClearAll) {
     mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
                                  BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 0b632f7..30f25e5 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -782,12 +782,8 @@
 
     std::optional<int32_t> associatedDisplayId = device->getAssociatedDisplayId();
     // No associated display. By default, can dispatch to all displays.
-    if (!associatedDisplayId) {
-        return true;
-    }
-
-    if (*associatedDisplayId == ADISPLAY_ID_NONE) {
-        ALOGW("Device %s is associated with display ADISPLAY_ID_NONE.", device->getName().c_str());
+    if (!associatedDisplayId ||
+            *associatedDisplayId == ADISPLAY_ID_NONE) {
         return true;
     }
 
diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp
index 3663cdb..de8e6b3 100644
--- a/services/surfaceflinger/BackgroundExecutor.cpp
+++ b/services/surfaceflinger/BackgroundExecutor.cpp
@@ -32,7 +32,9 @@
             std::vector<std::function<void()>> tasks;
             {
                 std::unique_lock lock(mMutex);
-                mWorkAvailableCv.wait(lock, [&]() { return mDone || !mTasks.empty(); });
+                android::base::ScopedLockAssertion assumeLock(mMutex);
+                mWorkAvailableCv.wait(lock,
+                                      [&]() REQUIRES(mMutex) { return mDone || !mTasks.empty(); });
                 tasks = std::move(mTasks);
                 mTasks.clear();
                 done = mDone;
@@ -47,7 +49,7 @@
 
 BackgroundExecutor::~BackgroundExecutor() {
     {
-        std::unique_lock lock(mMutex);
+        std::scoped_lock lock(mMutex);
         mDone = true;
         mWorkAvailableCv.notify_all();
     }
@@ -57,7 +59,7 @@
 }
 
 void BackgroundExecutor::execute(std::function<void()> task) {
-    std::unique_lock lock(mMutex);
+    std::scoped_lock lock(mMutex);
     mTasks.emplace_back(std::move(task));
     mWorkAvailableCv.notify_all();
 }
diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h
index 6f6d305..6db7dda 100644
--- a/services/surfaceflinger/BackgroundExecutor.h
+++ b/services/surfaceflinger/BackgroundExecutor.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <android-base/thread_annotations.h>
 #include <utils/Singleton.h>
 #include <condition_variable>
 #include <mutex>
@@ -33,10 +34,10 @@
 
 private:
     std::mutex mMutex;
-    std::condition_variable mWorkAvailableCv;
+    std::condition_variable mWorkAvailableCv GUARDED_BY(mMutex);
+    bool mDone GUARDED_BY(mMutex) = false;
+    std::vector<std::function<void()>> mTasks GUARDED_BY(mMutex);
     std::thread mThread;
-    bool mDone = false;
-    std::vector<std::function<void()>> mTasks;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 0a8ebec..6d7b732 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -98,7 +98,8 @@
 
 status_t Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,
                                int32_t* outLayerId) {
-    return mFlinger->mirrorLayer(this, mirrorFromHandle, outHandle, outLayerId);
+    LayerCreationArgs args(mFlinger.get(), this, "MirrorRoot", 0 /* flags */, LayerMetadata());
+    return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId);
 }
 
 status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index ac243c0..e77e155 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -134,6 +134,9 @@
 
         // Configure layer settings for using blurs
         BlurSetting blurSetting;
+
+        // Requested white point of the layer in nits
+        const float whitePointNits;
     };
 
     // A superset of LayerSettings required by RenderEngine to compose a layer
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index a000661..7e605f9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -161,7 +161,7 @@
     // The buffer and related state
     sp<GraphicBuffer> buffer;
     int bufferSlot{BufferQueue::INVALID_BUFFER_SLOT};
-    sp<Fence> acquireFence;
+    sp<Fence> acquireFence = Fence::NO_FENCE;
     Region surfaceDamage;
 
     // The handle to use for a sideband stream for this layer
@@ -200,6 +200,9 @@
     // The output-independent frame for the cursor
     Rect cursorFrame;
 
+    // framerate of the layer as measured by LayerHistory
+    float fps;
+
     virtual ~LayerFECompositionState();
 
     // Debugging
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index b407267..3571e11 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -76,7 +76,7 @@
     virtual void applyChangedTypesToLayers(const ChangedTypes&);
     virtual void applyDisplayRequests(const DisplayRequests&);
     virtual void applyLayerRequestsToLayers(const LayerRequests&);
-    virtual void applyClientTargetRequests(const ClientTargetProperty&);
+    virtual void applyClientTargetRequests(const ClientTargetProperty&, float whitePointNits);
 
     // Internal
     virtual void setConfiguration(const compositionengine::DisplayCreationArgs&);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 44f754f..c5b6443 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -127,6 +127,9 @@
     // SDR white point
     float sdrWhitePointNits{-1.f};
 
+    // White point of the client target
+    float clientTargetWhitePointNits{-1.f};
+
     // Debugging
     void dump(std::string& result) const;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 244f8ab..c15249d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -73,8 +73,9 @@
     void writeOutputIndependentGeometryStateToHWC(HWC2::Layer*, const LayerFECompositionState&,
                                                   bool skipLayer);
     void writeOutputDependentPerFrameStateToHWC(HWC2::Layer*);
-    void writeOutputIndependentPerFrameStateToHWC(HWC2::Layer*, const LayerFECompositionState&,
-                                                  bool skipLayer);
+    void writeOutputIndependentPerFrameStateToHWC(
+            HWC2::Layer*, const LayerFECompositionState&,
+            Hwc2::IComposerClient::Composition compositionType, bool skipLayer);
     void writeSolidColorStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
     void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
     void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&, bool skipLayer);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 7564c54..627b80b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -146,6 +146,10 @@
 
     // Timestamp for when the layer is queued for client composition
     nsecs_t clientCompositionTimestamp{0};
+
+    // White point of the layer, in nits.
+    static constexpr float kDefaultWhitePointNits = 200.f;
+    float whitePointNits = kDefaultWhitePointNits;
 };
 
 } // namespace compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index cff6527..92cc484 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -87,6 +87,13 @@
         const bool mEnableHolePunch;
     };
 
+    // Constants not yet backed by a sysprop
+    // CachedSets that contain no more than this many layers may be considered inactive on the basis
+    // of FPS.
+    static constexpr int kNumLayersFpsConsideration = 1;
+    // Frames/Second threshold below which these CachedSets may be considered inactive.
+    static constexpr float kFpsActiveThreshold = 1.f;
+
     Flattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables);
 
     void setDisplaySize(ui::Size size) {
@@ -127,21 +134,22 @@
         class Builder {
         private:
             std::vector<CachedSet>::const_iterator mStart;
-            std::vector<size_t> mLengths;
+            int32_t mNumSets = 0;
             const CachedSet* mHolePunchCandidate = nullptr;
             const CachedSet* mBlurringLayer = nullptr;
+            bool mBuilt = false;
 
         public:
             // Initializes a Builder a CachedSet to start from.
             // This start iterator must be an iterator for mLayers
             void init(const std::vector<CachedSet>::const_iterator& start) {
                 mStart = start;
-                mLengths.push_back(start->getLayerCount());
+                mNumSets = 1;
             }
 
             // Appends a new CachedSet to the end of the run
             // The provided length must be the size of the next sequential CachedSet in layers
-            void append(size_t length) { mLengths.push_back(length); }
+            void increment() { mNumSets++; }
 
             // Sets the hole punch candidate for the Run.
             void setHolePunchCandidate(const CachedSet* holePunchCandidate) {
@@ -154,19 +162,36 @@
 
             // Builds a Run instance, if a valid Run may be built.
             std::optional<Run> validateAndBuild() {
-                if (mLengths.size() == 0) {
-                    return std::nullopt;
-                }
-                // Runs of length 1 which are hole punch candidates are allowed if the candidate is
-                // going to be used.
-                if (mLengths.size() == 1 &&
-                    (!mHolePunchCandidate || !(mHolePunchCandidate->requiresHolePunch()))) {
+                const bool built = mBuilt;
+                mBuilt = true;
+                if (mNumSets <= 0 || built) {
                     return std::nullopt;
                 }
 
+                const bool requiresHolePunch =
+                        mHolePunchCandidate && mHolePunchCandidate->requiresHolePunch();
+
+                if (!requiresHolePunch) {
+                    // If we don't require a hole punch, then treat solid color layers at the front
+                    // to be "cheap", so remove them from the candidate cached set.
+                    while (mNumSets > 1 && mStart->getLayerCount() == 1 &&
+                           mStart->getFirstLayer().getBuffer() == nullptr) {
+                        mStart++;
+                        mNumSets--;
+                    }
+
+                    // Only allow for single cached sets if a hole punch is required. If we're here,
+                    // then we don't require a hole punch, so don't build a run.
+                    if (mNumSets <= 1) {
+                        return std::nullopt;
+                    }
+                }
+
                 return Run(mStart,
-                           std::reduce(mLengths.cbegin(), mLengths.cend(), 0u,
-                                       [](size_t left, size_t right) { return left + right; }),
+                           std::reduce(mStart, mStart + mNumSets, 0u,
+                                       [](size_t length, const CachedSet& set) {
+                                           return length + set.getLayerCount();
+                                       }),
                            mHolePunchCandidate, mBlurringLayer);
             }
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index 5237527..7397c19 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -245,6 +245,7 @@
     bool isProtected() const {
         return getOutputLayer()->getLayerFE().getCompositionState()->hasProtectedContent;
     }
+    float getFps() const { return getOutputLayer()->getLayerFE().getCompositionState()->fps; }
 
     void dump(std::string& result) const;
     std::optional<std::string> compare(const LayerState& other) const;
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 02fa49f..4603e6b 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -237,7 +237,8 @@
         applyChangedTypesToLayers(changes->changedTypes);
         applyDisplayRequests(changes->displayRequests);
         applyLayerRequestsToLayers(changes->layerRequests);
-        applyClientTargetRequests(changes->clientTargetProperty);
+        applyClientTargetRequests(changes->clientTargetProperty,
+                                  changes->clientTargetWhitePointNits);
     }
 
     // Determine what type of composition we are doing from the final state
@@ -309,12 +310,14 @@
     }
 }
 
-void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty) {
+void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty,
+                                        float whitePointNits) {
     if (clientTargetProperty.dataspace == ui::Dataspace::UNKNOWN) {
         return;
     }
 
     editState().dataspace = clientTargetProperty.dataspace;
+    editState().clientTargetWhitePointNits = whitePointNits;
     getRenderSurface()->setBufferDataspace(clientTargetProperty.dataspace);
     getRenderSurface()->setBufferPixelFormat(clientTargetProperty.pixelFormat);
 }
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 6800004..d503153 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1057,7 +1057,7 @@
     clientCompositionDisplay.maxLuminance = outputState.displayBrightnessNits > 0.f
             ? outputState.displayBrightnessNits
             : mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
-    clientCompositionDisplay.sdrWhitePointNits = outputState.sdrWhitePointNits;
+    clientCompositionDisplay.targetLuminanceNits = outputState.clientTargetWhitePointNits;
 
     // Compute the global color transform matrix.
     if (!outputState.usesDeviceComposition && !getSkipColorTransform()) {
@@ -1217,7 +1217,8 @@
                                        .dataspace = outputDataspace,
                                        .realContentIsVisible = realContentIsVisible,
                                        .clearContent = !clientComposition,
-                                       .blurSetting = blurSetting};
+                                       .blurSetting = blurSetting,
+                                       .whitePointNits = layerState.whitePointNits};
                 results = layerFE.prepareClientCompositionList(targetSettings);
                 if (realContentIsVisible && !results.empty()) {
                     layer->editState().clientCompositionTimestamp = systemTime();
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index e958549..b010d9f 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -24,6 +24,9 @@
 #include <compositionengine/impl/OutputLayer.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <cstdint>
+#include "system/graphics-base-v1.0.h"
+
+#include <ui/DataspaceUtils.h>
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic push
@@ -317,6 +320,14 @@
             ? outputState.targetDataspace
             : layerFEState->dataspace;
 
+    // For hdr content, treat the white point as the display brightness - HDR content should not be
+    // boosted or dimmed.
+    if (isHdrDataspace(state.dataspace)) {
+        state.whitePointNits = getOutput().getState().displayBrightnessNits;
+    } else {
+        state.whitePointNits = getOutput().getState().sdrWhitePointNits;
+    }
+
     // These are evaluated every frame as they can potentially change at any
     // time.
     if (layerFEState->forceClientComposition || !profile.isDataspaceSupported(state.dataspace) ||
@@ -347,6 +358,10 @@
 
     auto requestedCompositionType = outputIndependentState->compositionType;
 
+    if (requestedCompositionType == hal::Composition::SOLID_COLOR && state.overrideInfo.buffer) {
+        requestedCompositionType = hal::Composition::DEVICE;
+    }
+
     // TODO(b/181172795): We now update geometry for all flattened layers. We should update it
     // only when the geometry actually changes
     const bool isOverridden =
@@ -359,13 +374,15 @@
     }
 
     writeOutputDependentPerFrameStateToHWC(hwcLayer.get());
-    writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), *outputIndependentState, skipLayer);
+    writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), *outputIndependentState,
+                                             requestedCompositionType, skipLayer);
 
     writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough,
                               skipLayer);
 
-    // Always set the layer color after setting the composition type.
-    writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState);
+    if (requestedCompositionType == hal::Composition::SOLID_COLOR) {
+        writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState);
+    }
 
     editState().hwc->stateOverridden = isOverridden;
     editState().hwc->layerSkipped = skipLayer;
@@ -473,11 +490,21 @@
         ALOGE("[%s] Failed to set dataspace %d: %s (%d)", getLayerFE().getDebugName(), dataspace,
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
+
+    // Don't dim cached layers
+    const auto whitePointNits = outputDependentState.overrideInfo.buffer
+            ? getOutput().getState().displayBrightnessNits
+            : outputDependentState.whitePointNits;
+
+    if (auto error = hwcLayer->setWhitePointNits(whitePointNits); error != hal::Error::NONE) {
+        ALOGE("[%s] Failed to set white point %f: %s (%d)", getLayerFE().getDebugName(),
+              whitePointNits, to_string(error).c_str(), static_cast<int32_t>(error));
+    }
 }
 
 void OutputLayer::writeOutputIndependentPerFrameStateToHWC(
         HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState,
-        bool skipLayer) {
+        hal::Composition compositionType, bool skipLayer) {
     switch (auto error = hwcLayer->setColorTransform(outputIndependentState.colorTransform)) {
         case hal::Error::NONE:
             break;
@@ -501,7 +528,7 @@
     }
 
     // Content-specific per-frame state
-    switch (outputIndependentState.compositionType) {
+    switch (compositionType) {
         case hal::Composition::SOLID_COLOR:
             // For compatibility, should be written AFTER the composition type.
             break;
@@ -521,10 +548,6 @@
 
 void OutputLayer::writeSolidColorStateToHWC(HWC2::Layer* hwcLayer,
                                             const LayerFECompositionState& outputIndependentState) {
-    if (outputIndependentState.compositionType != hal::Composition::SOLID_COLOR) {
-        return;
-    }
-
     hal::Color color = {static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.r)),
                         static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.g)),
                         static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.b)),
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index ff96d94..2203f22 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -170,6 +170,7 @@
             .clip = viewport,
             .outputDataspace = outputDataspace,
             .orientation = orientation,
+            .targetLuminanceNits = outputState.displayBrightnessNits,
     };
 
     LayerFE::ClientCompositionTargetSettings targetSettings{
@@ -182,6 +183,7 @@
             .realContentIsVisible = true,
             .clearContent = false,
             .blurSetting = LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            .whitePointNits = outputState.displayBrightnessNits,
     };
 
     std::vector<renderengine::LayerSettings> layerSettings;
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 2272099..c14effc 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -409,25 +409,29 @@
     bool runHasFirstLayer = false;
 
     for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) {
-        const bool layerIsInactive =
-                now - currentSet->getLastUpdate() > mTunables.mActiveLayerTimeout;
+        bool layerIsInactive = now - currentSet->getLastUpdate() > mTunables.mActiveLayerTimeout;
         const bool layerHasBlur = currentSet->hasBlurBehind();
 
+        // Layers should also be considered inactive whenever their framerate is lower than 1fps.
+        if (!layerIsInactive && currentSet->getLayerCount() == kNumLayersFpsConsideration) {
+            auto layerFps = currentSet->getFirstLayer().getState()->getFps();
+            if (layerFps > 0 && layerFps <= kFpsActiveThreshold) {
+                ATRACE_FORMAT("layer is considered inactive due to low FPS [%s] %f",
+                              currentSet->getFirstLayer().getName().c_str(), layerFps);
+                layerIsInactive = true;
+            }
+        }
+
         if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) &&
             !currentSet->hasUnsupportedDataspace()) {
             if (isPartOfRun) {
-                builder.append(currentSet->getLayerCount());
+                builder.increment();
             } else {
-                // Runs can't start with a non-buffer layer
-                if (currentSet->getFirstLayer().getBuffer() == nullptr) {
-                    ALOGV("[%s] Skipping initial non-buffer layer", __func__);
-                } else {
-                    builder.init(currentSet);
-                    if (firstLayer) {
-                        runHasFirstLayer = true;
-                    }
-                    isPartOfRun = true;
+                builder.init(currentSet);
+                if (firstLayer) {
+                    runHasFirstLayer = true;
                 }
+                isPartOfRun = true;
             }
         } else if (isPartOfRun) {
             builder.setHolePunchCandidate(&(*currentSet));
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index ed235b8..568efce 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -596,6 +596,7 @@
             hal::DisplayRequest::FLIP_CLIENT_TARGET,
             {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}},
             {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN},
+            -1.f,
     };
 
     // Since two calls are made to anyLayersRequireClientComposition with different return
@@ -788,15 +789,18 @@
             .dataspace = hal::Dataspace::STANDARD_BT470M,
     };
 
+    static constexpr float kWhitePointNits = 800.f;
+
     mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
     mDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
 
     EXPECT_CALL(*renderSurface, setBufferPixelFormat(clientTargetProperty.pixelFormat));
     EXPECT_CALL(*renderSurface, setBufferDataspace(clientTargetProperty.dataspace));
-    mDisplay->applyClientTargetRequests(clientTargetProperty);
+    mDisplay->applyClientTargetRequests(clientTargetProperty, kWhitePointNits);
 
     auto& state = mDisplay->getState();
     EXPECT_EQ(clientTargetProperty.dataspace, state.dataspace);
+    EXPECT_EQ(kWhitePointNits, state.clientTargetWhitePointNits);
 }
 
 /*
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index 9518659..9e08f9e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -71,6 +71,7 @@
     MOCK_METHOD1(setColorTransform, Error(const android::mat4&));
     MOCK_METHOD3(setLayerGenericMetadata,
                  Error(const std::string&, bool, const std::vector<uint8_t>&));
+    MOCK_METHOD1(setWhitePointNits, Error(float));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index fbc2089..207c31e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -652,6 +652,22 @@
     EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace);
 }
 
+TEST_F(OutputLayerUpdateCompositionStateTest, setsWhitePointNitsCorrectly) {
+    mOutputState.sdrWhitePointNits = 200.f;
+    mOutputState.displayBrightnessNits = 800.f;
+
+    mLayerFEState.dataspace = ui::Dataspace::DISPLAY_P3;
+    mLayerFEState.isColorspaceAgnostic = false;
+    mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
+    EXPECT_EQ(mOutputState.sdrWhitePointNits, mOutputLayer.getState().whitePointNits);
+
+    mLayerFEState.dataspace = ui::Dataspace::BT2020_ITU_PQ;
+    mLayerFEState.isColorspaceAgnostic = false;
+    mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
+
+    EXPECT_EQ(mOutputState.displayBrightnessNits, mOutputLayer.getState().whitePointNits);
+}
+
 TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) {
     mOutputLayer.editState().forceClientComposition = false;
 
@@ -728,6 +744,8 @@
     static constexpr int kOverrideHwcSlot = impl::HwcBufferCache::FLATTENER_CACHING_SLOT;
     static constexpr bool kLayerGenericMetadata1Mandatory = true;
     static constexpr bool kLayerGenericMetadata2Mandatory = true;
+    static constexpr float kWhitePointNits = 200.f;
+    static constexpr float kDisplayBrightnessNits = 400.f;
 
     static const half4 kColor;
     static const Rect kDisplayFrame;
@@ -758,6 +776,7 @@
         outputLayerState.bufferTransform = static_cast<Hwc2::Transform>(kBufferTransform);
         outputLayerState.outputSpaceVisibleRegion = kOutputSpaceVisibleRegion;
         outputLayerState.dataspace = kDataspace;
+        outputLayerState.whitePointNits = kWhitePointNits;
 
         mLayerFEState.blendMode = kBlendMode;
         mLayerFEState.alpha = kAlpha;
@@ -770,6 +789,8 @@
         mLayerFEState.bufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
         mLayerFEState.acquireFence = kFence;
 
+        mOutputState.displayBrightnessNits = kDisplayBrightnessNits;
+
         EXPECT_CALL(mOutput, getDisplayColorProfile())
                 .WillRepeatedly(Return(&mDisplayColorProfile));
         EXPECT_CALL(mDisplayColorProfile, getSupportedPerFrameMetadata())
@@ -818,9 +839,11 @@
     void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None,
                                    ui::Dataspace dataspace = kDataspace,
                                    const Region& visibleRegion = kOutputSpaceVisibleRegion,
-                                   const Region& surfaceDamage = kSurfaceDamage) {
+                                   const Region& surfaceDamage = kSurfaceDamage,
+                                   float whitePointNits = kWhitePointNits) {
         EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(visibleRegion))).WillOnce(Return(kError));
         EXPECT_CALL(*mHwcLayer, setDataspace(dataspace)).WillOnce(Return(kError));
+        EXPECT_CALL(*mHwcLayer, setWhitePointNits(whitePointNits)).WillOnce(Return(kError));
         EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform))
                 .WillOnce(Return(unsupported == SimulateUnsupported::ColorTransform
                                          ? hal::Error::UNSUPPORTED
@@ -1084,7 +1107,23 @@
     expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
                               kOverrideBlendMode, kSkipAlpha);
     expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
-                              kOverrideSurfaceDamage);
+                              kOverrideSurfaceDamage, kDisplayBrightnessNits);
+    expectSetHdrMetadataAndBufferCalls();
+    expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+    EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
+
+    mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, 0,
+                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerForSolidColorDoesNotSendBuffer) {
+    mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+    includeOverrideInfo();
+
+    expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
+                              kOverrideBlendMode, kSkipAlpha);
+    expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
+                              kOverrideSurfaceDamage, kDisplayBrightnessNits);
     expectSetHdrMetadataAndBufferCalls();
     expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
     EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1100,7 +1139,23 @@
     expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
                               kOverrideBlendMode, kOverrideAlpha);
     expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
-                              kOverrideSurfaceDamage);
+                              kOverrideSurfaceDamage, kDisplayBrightnessNits);
+    expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
+    expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+    EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
+
+    mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoForSolidColorIfPresent) {
+    mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+    includeOverrideInfo();
+
+    expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
+                              kOverrideBlendMode, kOverrideAlpha);
+    expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
+                              kOverrideSurfaceDamage, kDisplayBrightnessNits);
     expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
     expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
     EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index cf63ef5..6d96260 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3023,6 +3023,7 @@
         mOutput.mState.usesDeviceComposition = false;
         mOutput.mState.reusedClientComposition = false;
         mOutput.mState.flipClientTarget = false;
+        mOutput.mState.clientTargetWhitePointNits = kClientTargetLuminanceNits;
 
         EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine));
         EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
@@ -3057,6 +3058,7 @@
     static constexpr float kDefaultMaxLuminance = 0.9f;
     static constexpr float kDefaultAvgLuminance = 0.7f;
     static constexpr float kDefaultMinLuminance = 0.1f;
+    static constexpr float kClientTargetLuminanceNits = 200.f;
 
     static const Rect kDefaultOutputFrame;
     static const Rect kDefaultOutputViewport;
@@ -3424,7 +3426,8 @@
             .andIfSkipColorTransform(false)
             .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
                                             kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
-                                            kDefaultOutputOrientationFlags})
+                                            kDefaultOutputOrientationFlags,
+                                            kClientTargetLuminanceNits})
             .execute()
             .expectAFenceWasReturned();
 }
@@ -3435,7 +3438,8 @@
             .andIfSkipColorTransform(false)
             .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
                                             kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
-                                            kDefaultOutputOrientationFlags})
+                                            kDefaultOutputOrientationFlags,
+                                            kClientTargetLuminanceNits})
             .execute()
             .expectAFenceWasReturned();
 }
@@ -3444,10 +3448,10 @@
     verify().ifMixedCompositionIs(false)
             .andIfUsesHdr(true)
             .andIfSkipColorTransform(false)
-            .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
-                                            kDefaultMaxLuminance, kDefaultOutputDataspace,
-                                            kDefaultColorTransformMat,
-                                            kDefaultOutputOrientationFlags})
+            .thenExpectDisplaySettingsUsed(
+                    {kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance,
+                     kDefaultOutputDataspace, kDefaultColorTransformMat,
+                     kDefaultOutputOrientationFlags, kClientTargetLuminanceNits})
             .execute()
             .expectAFenceWasReturned();
 }
@@ -3456,10 +3460,10 @@
     verify().ifMixedCompositionIs(false)
             .andIfUsesHdr(false)
             .andIfSkipColorTransform(false)
-            .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
-                                            kDefaultMaxLuminance, kDefaultOutputDataspace,
-                                            kDefaultColorTransformMat,
-                                            kDefaultOutputOrientationFlags})
+            .thenExpectDisplaySettingsUsed(
+                    {kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance,
+                     kDefaultOutputDataspace, kDefaultColorTransformMat,
+                     kDefaultOutputOrientationFlags, kClientTargetLuminanceNits})
             .execute()
             .expectAFenceWasReturned();
 }
@@ -3471,7 +3475,8 @@
             .andIfSkipColorTransform(true)
             .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
                                             kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
-                                            kDefaultOutputOrientationFlags})
+                                            kDefaultOutputOrientationFlags,
+                                            kClientTargetLuminanceNits})
             .execute()
             .expectAFenceWasReturned();
 }
@@ -3729,6 +3734,8 @@
         mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
     }
 
+    static constexpr float kLayerWhitePointNits = 200.f;
+
     mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
     mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
     StrictMock<OutputPartialMock> mOutput;
@@ -3768,6 +3775,7 @@
 
     static constexpr ui::Rotation kDisplayOrientation = ui::ROTATION_0;
     static constexpr ui::Dataspace kDisplayDataspace = ui::Dataspace::UNKNOWN;
+    static constexpr float kLayerWhitePointNits = 200.f;
 
     static const Rect kDisplayFrame;
     static const Rect kDisplayViewport;
@@ -3930,14 +3938,15 @@
 
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
-            false,      /* needs filtering */
-            false,      /* secure */
-            false,      /* supports protected content */
+            false, /* needs filtering */
+            false, /* secure */
+            false, /* supports protected content */
             kDisplayViewport,
             kDisplayDataspace,
             false /* realContentIsVisible */,
             true /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -3949,6 +3958,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
 
     LayerFE::LayerSettings mBlackoutSettings = mLayers[1].mLayerSettings;
@@ -3988,6 +3998,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(Rect(0, 0, 30, 30)),
@@ -3999,6 +4010,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(Rect(0, 0, 40, 201)),
@@ -4010,6 +4022,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
 
     EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
@@ -4039,6 +4052,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
@@ -4050,6 +4064,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -4061,6 +4076,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
 
     EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
@@ -4090,7 +4106,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
-
+            kLayerWhitePointNits,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
@@ -4102,6 +4118,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -4113,6 +4130,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
 
     EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
@@ -4141,6 +4159,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
@@ -4152,6 +4171,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -4163,6 +4183,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
 
     EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
@@ -4179,7 +4200,6 @@
 
 TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
        protectedContentSupportUsedToGenerateRequests) {
-
     compositionengine::LayerFE::ClientCompositionTargetSettings layer0TargetSettings{
             Region(kDisplayFrame),
             false, /* needs filtering */
@@ -4190,6 +4210,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
@@ -4201,6 +4222,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -4212,6 +4234,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
 
     EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
@@ -4379,6 +4402,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
 
     EXPECT_CALL(leftLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
@@ -4396,6 +4420,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
 
     EXPECT_CALL(rightLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
@@ -4428,6 +4453,7 @@
             false /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
 
     LayerFE::LayerSettings mShadowSettings;
@@ -4472,6 +4498,7 @@
             true /* realContentIsVisible */,
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+            kLayerWhitePointNits,
     };
 
     EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 42b3d97..d5a117a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -55,13 +55,21 @@
 }
 
 MATCHER_P(ClientCompositionTargetSettingsSecureEq, expectedSecureSetting, "") {
-    *result_listener << "ClientCompositionTargetSettings' SecureSettings aren't equal \n";
+    *result_listener << "ClientCompositionTargetSettings' isSecure bits aren't equal \n";
     *result_listener << "expected " << expectedSecureSetting << "\n";
     *result_listener << "actual " << arg.isSecure << "\n";
 
     return expectedSecureSetting == arg.isSecure;
 }
 
+MATCHER_P(ClientCompositionTargetSettingsWhitePointEq, expectedWhitePoint, "") {
+    *result_listener << "ClientCompositionTargetSettings' white points aren't equal \n";
+    *result_listener << "expected " << expectedWhitePoint << "\n";
+    *result_listener << "actual " << arg.whitePointNits << "\n";
+
+    return expectedWhitePoint == arg.whitePointNits;
+}
+
 static const ui::Size kOutputSize = ui::Size(1, 1);
 
 class CachedSetTest : public testing::Test {
@@ -431,6 +439,54 @@
     cachedSet.append(CachedSet(layer3));
 }
 
+TEST_F(CachedSetTest, renderWhitePoint) {
+    // Skip the 0th layer to ensure that the bounding box of the layers is offset from (0, 0)
+    CachedSet::Layer& layer1 = *mTestLayers[1]->cachedSetLayer.get();
+    sp<mock::LayerFE> layerFE1 = mTestLayers[1]->layerFE;
+    CachedSet::Layer& layer2 = *mTestLayers[2]->cachedSetLayer.get();
+    sp<mock::LayerFE> layerFE2 = mTestLayers[2]->layerFE;
+
+    CachedSet cachedSet(layer1);
+    cachedSet.append(CachedSet(layer2));
+
+    std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1;
+    clientCompList1.push_back({});
+
+    std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2;
+    clientCompList2.push_back({});
+
+    mOutputState.displayBrightnessNits = 400.f;
+
+    const auto drawLayers =
+            [&](const renderengine::DisplaySettings& displaySettings,
+                const std::vector<renderengine::LayerSettings>&,
+                const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+        EXPECT_EQ(mOutputState.displayBrightnessNits, displaySettings.targetLuminanceNits);
+        return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+    };
+
+    EXPECT_CALL(*layerFE1,
+                prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq(
+                        mOutputState.displayBrightnessNits)))
+            .WillOnce(Return(clientCompList1));
+    EXPECT_CALL(*layerFE2,
+                prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq(
+                        mOutputState.displayBrightnessNits)))
+            .WillOnce(Return(clientCompList2));
+    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
+    mOutputState.isSecure = true;
+    cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+    expectReadyBuffer(cachedSet);
+
+    EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
+    EXPECT_EQ(Rect(kOutputSize.width, kOutputSize.height), cachedSet.getTextureBounds());
+
+    // Now check that appending a new cached set properly cleans up RenderEngine resources.
+    CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+    cachedSet.append(CachedSet(layer3));
+}
+
 TEST_F(CachedSetTest, rendersWithOffsetFramebufferContent) {
     // Skip the 0th layer to ensure that the bounding box of the layers is offset from (0, 0)
     CachedSet::Layer& layer1 = *mTestLayers[1]->cachedSetLayer.get();
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 9b0a75f..35d051e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -224,6 +224,22 @@
     mFlattener->renderCachedSets(mOutputState, std::nullopt);
 }
 
+TEST_F(FlattenerTest, flattenLayers_ActiveLayersWithLowFpsAreFlattened) {
+    mTestLayers[0]->layerFECompositionState.fps = Flattener::kFpsActiveThreshold / 2;
+    mTestLayers[1]->layerFECompositionState.fps = Flattener::kFpsActiveThreshold;
+
+    auto& layerState1 = mTestLayers[0]->layerState;
+    auto& layerState2 = mTestLayers[1]->layerState;
+
+    const std::vector<const LayerState*> layers = {
+            layerState1.get(),
+            layerState2.get(),
+    };
+
+    initializeFlattener(layers);
+    expectAllLayersFlattened(layers);
+}
+
 TEST_F(FlattenerTest, flattenLayers_basicFlatten) {
     auto& layerState1 = mTestLayers[0]->layerState;
     auto& layerState2 = mTestLayers[1]->layerState;
@@ -746,6 +762,76 @@
     EXPECT_EQ(nullptr, peekThroughLayer1);
 }
 
+TEST_F(FlattenerTest, flattenLayers_holePunchSingleColorLayer) {
+    mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5);
+    mTestLayers[0]->layerFECompositionState.color = half4(255.f, 0.f, 0.f, 255.f);
+    mTestLayers[0]->layerFECompositionState.buffer = nullptr;
+
+    // An opaque static background
+    auto& layerState0 = mTestLayers[0]->layerState;
+    const auto& overrideBuffer0 = layerState0->getOutputLayer()->getState().overrideInfo.buffer;
+
+    // a rounded updating layer
+    auto& layerState1 = mTestLayers[1]->layerState;
+    const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
+
+    EXPECT_CALL(*mTestLayers[1]->layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
+
+    std::vector<LayerFE::LayerSettings> clientCompositionList = {
+            LayerFE::LayerSettings{},
+    };
+    clientCompositionList[0].source.buffer.buffer = std::make_shared<
+            renderengine::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer,
+                                           mRenderEngine,
+                                           renderengine::ExternalTexture::Usage::READABLE);
+    EXPECT_CALL(*mTestLayers[1]->layerFE, prepareClientCompositionList(_))
+            .WillOnce(Return(clientCompositionList));
+
+    const std::vector<const LayerState*> layers = {
+            layerState0.get(),
+            layerState1.get(),
+    };
+
+    initializeFlattener(layers);
+
+    // layer 1 satisfies every condition in CachedSet::requiresHolePunch()
+    mTime += 200ms;
+    layerState1->resetFramesSinceBufferUpdate(); // it is updating
+
+    initializeOverrideBuffer(layers);
+    // Expect no cache invalidation the first time (there's no cache yet)
+    EXPECT_EQ(getNonBufferHash(layers),
+              mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+
+    // This will render a CachedSet of layer 0. Though it is just one layer, it satisfies the
+    // exception that there would be a hole punch above it.
+    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+            .WillOnce(Return(ByMove(
+                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+
+    // We've rendered a CachedSet, but we haven't merged it in.
+    EXPECT_EQ(nullptr, overrideBuffer0);
+
+    // This time we merge the CachedSet in and we should still have only two sets.
+    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
+    initializeOverrideBuffer(layers);
+    EXPECT_EQ(getNonBufferHash(layers),
+              mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+
+    EXPECT_NE(nullptr, overrideBuffer0); // got overridden
+    EXPECT_EQ(nullptr, overrideBuffer1); // did not
+
+    // expect 0's peek though layer to be 1's output layer
+    const auto* peekThroughLayer0 =
+            layerState0->getOutputLayer()->getState().overrideInfo.peekThroughLayer;
+    const auto* peekThroughLayer1 =
+            layerState1->getOutputLayer()->getState().overrideInfo.peekThroughLayer;
+    EXPECT_EQ(&mTestLayers[1]->outputLayer, peekThroughLayer0);
+    EXPECT_EQ(nullptr, peekThroughLayer1);
+}
+
 TEST_F(FlattenerTest, flattenLayers_flattensBlurBehindRunIfFirstRun) {
     auto& layerState1 = mTestLayers[0]->layerState;
 
@@ -1191,5 +1277,61 @@
     EXPECT_EQ(nullptr, overrideBuffer3);
 }
 
+TEST_F(FlattenerTest, flattenLayers_skipsColorLayers) {
+    auto& layerState1 = mTestLayers[0]->layerState;
+    const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
+    auto& layerState2 = mTestLayers[1]->layerState;
+    const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer;
+    auto& layerState3 = mTestLayers[2]->layerState;
+    const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer;
+    auto& layerState4 = mTestLayers[3]->layerState;
+    const auto& overrideBuffer4 = layerState4->getOutputLayer()->getState().overrideInfo.buffer;
+
+    // Rewrite the first two layers to just be a solid color.
+    mTestLayers[0]->layerFECompositionState.color = half4(255.f, 0.f, 0.f, 255.f);
+    mTestLayers[0]->layerFECompositionState.buffer = nullptr;
+    mTestLayers[1]->layerFECompositionState.color = half4(0.f, 255.f, 0.f, 255.f);
+    mTestLayers[1]->layerFECompositionState.buffer = nullptr;
+
+    const std::vector<const LayerState*> layers = {
+            layerState1.get(),
+            layerState2.get(),
+            layerState3.get(),
+            layerState4.get(),
+    };
+
+    initializeFlattener(layers);
+
+    mTime += 200ms;
+    initializeOverrideBuffer(layers);
+    EXPECT_EQ(getNonBufferHash(layers),
+              mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+
+    // This will render a CachedSet.
+    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+            .WillOnce(Return(ByMove(
+                    futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+
+    // We've rendered a CachedSet, but we haven't merged it in.
+    EXPECT_EQ(nullptr, overrideBuffer1);
+    EXPECT_EQ(nullptr, overrideBuffer2);
+    EXPECT_EQ(nullptr, overrideBuffer3);
+    EXPECT_EQ(nullptr, overrideBuffer4);
+
+    // This time we merge the CachedSet in, so we have a new hash, and we should
+    // only have two sets.
+    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
+    initializeOverrideBuffer(layers);
+    EXPECT_NE(getNonBufferHash(layers),
+              mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+    mFlattener->renderCachedSets(mOutputState, std::nullopt);
+
+    EXPECT_EQ(nullptr, overrideBuffer1);
+    EXPECT_EQ(nullptr, overrideBuffer2);
+    EXPECT_EQ(overrideBuffer3, overrideBuffer4);
+    EXPECT_NE(nullptr, overrideBuffer4);
+}
+
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index ba57be5..29e5a74 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -41,6 +41,8 @@
 using aidl::android::hardware::graphics::composer3::PowerMode;
 using aidl::android::hardware::graphics::composer3::VirtualDisplay;
 
+using aidl::android::hardware::graphics::composer3::command::CommandResultPayload;
+
 using AidlColorMode = aidl::android::hardware::graphics::composer3::ColorMode;
 using AidlContentType = aidl::android::hardware::graphics::composer3::ContentType;
 using AidlDisplayIdentification =
@@ -48,8 +50,6 @@
 using AidlDisplayContentSample = aidl::android::hardware::graphics::composer3::DisplayContentSample;
 using AidlDisplayAttribute = aidl::android::hardware::graphics::composer3::DisplayAttribute;
 using AidlDisplayCapability = aidl::android::hardware::graphics::composer3::DisplayCapability;
-using AidlExecuteCommandsStatus =
-        aidl::android::hardware::graphics::composer3::ExecuteCommandsStatus;
 using AidlHdrCapabilities = aidl::android::hardware::graphics::composer3::HdrCapabilities;
 using AidlPerFrameMetadata = aidl::android::hardware::graphics::composer3::PerFrameMetadata;
 using AidlPerFrameMetadataKey = aidl::android::hardware::graphics::composer3::PerFrameMetadataKey;
@@ -174,6 +174,14 @@
     };
 }
 
+template <>
+IComposerClient::ClientTargetProperty translate(ClientTargetProperty x) {
+    return IComposerClient::ClientTargetProperty{
+            .pixelFormat = translate<PixelFormat>(x.pixelFormat),
+            .dataspace = translate<Dataspace>(x.dataspace),
+    };
+}
+
 mat4 makeMat4(std::vector<float> in) {
     return mat4(static_cast<const float*>(in.data()));
 }
@@ -226,7 +234,7 @@
     return AServiceManager_isDeclared(instance(serviceName).c_str());
 }
 
-AidlComposer::AidlComposer(const std::string& serviceName) : mWriter(kWriterInitialSize) {
+AidlComposer::AidlComposer(const std::string& serviceName) {
     // This only waits if the service is actually declared
     mAidlComposer = AidlIComposer::fromBinder(
             ndk::SpAIBinder(AServiceManager_waitForService(instance(serviceName).c_str())));
@@ -327,8 +335,7 @@
 }
 
 Error AidlComposer::acceptDisplayChanges(Display display) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.acceptDisplayChanges();
+    mWriter.acceptDisplayChanges(translate<int64_t>(display));
     return Error::NONE;
 }
 
@@ -369,7 +376,12 @@
 Error AidlComposer::getChangedCompositionTypes(
         Display display, std::vector<Layer>* outLayers,
         std::vector<IComposerClient::Composition>* outTypes) {
-    mReader.takeChangedCompositionTypes(display, outLayers, outTypes);
+    std::vector<int64_t> layers;
+    std::vector<Composition> types;
+    mReader.takeChangedCompositionTypes(translate<int64_t>(display), &layers, &types);
+
+    *outLayers = translate<Layer>(layers);
+    *outTypes = translate<IComposerClient::Composition>(types);
     return Error::NONE;
 }
 
@@ -422,7 +434,10 @@
 Error AidlComposer::getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
                                        std::vector<Layer>* outLayers,
                                        std::vector<uint32_t>* outLayerRequestMasks) {
-    mReader.takeDisplayRequests(display, outDisplayRequestMask, outLayers, outLayerRequestMasks);
+    std::vector<int64_t> layers;
+    mReader.takeDisplayRequests(translate<int64_t>(display), outDisplayRequestMask, &layers,
+                                outLayerRequestMasks);
+    *outLayers = translate<Layer>(layers);
     return Error::NONE;
 }
 
@@ -456,21 +471,22 @@
 
 Error AidlComposer::getReleaseFences(Display display, std::vector<Layer>* outLayers,
                                      std::vector<int>* outReleaseFences) {
-    mReader.takeReleaseFences(display, outLayers, outReleaseFences);
+    std::vector<int64_t> layers;
+    mReader.takeReleaseFences(translate<int64_t>(display), &layers, outReleaseFences);
+    *outLayers = translate<Layer>(layers);
     return Error::NONE;
 }
 
 Error AidlComposer::presentDisplay(Display display, int* outPresentFence) {
     ATRACE_NAME("HwcPresentDisplay");
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.presentDisplay();
+    mWriter.presentDisplay(translate<int64_t>(display));
 
     Error error = execute();
     if (error != Error::NONE) {
         return error;
     }
 
-    mReader.takePresentFence(display, outPresentFence);
+    mReader.takePresentFence(translate<int64_t>(display), outPresentFence);
 
     return Error::NONE;
 }
@@ -488,14 +504,12 @@
 Error AidlComposer::setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
                                     int acquireFence, Dataspace dataspace,
                                     const std::vector<IComposerClient::Rect>& damage) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-
     const native_handle_t* handle = nullptr;
     if (target.get()) {
         handle = target->getNativeBuffer()->handle;
     }
 
-    mWriter.setClientTarget(slot, handle, acquireFence,
+    mWriter.setClientTarget(translate<int64_t>(display), slot, handle, acquireFence,
                             translate<aidl::android::hardware::graphics::common::Dataspace>(
                                     dataspace),
                             translate<AidlRect>(damage));
@@ -515,15 +529,14 @@
 }
 
 Error AidlComposer::setColorTransform(Display display, const float* matrix, ColorTransform hint) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.setColorTransform(matrix, translate<AidlColorTransform>(hint));
+    mWriter.setColorTransform(translate<int64_t>(display), matrix,
+                              translate<AidlColorTransform>(hint));
     return Error::NONE;
 }
 
 Error AidlComposer::setOutputBuffer(Display display, const native_handle_t* buffer,
                                     int releaseFence) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.setOutputBuffer(0, buffer, dup(releaseFence));
+    mWriter.setOutputBuffer(translate<int64_t>(display), 0, buffer, dup(releaseFence));
     return Error::NONE;
 }
 
@@ -562,15 +575,14 @@
 Error AidlComposer::validateDisplay(Display display, uint32_t* outNumTypes,
                                     uint32_t* outNumRequests) {
     ATRACE_NAME("HwcValidateDisplay");
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.validateDisplay();
+    mWriter.validateDisplay(translate<int64_t>(display));
 
     Error error = execute();
     if (error != Error::NONE) {
         return error;
     }
 
-    mReader.hasChanges(display, outNumTypes, outNumRequests);
+    mReader.hasChanges(translate<int64_t>(display), outNumTypes, outNumRequests);
 
     return Error::NONE;
 }
@@ -579,207 +591,154 @@
                                              uint32_t* outNumRequests, int* outPresentFence,
                                              uint32_t* state) {
     ATRACE_NAME("HwcPresentOrValidateDisplay");
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.presentOrvalidateDisplay();
+    mWriter.presentOrvalidateDisplay(translate<int64_t>(display));
 
     Error error = execute();
     if (error != Error::NONE) {
         return error;
     }
 
-    mReader.takePresentOrValidateStage(display, state);
+    mReader.takePresentOrValidateStage(translate<int64_t>(display), state);
 
     if (*state == 1) { // Present succeeded
-        mReader.takePresentFence(display, outPresentFence);
+        mReader.takePresentFence(translate<int64_t>(display), outPresentFence);
     }
 
     if (*state == 0) { // Validate succeeded.
-        mReader.hasChanges(display, outNumTypes, outNumRequests);
+        mReader.hasChanges(translate<int64_t>(display), outNumTypes, outNumRequests);
     }
 
     return Error::NONE;
 }
 
 Error AidlComposer::setCursorPosition(Display display, Layer layer, int32_t x, int32_t y) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerCursorPosition(x, y);
+    mWriter.setLayerCursorPosition(translate<int64_t>(display), translate<int64_t>(layer), x, y);
     return Error::NONE;
 }
 
 Error AidlComposer::setLayerBuffer(Display display, Layer layer, uint32_t slot,
                                    const sp<GraphicBuffer>& buffer, int acquireFence) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-
     const native_handle_t* handle = nullptr;
     if (buffer.get()) {
         handle = buffer->getNativeBuffer()->handle;
     }
 
-    mWriter.setLayerBuffer(slot, handle, acquireFence);
+    mWriter.setLayerBuffer(translate<int64_t>(display), translate<int64_t>(layer), slot, handle,
+                           acquireFence);
     return Error::NONE;
 }
 
 Error AidlComposer::setLayerSurfaceDamage(Display display, Layer layer,
                                           const std::vector<IComposerClient::Rect>& damage) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerSurfaceDamage(translate<AidlRect>(damage));
+    mWriter.setLayerSurfaceDamage(translate<int64_t>(display), translate<int64_t>(layer),
+                                  translate<AidlRect>(damage));
     return Error::NONE;
 }
 
 Error AidlComposer::setLayerBlendMode(Display display, Layer layer,
                                       IComposerClient::BlendMode mode) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerBlendMode(translate<BlendMode>(mode));
+    mWriter.setLayerBlendMode(translate<int64_t>(display), translate<int64_t>(layer),
+                              translate<BlendMode>(mode));
     return Error::NONE;
 }
 
 Error AidlComposer::setLayerColor(Display display, Layer layer,
                                   const IComposerClient::Color& color) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerColor(translate<Color>(color));
+    mWriter.setLayerColor(translate<int64_t>(display), translate<int64_t>(layer),
+                          translate<Color>(color));
     return Error::NONE;
 }
 
 Error AidlComposer::setLayerCompositionType(Display display, Layer layer,
                                             IComposerClient::Composition type) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerCompositionType(translate<Composition>(type));
+    mWriter.setLayerCompositionType(translate<int64_t>(display), translate<int64_t>(layer),
+                                    translate<Composition>(type));
     return Error::NONE;
 }
 
 Error AidlComposer::setLayerDataspace(Display display, Layer layer, Dataspace dataspace) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerDataspace(translate<AidlDataspace>(dataspace));
+    mWriter.setLayerDataspace(translate<int64_t>(display), translate<int64_t>(layer),
+                              translate<AidlDataspace>(dataspace));
     return Error::NONE;
 }
 
 Error AidlComposer::setLayerDisplayFrame(Display display, Layer layer,
                                          const IComposerClient::Rect& frame) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerDisplayFrame(translate<AidlRect>(frame));
+    mWriter.setLayerDisplayFrame(translate<int64_t>(display), translate<int64_t>(layer),
+                                 translate<AidlRect>(frame));
     return Error::NONE;
 }
 
 Error AidlComposer::setLayerPlaneAlpha(Display display, Layer layer, float alpha) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerPlaneAlpha(alpha);
+    mWriter.setLayerPlaneAlpha(translate<int64_t>(display), translate<int64_t>(layer), alpha);
     return Error::NONE;
 }
 
 Error AidlComposer::setLayerSidebandStream(Display display, Layer layer,
                                            const native_handle_t* stream) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerSidebandStream(stream);
+    mWriter.setLayerSidebandStream(translate<int64_t>(display), translate<int64_t>(layer), stream);
     return Error::NONE;
 }
 
 Error AidlComposer::setLayerSourceCrop(Display display, Layer layer,
                                        const IComposerClient::FRect& crop) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerSourceCrop(translate<AidlFRect>(crop));
+    mWriter.setLayerSourceCrop(translate<int64_t>(display), translate<int64_t>(layer),
+                               translate<AidlFRect>(crop));
     return Error::NONE;
 }
 
 Error AidlComposer::setLayerTransform(Display display, Layer layer, Transform transform) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerTransform(translate<AidlTransform>(transform));
+    mWriter.setLayerTransform(translate<int64_t>(display), translate<int64_t>(layer),
+                              translate<AidlTransform>(transform));
     return Error::NONE;
 }
 
 Error AidlComposer::setLayerVisibleRegion(Display display, Layer layer,
                                           const std::vector<IComposerClient::Rect>& visible) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerVisibleRegion(translate<AidlRect>(visible));
+    mWriter.setLayerVisibleRegion(translate<int64_t>(display), translate<int64_t>(layer),
+                                  translate<AidlRect>(visible));
     return Error::NONE;
 }
 
 Error AidlComposer::setLayerZOrder(Display display, Layer layer, uint32_t z) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerZOrder(z);
+    mWriter.setLayerZOrder(translate<int64_t>(display), translate<int64_t>(layer), z);
     return Error::NONE;
 }
 
 Error AidlComposer::execute() {
-    // prepare input command queue
-    bool queueChanged = false;
-    int32_t commandLength = 0;
-    std::vector<aidl::android::hardware::common::NativeHandle> commandHandles;
-    if (!mWriter.writeQueue(&queueChanged, &commandLength, &commandHandles)) {
-        mWriter.reset();
-        return Error::NO_RESOURCES;
-    }
-
-    // set up new input command queue if necessary
-    if (queueChanged) {
-        const auto status = mAidlComposerClient->setInputCommandQueue(mWriter.getMQDescriptor());
-        if (!status.isOk()) {
-            ALOGE("setInputCommandQueue failed %s", status.getDescription().c_str());
-            mWriter.reset();
-            return static_cast<Error>(status.getServiceSpecificError());
-        }
-    }
-
-    if (commandLength == 0) {
+    const auto& commands = mWriter.getPendingCommands();
+    if (commands.empty()) {
         mWriter.reset();
         return Error::NONE;
     }
 
-    AidlExecuteCommandsStatus commandStatus;
-    auto status =
-            mAidlComposerClient->executeCommands(commandLength, commandHandles, &commandStatus);
-    // executeCommands can fail because of out-of-fd and we do not want to
-    // abort() in that case
+    std::vector<CommandResultPayload> results;
+    auto status = mAidlComposerClient->executeCommands(commands, &results);
     if (!status.isOk()) {
         ALOGE("executeCommands failed %s", status.getDescription().c_str());
         return static_cast<Error>(status.getServiceSpecificError());
     }
 
-    // set up new output command queue if necessary
-    if (commandStatus.queueChanged) {
-        ::aidl::android::hardware::common::fmq::MQDescriptor<
-                int32_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
-                outputCommandQueue;
-        status = mAidlComposerClient->getOutputCommandQueue(&outputCommandQueue);
-        if (!status.isOk()) {
-            ALOGE("getOutputCommandQueue failed %s", status.getDescription().c_str());
-            return static_cast<Error>(status.getServiceSpecificError());
+    mReader.parse(results);
+    const auto commandErrors = mReader.takeErrors();
+    Error error = Error::NONE;
+    for (const auto& cmdErr : commandErrors) {
+        const auto index = static_cast<size_t>(cmdErr.commandIndex);
+        if (index < 0 || index >= commands.size()) {
+            ALOGE("invalid command index %zu", index);
+            return Error::BAD_PARAMETER;
         }
 
-        mReader.setMQDescriptor(outputCommandQueue);
-    }
-
-    Error error;
-    if (mReader.readQueue(commandStatus.length, std::move(commandStatus.handles))) {
-        error = static_cast<Error>(mReader.parse());
-        mReader.reset();
-    } else {
-        error = Error::NO_RESOURCES;
-    }
-
-    if (error == Error::NONE) {
-        std::vector<AidlCommandReader::CommandError> commandErrors = mReader.takeErrors();
-
-        for (const auto& cmdErr : commandErrors) {
-            auto command = mWriter.getCommand(cmdErr.location);
-            if (command == Command::VALIDATE_DISPLAY || command == Command::PRESENT_DISPLAY ||
-                command == Command::PRESENT_OR_VALIDATE_DISPLAY) {
-                error = cmdErr.error;
+        const auto& command = commands[index];
+        if (command.getTag() == command::CommandPayload::Tag::displayCommand) {
+            const auto& displayCommand =
+                    command.get<command::CommandPayload::Tag::displayCommand>();
+            if (displayCommand.validateDisplay || displayCommand.presentDisplay ||
+                displayCommand.presentOrValidateDisplay) {
+                error = translate<Error>(cmdErr.errorCode);
             } else {
-                ALOGW("command 0x%x generated error %d", command, cmdErr.error);
+                ALOGW("command '%s' generated error %" PRId32, command.toString().c_str(),
+                      cmdErr.errorCode);
             }
         }
     }
@@ -792,9 +751,8 @@
 Error AidlComposer::setLayerPerFrameMetadata(
         Display display, Layer layer,
         const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerPerFrameMetadata(translate<AidlPerFrameMetadata>(perFrameMetadatas));
+    mWriter.setLayerPerFrameMetadata(translate<int64_t>(display), translate<int64_t>(layer),
+                                     translate<AidlPerFrameMetadata>(perFrameMetadatas));
     return Error::NONE;
 }
 
@@ -855,9 +813,7 @@
 }
 
 Error AidlComposer::setLayerColorTransform(Display display, Layer layer, const float* matrix) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerColorTransform(matrix);
+    mWriter.setLayerColorTransform(translate<int64_t>(display), translate<int64_t>(layer), matrix);
     return Error::NONE;
 }
 
@@ -921,9 +877,8 @@
 Error AidlComposer::setLayerPerFrameMetadataBlobs(
         Display display, Layer layer,
         const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerPerFrameMetadataBlobs(translate<AidlPerFrameMetadataBlob>(metadata));
+    mWriter.setLayerPerFrameMetadataBlobs(translate<int64_t>(display), translate<int64_t>(layer),
+                                          translate<AidlPerFrameMetadataBlob>(metadata));
     return Error::NONE;
 }
 
@@ -1032,9 +987,8 @@
 V2_4::Error AidlComposer::setLayerGenericMetadata(Display display, Layer layer,
                                                   const std::string& key, bool mandatory,
                                                   const std::vector<uint8_t>& value) {
-    mWriter.selectDisplay(translate<int64_t>(display));
-    mWriter.selectLayer(translate<int64_t>(layer));
-    mWriter.setLayerGenericMetadata(key, mandatory, value);
+    mWriter.setLayerGenericMetadata(translate<int64_t>(display), translate<int64_t>(layer), key,
+                                    mandatory, value);
     return V2_4::Error::NONE;
 }
 
@@ -1051,320 +1005,18 @@
 }
 
 Error AidlComposer::getClientTargetProperty(
-        Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
-    mReader.takeClientTargetProperty(display, outClientTargetProperty);
+        Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
+        float* whitePointNits) {
+    ClientTargetProperty property;
+    mReader.takeClientTargetProperty(translate<int64_t>(display), &property, whitePointNits);
+    *outClientTargetProperty = translate<IComposerClient::ClientTargetProperty>(property);
     return Error::NONE;
 }
 
-AidlCommandReader::~AidlCommandReader() {
-    resetData();
-}
-
-int AidlCommandReader::parse() {
-    resetData();
-
-    Command command;
-    uint16_t length = 0;
-
-    while (!isEmpty()) {
-        if (!beginCommand(&command, &length)) {
-            break;
-        }
-
-        bool parsed = false;
-        switch (command) {
-            case Command::SELECT_DISPLAY:
-                parsed = parseSelectDisplay(length);
-                break;
-            case Command::SET_ERROR:
-                parsed = parseSetError(length);
-                break;
-            case Command::SET_CHANGED_COMPOSITION_TYPES:
-                parsed = parseSetChangedCompositionTypes(length);
-                break;
-            case Command::SET_DISPLAY_REQUESTS:
-                parsed = parseSetDisplayRequests(length);
-                break;
-            case Command::SET_PRESENT_FENCE:
-                parsed = parseSetPresentFence(length);
-                break;
-            case Command::SET_RELEASE_FENCES:
-                parsed = parseSetReleaseFences(length);
-                break;
-            case Command ::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT:
-                parsed = parseSetPresentOrValidateDisplayResult(length);
-                break;
-            case Command::SET_CLIENT_TARGET_PROPERTY:
-                parsed = parseSetClientTargetProperty(length);
-                break;
-            default:
-                parsed = false;
-                break;
-        }
-
-        endCommand();
-
-        if (!parsed) {
-            ALOGE("failed to parse command 0x%x length %" PRIu16, command, length);
-            break;
-        }
-    }
-
-    return isEmpty() ? 0 : AidlIComposerClient::EX_NO_RESOURCES;
-}
-
-bool AidlCommandReader::parseSelectDisplay(uint16_t length) {
-    if (length != CommandWriterBase::kSelectDisplayLength) {
-        return false;
-    }
-
-    mCurrentReturnData = &mReturnData[read64()];
-
-    return true;
-}
-
-bool AidlCommandReader::parseSetError(uint16_t length) {
-    if (length != CommandWriterBase::kSetErrorLength) {
-        return false;
-    }
-
-    auto location = read();
-    auto error = static_cast<Error>(readSigned());
-
-    mErrors.emplace_back(CommandError{location, error});
-
-    return true;
-}
-
-bool AidlCommandReader::parseSetChangedCompositionTypes(uint16_t length) {
-    // (layer id [64bit], composition type [32bit]) pairs
-    static constexpr int kCommandWords = 3;
-
-    if (length % kCommandWords != 0 || !mCurrentReturnData) {
-        return false;
-    }
-
-    uint32_t count = length / kCommandWords;
-    mCurrentReturnData->changedLayers.reserve(count);
-    mCurrentReturnData->compositionTypes.reserve(count);
-    while (count > 0) {
-        auto layer = read64();
-        auto type = static_cast<IComposerClient::Composition>(readSigned());
-
-        mCurrentReturnData->changedLayers.push_back(layer);
-        mCurrentReturnData->compositionTypes.push_back(type);
-
-        count--;
-    }
-
-    return true;
-}
-
-bool AidlCommandReader::parseSetDisplayRequests(uint16_t length) {
-    // display requests [32 bit] followed by
-    // (layer id [64bit], layer requests [32bit]) pairs
-    static constexpr int kDisplayRequestsWords = 1;
-    static constexpr int kCommandWords = 3;
-    if (length % kCommandWords != kDisplayRequestsWords || !mCurrentReturnData) {
-        return false;
-    }
-
-    mCurrentReturnData->displayRequests = read();
-
-    uint32_t count = (length - kDisplayRequestsWords) / kCommandWords;
-    mCurrentReturnData->requestedLayers.reserve(count);
-    mCurrentReturnData->requestMasks.reserve(count);
-    while (count > 0) {
-        auto layer = read64();
-        auto layerRequestMask = read();
-
-        mCurrentReturnData->requestedLayers.push_back(layer);
-        mCurrentReturnData->requestMasks.push_back(layerRequestMask);
-
-        count--;
-    }
-
-    return true;
-}
-
-bool AidlCommandReader::parseSetPresentFence(uint16_t length) {
-    if (length != CommandWriterBase::kSetPresentFenceLength || !mCurrentReturnData) {
-        return false;
-    }
-
-    if (mCurrentReturnData->presentFence >= 0) {
-        close(mCurrentReturnData->presentFence);
-    }
-    mCurrentReturnData->presentFence = readFence();
-
-    return true;
-}
-
-bool AidlCommandReader::parseSetReleaseFences(uint16_t length) {
-    // (layer id [64bit], release fence index [32bit]) pairs
-    static constexpr int kCommandWords = 3;
-
-    if (length % kCommandWords != 0 || !mCurrentReturnData) {
-        return false;
-    }
-
-    uint32_t count = length / kCommandWords;
-    mCurrentReturnData->releasedLayers.reserve(count);
-    mCurrentReturnData->releaseFences.reserve(count);
-    while (count > 0) {
-        auto layer = read64();
-        auto fence = readFence();
-
-        mCurrentReturnData->releasedLayers.push_back(layer);
-        mCurrentReturnData->releaseFences.push_back(fence);
-
-        count--;
-    }
-
-    return true;
-}
-
-bool AidlCommandReader::parseSetPresentOrValidateDisplayResult(uint16_t length) {
-    if (length != CommandWriterBase::kPresentOrValidateDisplayResultLength || !mCurrentReturnData) {
-        return false;
-    }
-    mCurrentReturnData->presentOrValidateState = read();
-    return true;
-}
-
-bool AidlCommandReader::parseSetClientTargetProperty(uint16_t length) {
-    if (length != CommandWriterBase::kSetClientTargetPropertyLength || !mCurrentReturnData) {
-        return false;
-    }
-    mCurrentReturnData->clientTargetProperty.pixelFormat = static_cast<PixelFormat>(readSigned());
-    mCurrentReturnData->clientTargetProperty.dataspace = static_cast<Dataspace>(readSigned());
-    return true;
-}
-
-void AidlCommandReader::resetData() {
-    mErrors.clear();
-
-    for (auto& data : mReturnData) {
-        if (data.second.presentFence >= 0) {
-            close(data.second.presentFence);
-        }
-        for (auto fence : data.second.releaseFences) {
-            if (fence >= 0) {
-                close(fence);
-            }
-        }
-    }
-
-    mReturnData.clear();
-    mCurrentReturnData = nullptr;
-}
-
-std::vector<AidlCommandReader::CommandError> AidlCommandReader::takeErrors() {
-    return std::move(mErrors);
-}
-
-bool AidlCommandReader::hasChanges(Display display, uint32_t* outNumChangedCompositionTypes,
-                                   uint32_t* outNumLayerRequestMasks) const {
-    auto found = mReturnData.find(display);
-    if (found == mReturnData.end()) {
-        *outNumChangedCompositionTypes = 0;
-        *outNumLayerRequestMasks = 0;
-        return false;
-    }
-
-    const ReturnData& data = found->second;
-
-    *outNumChangedCompositionTypes = static_cast<uint32_t>(data.compositionTypes.size());
-    *outNumLayerRequestMasks = static_cast<uint32_t>(data.requestMasks.size());
-
-    return !(data.compositionTypes.empty() && data.requestMasks.empty());
-}
-
-void AidlCommandReader::takeChangedCompositionTypes(
-        Display display, std::vector<Layer>* outLayers,
-        std::vector<IComposerClient::Composition>* outTypes) {
-    auto found = mReturnData.find(display);
-    if (found == mReturnData.end()) {
-        outLayers->clear();
-        outTypes->clear();
-        return;
-    }
-
-    ReturnData& data = found->second;
-
-    *outLayers = std::move(data.changedLayers);
-    *outTypes = std::move(data.compositionTypes);
-}
-
-void AidlCommandReader::takeDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
-                                            std::vector<Layer>* outLayers,
-                                            std::vector<uint32_t>* outLayerRequestMasks) {
-    auto found = mReturnData.find(display);
-    if (found == mReturnData.end()) {
-        *outDisplayRequestMask = 0;
-        outLayers->clear();
-        outLayerRequestMasks->clear();
-        return;
-    }
-
-    ReturnData& data = found->second;
-
-    *outDisplayRequestMask = data.displayRequests;
-    *outLayers = std::move(data.requestedLayers);
-    *outLayerRequestMasks = std::move(data.requestMasks);
-}
-
-void AidlCommandReader::takeReleaseFences(Display display, std::vector<Layer>* outLayers,
-                                          std::vector<int>* outReleaseFences) {
-    auto found = mReturnData.find(display);
-    if (found == mReturnData.end()) {
-        outLayers->clear();
-        outReleaseFences->clear();
-        return;
-    }
-
-    ReturnData& data = found->second;
-
-    *outLayers = std::move(data.releasedLayers);
-    *outReleaseFences = std::move(data.releaseFences);
-}
-
-void AidlCommandReader::takePresentFence(Display display, int* outPresentFence) {
-    auto found = mReturnData.find(display);
-    if (found == mReturnData.end()) {
-        *outPresentFence = -1;
-        return;
-    }
-
-    ReturnData& data = found->second;
-
-    *outPresentFence = data.presentFence;
-    data.presentFence = -1;
-}
-
-void AidlCommandReader::takePresentOrValidateStage(Display display, uint32_t* state) {
-    auto found = mReturnData.find(display);
-    if (found == mReturnData.end()) {
-        *state = static_cast<uint32_t>(-1);
-        return;
-    }
-    ReturnData& data = found->second;
-    *state = data.presentOrValidateState;
-}
-
-void AidlCommandReader::takeClientTargetProperty(
-        Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
-    auto found = mReturnData.find(display);
-
-    // If not found, return the default values.
-    if (found == mReturnData.end()) {
-        outClientTargetProperty->pixelFormat = PixelFormat::RGBA_8888;
-        outClientTargetProperty->dataspace = Dataspace::UNKNOWN;
-        return;
-    }
-
-    ReturnData& data = found->second;
-    *outClientTargetProperty = data.clientTargetProperty;
+Error AidlComposer::setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) {
+    mWriter.setLayerWhitePointNits(translate<int64_t>(display), translate<int64_t>(layer),
+                                   whitePointNits);
+    return Error::NONE;
 }
 
 } // namespace Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index a6d9500..8cae25f 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -43,95 +43,10 @@
 
 using AidlCommandWriterBase = aidl::android::hardware::graphics::composer3::CommandWriterBase;
 using AidlCommandReaderBase = aidl::android::hardware::graphics::composer3::CommandReaderBase;
+using aidl::android::hardware::graphics::composer3::command::CommandResultPayload;
 
 class AidlIComposerCallbackWrapper;
 
-class AidlCommandReader : public AidlCommandReaderBase {
-public:
-    ~AidlCommandReader();
-
-    // Parse and execute commands from the command queue.  The commands are
-    // actually return values from the server and will be saved in ReturnData.
-    int parse();
-
-    // Get and clear saved errors.
-    struct CommandError {
-        uint32_t location;
-        Error error;
-    };
-    std::vector<CommandError> takeErrors();
-
-    bool hasChanges(Display display, uint32_t* outNumChangedCompositionTypes,
-                    uint32_t* outNumLayerRequestMasks) const;
-
-    // Get and clear saved changed composition types.
-    void takeChangedCompositionTypes(Display display, std::vector<Layer>* outLayers,
-                                     std::vector<IComposerClient::Composition>* outTypes);
-
-    // Get and clear saved display requests.
-    void takeDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
-                             std::vector<Layer>* outLayers,
-                             std::vector<uint32_t>* outLayerRequestMasks);
-
-    // Get and clear saved release fences.
-    void takeReleaseFences(Display display, std::vector<Layer>* outLayers,
-                           std::vector<int>* outReleaseFences);
-
-    // Get and clear saved present fence.
-    void takePresentFence(Display display, int* outPresentFence);
-
-    // Get what stage succeeded during PresentOrValidate: Present or Validate
-    void takePresentOrValidateStage(Display display, uint32_t* state);
-
-    // Get the client target properties requested by hardware composer.
-    void takeClientTargetProperty(Display display,
-                                  IComposerClient::ClientTargetProperty* outClientTargetProperty);
-
-private:
-    void resetData();
-
-    bool parseSelectDisplay(uint16_t length);
-    bool parseSetError(uint16_t length);
-    bool parseSetChangedCompositionTypes(uint16_t length);
-    bool parseSetDisplayRequests(uint16_t length);
-    bool parseSetPresentFence(uint16_t length);
-    bool parseSetReleaseFences(uint16_t length);
-    bool parseSetPresentOrValidateDisplayResult(uint16_t length);
-    bool parseSetClientTargetProperty(uint16_t length);
-
-    struct ReturnData {
-        uint32_t displayRequests = 0;
-
-        std::vector<Layer> changedLayers;
-        std::vector<IComposerClient::Composition> compositionTypes;
-
-        std::vector<Layer> requestedLayers;
-        std::vector<uint32_t> requestMasks;
-
-        int presentFence = -1;
-
-        std::vector<Layer> releasedLayers;
-        std::vector<int> releaseFences;
-
-        uint32_t presentOrValidateState;
-
-        // Composer 2.4 implementation can return a client target property
-        // structure to indicate the client target properties that hardware
-        // composer requests. The composer client must change the client target
-        // properties to match this request.
-        IComposerClient::ClientTargetProperty clientTargetProperty{PixelFormat::RGBA_8888,
-                                                                   Dataspace::UNKNOWN};
-    };
-
-    std::vector<CommandError> mErrors;
-    std::unordered_map<Display, ReturnData> mReturnData;
-
-    // When SELECT_DISPLAY is parsed, this is updated to point to the
-    // display's return data in mReturnData.  We use it to avoid repeated
-    // map lookups.
-    ReturnData* mCurrentReturnData;
-};
-
 // Composer is a wrapper to IComposer, a proxy to server-side composer.
 class AidlComposer final : public Hwc2::Composer {
 public:
@@ -279,18 +194,12 @@
                                         bool mandatory, const std::vector<uint8_t>& value) override;
     V2_4::Error getLayerGenericMetadataKeys(
             std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
-    Error getClientTargetProperty(
-            Display display,
-            IComposerClient::ClientTargetProperty* outClientTargetProperty) override;
+    Error getClientTargetProperty(Display display,
+                                  IComposerClient::ClientTargetProperty* outClientTargetProperty,
+                                  float* outClientTargetWhitePointNits) override;
+    Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override;
 
 private:
-    class AidlCommandWriter : public AidlCommandWriterBase {
-    public:
-        explicit AidlCommandWriter(uint32_t initialMaxSize)
-              : AidlCommandWriterBase(initialMaxSize) {}
-        ~AidlCommandWriter() override {}
-    };
-
     // Many public functions above simply write a command into the command
     // queue to batch the calls.  validateDisplay and presentDisplay will call
     // this function to execute the command queue.
@@ -306,8 +215,8 @@
     // 1. Tightly coupling this cache to the max size of BufferQueue
     // 2. Adding an additional slot for the layer caching feature in SurfaceFlinger (see: Planner.h)
     static const constexpr uint32_t kMaxLayerBufferCount = BufferQueue::NUM_BUFFER_SLOTS + 1;
-    AidlCommandWriter mWriter;
-    AidlCommandReader mReader;
+    AidlCommandWriterBase mWriter;
+    AidlCommandReaderBase mReader;
 
     // Aidl interface
     using AidlIComposer = aidl::android::hardware::graphics::composer3::IComposer;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 3bbce7b..3cc5e5e 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -221,7 +221,11 @@
     virtual V2_4::Error getLayerGenericMetadataKeys(
             std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
     virtual Error getClientTargetProperty(
-            Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0;
+            Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
+            float* outWhitePointNits) = 0;
+
+    // AIDL Composer
+    virtual Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) = 0;
 };
 
 } // namespace android::Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index e21b0da..596666c 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -555,8 +555,10 @@
     return static_cast<Error>(intError);
 }
 
-Error Display::getClientTargetProperty(ClientTargetProperty* outClientTargetProperty) {
-    const auto error = mComposer.getClientTargetProperty(mId, outClientTargetProperty);
+Error Display::getClientTargetProperty(ClientTargetProperty* outClientTargetProperty,
+                                       float* outWhitePointNits) {
+    const auto error =
+            mComposer.getClientTargetProperty(mId, outClientTargetProperty, outWhitePointNits);
     return static_cast<Error>(error);
 }
 
@@ -919,6 +921,16 @@
     return static_cast<Error>(intError);
 }
 
+// AIDL HAL
+Error Layer::setWhitePointNits(float whitePointNits) {
+    if (CC_UNLIKELY(!mDisplay)) {
+        return Error::BAD_DISPLAY;
+    }
+
+    auto intError = mComposer.setLayerWhitePointNits(mDisplay->getId(), mId, whitePointNits);
+    return static_cast<Error>(intError);
+}
+
 } // namespace impl
 } // namespace HWC2
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index a65efb2..5e0ba06 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -146,7 +146,7 @@
             std::vector<hal::ContentType>*) const = 0;
     [[clang::warn_unused_result]] virtual hal::Error setContentType(hal::ContentType) = 0;
     [[clang::warn_unused_result]] virtual hal::Error getClientTargetProperty(
-            hal::ClientTargetProperty* outClientTargetProperty) = 0;
+            hal::ClientTargetProperty* outClientTargetProperty, float* outWhitePointNits) = 0;
 };
 
 namespace impl {
@@ -209,7 +209,8 @@
     hal::Error getSupportedContentTypes(
             std::vector<hal::ContentType>* outSupportedContentTypes) const override;
     hal::Error setContentType(hal::ContentType) override;
-    hal::Error getClientTargetProperty(hal::ClientTargetProperty* outClientTargetProperty) override;
+    hal::Error getClientTargetProperty(hal::ClientTargetProperty* outClientTargetProperty,
+                                       float* outWhitePointNits) override;
 
     // Other Display methods
     hal::HWDisplayId getId() const override { return mId; }
@@ -288,6 +289,9 @@
     // Composer HAL 2.4
     [[clang::warn_unused_result]] virtual hal::Error setLayerGenericMetadata(
             const std::string& name, bool mandatory, const std::vector<uint8_t>& value) = 0;
+
+    // AIDL HAL
+    [[clang::warn_unused_result]] virtual hal::Error setWhitePointNits(float whitePointNits) = 0;
 };
 
 namespace impl {
@@ -331,6 +335,9 @@
     hal::Error setLayerGenericMetadata(const std::string& name, bool mandatory,
                                        const std::vector<uint8_t>& value) override;
 
+    // AIDL HAL
+    hal::Error setWhitePointNits(float whitePointNits) override;
+
 private:
     // These are references to data owned by HWC2::Device, which will outlive
     // this HWC2::Layer, so these references are guaranteed to be valid for
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 06f5df5..d851e22 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -522,11 +522,13 @@
     RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
 
     DeviceRequestedChanges::ClientTargetProperty clientTargetProperty;
-    error = hwcDisplay->getClientTargetProperty(&clientTargetProperty);
+    float clientTargetWhitePointNits;
+    error = hwcDisplay->getClientTargetProperty(&clientTargetProperty, &clientTargetWhitePointNits);
 
     outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
                                                std::move(layerRequests),
-                                               std::move(clientTargetProperty)});
+                                               std::move(clientTargetProperty),
+                                               clientTargetWhitePointNits});
     error = hwcDisplay->acceptChanges();
     RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 0a090da..bd79977 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -79,6 +79,7 @@
         DisplayRequests displayRequests;
         LayerRequests layerRequests;
         ClientTargetProperty clientTargetProperty;
+        float clientTargetWhitePointNits;
     };
 
     struct HWCDisplayMode {
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 6c40598..11d41c0 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -1164,8 +1164,14 @@
 }
 
 Error HidlComposer::getClientTargetProperty(
-        Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
+        Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
+        float* outWhitePointNits) {
     mReader.takeClientTargetProperty(display, outClientTargetProperty);
+    *outWhitePointNits = -1.f;
+    return Error::NONE;
+}
+
+Error HidlComposer::setLayerWhitePointNits(Display, Layer, float) {
     return Error::NONE;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index ad253a2..18c0635 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -304,9 +304,10 @@
                                         bool mandatory, const std::vector<uint8_t>& value) override;
     V2_4::Error getLayerGenericMetadataKeys(
             std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
-    Error getClientTargetProperty(
-            Display display,
-            IComposerClient::ClientTargetProperty* outClientTargetProperty) override;
+    Error getClientTargetProperty(Display display,
+                                  IComposerClient::ClientTargetProperty* outClientTargetProperty,
+                                  float* outWhitePointNits) override;
+    Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override;
 
 private:
     class CommandWriter : public CommandWriterBase {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index dfb99cc..b395159 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -46,6 +46,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <sys/types.h>
+#include <ui/DataspaceUtils.h>
 #include <ui/DebugUtils.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
@@ -418,6 +419,8 @@
 
     compositionState->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
     compositionState->alpha = alpha;
+    compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
+    compositionState->blurRegions = drawingState.blurRegions;
     compositionState->stretchEffect = getStretchEffect();
 }
 
@@ -482,6 +485,11 @@
     // If there are no visible region changes, we still need to update blur parameters.
     compositionState->blurRegions = drawingState.blurRegions;
     compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
+
+    // Layer framerate is used in caching decisions.
+    // Retrieve it from the scheduler which maintains an instance of LayerHistory, and store it in
+    // LayerFECompositionState where it would be visible to Flattener.
+    compositionState->fps = mFlinger->getLayerFramerate(systemTime(), getSequence());
 }
 
 void Layer::prepareCursorCompositionState() {
@@ -578,6 +586,8 @@
 
     layerSettings.alpha = alpha;
     layerSettings.sourceDataspace = getDataSpace();
+
+    layerSettings.whitePointNits = targetSettings.whitePointNits;
     switch (targetSettings.blurSetting) {
         case LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled:
             layerSettings.backgroundBlurRadius = getBackgroundBlurRadius();
@@ -932,7 +942,6 @@
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
-
 bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix,
         bool allowNonRectPreservingTransforms) {
     ui::Transform t;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 84e3548..74a2ca7 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -84,42 +84,38 @@
 
 void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) {
     std::lock_guard lock(mLock);
-    for (const auto& info : mLayerInfos) {
-        LOG_ALWAYS_FATAL_IF(info.first == layer, "%s already registered", layer->getName().c_str());
-    }
+    LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first !=
+                                LayerHistory::layerStatus::NotFound,
+                        "%s already registered", layer->getName().c_str());
     auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type);
-    mLayerInfos.emplace_back(layer, std::move(info));
+
+    // The layer can be placed on either map, it is assumed that partitionLayers() will be called
+    // to correct them.
+    mInactiveLayerInfos.insert({layer->getSequence(), std::make_pair(layer, std::move(info))});
 }
 
 void LayerHistory::deregisterLayer(Layer* layer) {
     std::lock_guard lock(mLock);
-
-    const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
-                                 [layer](const auto& pair) { return pair.first == layer; });
-    LOG_ALWAYS_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
-
-    const size_t i = static_cast<size_t>(it - mLayerInfos.begin());
-    if (i < mActiveLayersEnd) {
-        mActiveLayersEnd--;
+    if (!mActiveLayerInfos.erase(layer->getSequence())) {
+        if (!mInactiveLayerInfos.erase(layer->getSequence())) {
+            LOG_ALWAYS_FATAL("%s: unknown layer %p", __FUNCTION__, layer);
+        }
     }
-    const size_t last = mLayerInfos.size() - 1;
-    std::swap(mLayerInfos[i], mLayerInfos[last]);
-    mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(last));
 }
 
 void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
                           LayerUpdateType updateType) {
     std::lock_guard lock(mLock);
+    auto id = layer->getSequence();
 
-    const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
-                                 [layer](const auto& pair) { return pair.first == layer; });
-    if (it == mLayerInfos.end()) {
+    auto [found, layerPair] = findLayer(id);
+    if (found == LayerHistory::layerStatus::NotFound) {
         // Offscreen layer
         ALOGV("LayerHistory::record: %s not registered", layer->getName().c_str());
         return;
     }
 
-    const auto& info = it->second;
+    const auto& info = layerPair->second;
     const auto layerProps = LayerInfo::LayerProps{
             .visible = layer->isVisible(),
             .bounds = layer->getBounds(),
@@ -131,9 +127,10 @@
     info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps);
 
     // Activate layer if inactive.
-    if (const auto end = activeLayers().end(); it >= end) {
-        std::iter_swap(it, end);
-        mActiveLayersEnd++;
+    if (found == LayerHistory::layerStatus::LayerInInactiveMap) {
+        mActiveLayerInfos.insert(
+                {id, std::make_pair(layerPair->first, std::move(layerPair->second))});
+        mInactiveLayerInfos.erase(id);
     }
 }
 
@@ -145,7 +142,8 @@
 
     partitionLayers(now);
 
-    for (const auto& [layer, info] : activeLayers()) {
+    for (const auto& [key, value] : mActiveLayerInfos) {
+        auto& info = value.second;
         const auto frameRateSelectionPriority = info->getFrameRateSelectionPriority();
         const auto layerFocused = Layer::isLayerFocusedBasedOnPriority(frameRateSelectionPriority);
         ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority,
@@ -179,12 +177,29 @@
 void LayerHistory::partitionLayers(nsecs_t now) {
     const nsecs_t threshold = getActiveLayerThreshold(now);
 
-    // Collect expired and inactive layers after active layers.
-    size_t i = 0;
-    while (i < mActiveLayersEnd) {
-        auto& [layerUnsafe, info] = mLayerInfos[i];
+    // iterate over inactive map
+    LayerInfos::iterator it = mInactiveLayerInfos.begin();
+    while (it != mInactiveLayerInfos.end()) {
+        auto& [layerUnsafe, info] = it->second;
         if (isLayerActive(*info, threshold)) {
-            i++;
+            // move this to the active map
+
+            mActiveLayerInfos.insert({it->first, std::move(it->second)});
+            it = mInactiveLayerInfos.erase(it);
+        } else {
+            if (CC_UNLIKELY(mTraceEnabled)) {
+                trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
+            }
+            info->onLayerInactive(now);
+            it++;
+        }
+    }
+
+    // iterate over active map
+    it = mActiveLayerInfos.begin();
+    while (it != mActiveLayerInfos.end()) {
+        auto& [layerUnsafe, info] = it->second;
+        if (isLayerActive(*info, threshold)) {
             // Set layer vote if set
             const auto frameRate = info->getSetFrameRateVote();
             const auto voteType = [&]() {
@@ -206,30 +221,68 @@
             } else {
                 info->resetLayerVote();
             }
-            continue;
-        }
 
-        if (CC_UNLIKELY(mTraceEnabled)) {
-            trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
+            it++;
+        } else {
+            if (CC_UNLIKELY(mTraceEnabled)) {
+                trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
+            }
+            info->onLayerInactive(now);
+            // move this to the inactive map
+            mInactiveLayerInfos.insert({it->first, std::move(it->second)});
+            it = mActiveLayerInfos.erase(it);
         }
-
-        info->onLayerInactive(now);
-        std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]);
     }
 }
 
 void LayerHistory::clear() {
     std::lock_guard lock(mLock);
-
-    for (const auto& [layer, info] : activeLayers()) {
-        info->clearHistory(systemTime());
+    for (const auto& [key, value] : mActiveLayerInfos) {
+        value.second->clearHistory(systemTime());
     }
 }
 
 std::string LayerHistory::dump() const {
     std::lock_guard lock(mLock);
-    return base::StringPrintf("LayerHistory{size=%zu, active=%zu}", mLayerInfos.size(),
-                              mActiveLayersEnd);
+    return base::StringPrintf("LayerHistory{size=%zu, active=%zu}",
+                              mActiveLayerInfos.size() + mInactiveLayerInfos.size(),
+                              mActiveLayerInfos.size());
+}
+
+float LayerHistory::getLayerFramerate(nsecs_t now, int32_t id) const {
+    std::lock_guard lock(mLock);
+    auto [found, layerPair] = findLayer(id);
+    if (found != LayerHistory::layerStatus::NotFound) {
+        return layerPair->second->getFps(now).getValue();
+    }
+    return 0.f;
+}
+
+std::pair<LayerHistory::layerStatus, LayerHistory::LayerPair*> LayerHistory::findLayer(int32_t id) {
+    // the layer could be in either the active or inactive map, try both
+    auto it = mActiveLayerInfos.find(id);
+    if (it != mActiveLayerInfos.end()) {
+        return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second));
+    }
+    it = mInactiveLayerInfos.find(id);
+    if (it != mInactiveLayerInfos.end()) {
+        return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second));
+    }
+    return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr);
+}
+
+std::pair<LayerHistory::layerStatus, const LayerHistory::LayerPair*> LayerHistory::findLayer(
+        int32_t id) const {
+    // the layer could be in either the active or inactive map, try both
+    auto it = mActiveLayerInfos.find(id);
+    if (it != mActiveLayerInfos.end()) {
+        return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second));
+    }
+    it = mInactiveLayerInfos.find(id);
+    if (it != mInactiveLayerInfos.end()) {
+        return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second));
+    }
+    return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr);
 }
 
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 8d56951..cc55700 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -20,6 +20,7 @@
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 
+#include <map>
 #include <memory>
 #include <mutex>
 #include <string>
@@ -72,34 +73,43 @@
     void deregisterLayer(Layer*);
     std::string dump() const;
 
+    // return the frames per second of the layer with the given sequence id.
+    float getLayerFramerate(nsecs_t now, int32_t id) const;
+
 private:
     friend class LayerHistoryTest;
     friend class TestableScheduler;
 
     using LayerPair = std::pair<Layer*, std::unique_ptr<LayerInfo>>;
-    using LayerInfos = std::vector<LayerPair>;
+    // keyed by id as returned from Layer::getSequence()
+    using LayerInfos = std::unordered_map<int32_t, LayerPair>;
 
-    struct ActiveLayers {
-        LayerInfos& infos;
-        const size_t index;
+    // Iterates over layers maps moving all active layers to mActiveLayerInfos and all inactive
+    // layers to mInactiveLayerInfos.
+    // worst case time complexity is O(2 * inactive + active)
+    void partitionLayers(nsecs_t now) REQUIRES(mLock);
 
-        auto begin() { return infos.begin(); }
-        auto end() { return begin() + static_cast<long>(index); }
+    enum class layerStatus {
+        NotFound,
+        LayerInActiveMap,
+        LayerInInactiveMap,
     };
 
-    ActiveLayers activeLayers() REQUIRES(mLock) { return {mLayerInfos, mActiveLayersEnd}; }
-
-    // Iterates over layers in a single pass, swapping pairs such that active layers precede
-    // inactive layers, and inactive layers precede expired layers. Removes expired layers by
-    // truncating after inactive layers.
-    void partitionLayers(nsecs_t now) REQUIRES(mLock);
+    // looks up a layer by sequence id in both layerInfo maps.
+    // The first element indicates if and where the item was found
+    std::pair<layerStatus, LayerHistory::LayerPair*> findLayer(int32_t id) REQUIRES(mLock);
+    std::pair<layerStatus, const LayerHistory::LayerPair*> findLayer(int32_t id) const
+            REQUIRES(mLock);
 
     mutable std::mutex mLock;
 
-    // Partitioned such that active layers precede inactive layers. For fast lookup, the few active
-    // layers are at the front, and weak pointers are stored in contiguous memory to hit the cache.
-    LayerInfos mLayerInfos GUARDED_BY(mLock);
-    size_t mActiveLayersEnd GUARDED_BY(mLock) = 0;
+    // Partitioned into two maps to facility two kinds of retrieval:
+    // 1. retrieval of a layer by id (attempt lookup in both maps)
+    // 2. retrieval of all active layers (iterate that map)
+    // The partitioning is allowed to become out of date but calling partitionLayers refreshes the
+    // validity of each map.
+    LayerInfos mActiveLayerInfos GUARDED_BY(mLock);
+    LayerInfos mInactiveLayerInfos GUARDED_BY(mLock);
 
     uint32_t mDisplayArea = 0;
 
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index ae61eeb..943615c 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -75,12 +75,16 @@
 }
 
 bool LayerInfo::isFrequent(nsecs_t now) const {
+    using fps_approx_ops::operator>=;
     // If we know nothing about this layer we consider it as frequent as it might be the start
     // of an animation.
     if (mFrameTimes.size() < kFrequentLayerWindowSize) {
         return true;
     }
+    return getFps(now) >= kMinFpsForFrequentLayer;
+}
 
+Fps LayerInfo::getFps(nsecs_t now) const {
     // Find the first active frame
     auto it = mFrameTimes.begin();
     for (; it != mFrameTimes.end(); ++it) {
@@ -91,14 +95,12 @@
 
     const auto numFrames = std::distance(it, mFrameTimes.end());
     if (numFrames < kFrequentLayerWindowSize) {
-        return false;
+        return Fps();
     }
 
-    using fps_approx_ops::operator>=;
-
     // Layer is considered frequent if the average frame rate is higher than the threshold
     const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
-    return Fps::fromPeriodNsecs(totalTime / (numFrames - 1)) >= kMinFpsForFrequentLayer;
+    return Fps::fromPeriodNsecs(totalTime / (numFrames - 1));
 }
 
 bool LayerInfo::isAnimating(nsecs_t now) const {
@@ -236,7 +238,7 @@
     if (!isFrequent(now)) {
         ALOGV("%s is infrequent", mName.c_str());
         mLastRefreshRate.animatingOrInfrequent = true;
-        // Infrequent layers vote for minimal refresh rate for
+        // Infrequent layers vote for mininal refresh rate for
         // battery saving purposes and also to prevent b/135718869.
         return {LayerHistory::LayerVoteType::Min, Fps()};
     }
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 690abda..2d88a4f 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -178,6 +178,9 @@
     // Returns a C string for tracing a vote
     const char* getTraceTag(LayerHistory::LayerVoteType type) const;
 
+    // Return the framerate of this layer.
+    Fps getFps(nsecs_t now) const;
+
     void onLayerInactive(nsecs_t now) {
         // Mark mFrameTimeValidSince to now to ignore all previous frame times.
         // We are not deleting the old frame to keep track of whether we should treat the first
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index e127ff7..818f1ed 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -233,6 +233,11 @@
         return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
     }
 
+    // Returns the framerate of the layer with the given sequence ID
+    float getLayerFramerate(nsecs_t now, int32_t id) const {
+        return mLayerHistory.getLayerFramerate(now, id);
+    }
+
 private:
     friend class TestableScheduler;
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5f5f1f6..4f38588 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -67,6 +67,7 @@
 #include <renderengine/RenderEngine.h>
 #include <sys/types.h>
 #include <ui/ColorSpace.h>
+#include <ui/DataspaceUtils.h>
 #include <ui/DebugUtils.h>
 #include <ui/DisplayId.h>
 #include <ui/DisplayMode.h>
@@ -93,6 +94,7 @@
 #include <type_traits>
 #include <unordered_map>
 
+#include "BackgroundExecutor.h"
 #include "BufferLayer.h"
 #include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
@@ -492,7 +494,8 @@
 
     enableLatchUnsignaledConfig = getLatchUnsignaledConfig();
 
-    mTransactionTracingEnabled = property_get_bool("debug.sf.enable_transaction_tracing", false);
+    mTransactionTracingEnabled =
+            !mIsUserBuild && property_get_bool("debug.sf.enable_transaction_tracing", true);
     if (mTransactionTracingEnabled) {
         mTransactionTracing.enable();
     }
@@ -2315,12 +2318,7 @@
             mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
                 const auto layerFe = layer->getCompositionEngineLayerFE();
                 if (layer->isVisible() && compositionDisplay->includesLayer(layerFe)) {
-                    const Dataspace transfer =
-                        static_cast<Dataspace>(layer->getDataSpace() & Dataspace::TRANSFER_MASK);
-                    const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 ||
-                                        transfer == Dataspace::TRANSFER_HLG);
-
-                    if (isHdr) {
+                    if (isHdrDataspace(layer->getDataSpace())) {
                         const auto* outputLayer =
                             compositionDisplay->getOutputLayerForLayer(layerFe);
                         if (outputLayer) {
@@ -3054,28 +3052,45 @@
         return;
     }
 
+    std::vector<WindowInfo> windowInfos;
+    std::vector<DisplayInfo> displayInfos;
+    bool updateWindowInfo = false;
     if (mVisibleRegionsDirty || mInputInfoChanged) {
         mInputInfoChanged = false;
-        notifyWindowInfos();
-    } else if (mInputWindowCommands.syncInputWindows) {
-        // If the caller requested to sync input windows, but there are no
-        // changes to input windows, notify immediately.
-        windowInfosReported();
+        updateWindowInfo = true;
+        buildWindowInfos(windowInfos, displayInfos);
     }
+    if (!updateWindowInfo && mInputWindowCommands.empty()) {
+        return;
+    }
+    BackgroundExecutor::getInstance().execute([updateWindowInfo,
+                                               windowInfos = std::move(windowInfos),
+                                               displayInfos = std::move(displayInfos),
+                                               inputWindowCommands =
+                                                       std::move(mInputWindowCommands),
+                                               inputFlinger = mInputFlinger, this]() {
+        ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
+        if (updateWindowInfo) {
+            mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
+                                                            inputWindowCommands.syncInputWindows);
+        } else if (inputWindowCommands.syncInputWindows) {
+            // If the caller requested to sync input windows, but there are no
+            // changes to input windows, notify immediately.
+            windowInfosReported();
+        }
+        for (const auto& focusRequest : inputWindowCommands.focusRequests) {
+            inputFlinger->setFocusedWindow(focusRequest);
+        }
+    });
 
-    for (const auto& focusRequest : mInputWindowCommands.focusRequests) {
-        mInputFlinger->setFocusedWindow(focusRequest);
-    }
     mInputWindowCommands.clear();
 }
 
-void SurfaceFlinger::notifyWindowInfos() {
-    std::vector<WindowInfo> windowInfos;
-    std::vector<DisplayInfo> displayInfos;
+void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos,
+                                      std::vector<DisplayInfo>& outDisplayInfos) {
     std::unordered_map<uint32_t /*layerStackId*/,
                        std::pair<bool /* isSecure */, const ui::Transform>>
             inputDisplayDetails;
-
     for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
         if (!display->receivesInput()) {
             continue;
@@ -3089,7 +3104,7 @@
                   layerStackId);
             continue;
         }
-        displayInfos.emplace_back(info);
+        outDisplayInfos.emplace_back(info);
     }
 
     mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
@@ -3104,15 +3119,10 @@
             const auto& [secure, transform] = it->second;
             isSecure = secure;
             displayTransform = transform;
-        } else {
-            ALOGE("No input-enabled display found for layer `%s` on layer stack id: %d",
-                  layer->getDebugName(), layerStackId);
         }
 
-        windowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure));
+        outWindowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure));
     });
-    mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
-                                                    mInputWindowCommands.syncInputWindows);
 }
 
 void SurfaceFlinger::updateCursorAsync() {
@@ -4328,8 +4338,9 @@
     return hasChanges ? eTraversalNeeded : 0;
 }
 
-status_t SurfaceFlinger::mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
-                                     sp<IBinder>* outHandle, int32_t* outLayerId) {
+status_t SurfaceFlinger::mirrorLayer(const LayerCreationArgs& args,
+                                     const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,
+                                     int32_t* outLayerId) {
     if (!mirrorFromHandle) {
         return NAME_NOT_FOUND;
     }
@@ -4342,7 +4353,6 @@
         if (!mirrorFrom) {
             return NAME_NOT_FOUND;
         }
-        LayerCreationArgs args(this, client, "MirrorRoot", 0, LayerMetadata());
         status_t result = createContainerLayer(args, outHandle, &mirrorLayer);
         if (result != NO_ERROR) {
             return result;
@@ -4352,7 +4362,11 @@
     }
 
     *outLayerId = mirrorLayer->sequence;
-    return addClientLayer(client, *outHandle, mirrorLayer /* layer */, nullptr /* parent */,
+    if (mTransactionTracingEnabled) {
+        mTransactionTracing.onMirrorLayerAdded((*outHandle)->localBinder(), mirrorLayer->sequence,
+                                               args.name, mirrorFrom->sequence);
+    }
+    return addClientLayer(args.client, *outHandle, mirrorLayer /* layer */, nullptr /* parent */,
                           false /* addAsRoot */, nullptr /* outTransformHint */);
 }
 
@@ -4402,10 +4416,6 @@
     if (parentLayer != nullptr) {
         addToRoot = false;
     }
-    result = addClientLayer(args.client, *outHandle, layer, parent, addToRoot, outTransformHint);
-    if (result != NO_ERROR) {
-        return result;
-    }
 
     int parentId = -1;
     // We can safely promote the layer in binder thread because we have a strong reference
@@ -4414,8 +4424,15 @@
     if (parentSp != nullptr) {
         parentId = parentSp->getSequence();
     }
-    mTransactionTracing.onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name,
-                                     args.flags, parentId);
+    if (mTransactionTracingEnabled) {
+        mTransactionTracing.onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name,
+                                         args.flags, parentId);
+    }
+
+    result = addClientLayer(args.client, *outHandle, layer, parent, addToRoot, outTransformHint);
+    if (result != NO_ERROR) {
+        return result;
+    }
 
     setTransactionFlags(eTransactionNeeded);
     *outLayerId = layer->sequence;
@@ -4466,14 +4483,14 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::createEffectLayer(LayerCreationArgs& args, sp<IBinder>* handle,
+status_t SurfaceFlinger::createEffectLayer(const LayerCreationArgs& args, sp<IBinder>* handle,
                                            sp<Layer>* outLayer) {
     *outLayer = getFactory().createEffectLayer(args);
     *handle = (*outLayer)->getHandle();
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::createContainerLayer(LayerCreationArgs& args, sp<IBinder>* handle,
+status_t SurfaceFlinger::createContainerLayer(const LayerCreationArgs& args, sp<IBinder>* handle,
                                               sp<Layer>* outLayer) {
     *outLayer = getFactory().createContainerLayer(args);
     *handle = (*outLayer)->getHandle();
@@ -4499,6 +4516,9 @@
     markLayerPendingRemovalLocked(layer);
     mBufferCountTracker.remove(handle);
     layer.clear();
+    if (mTransactionTracingEnabled) {
+        mTransactionTracing.onHandleRemoved(handle);
+    }
 }
 
 // ---------------------------------------------------------------------------
@@ -6409,6 +6429,8 @@
                                        BlurSetting::Disabled
                              : compositionengine::LayerFE::ClientCompositionTargetSettings::
                                        BlurSetting::Enabled,
+                DisplayDevice::sDefaultMaxLumiance,
+
         };
         std::vector<compositionengine::LayerFE::LayerSettings> results =
                 layer->prepareClientCompositionList(targetSettings);
@@ -6653,7 +6675,9 @@
     if (!layer->isRemovedFromCurrentState()) {
         mScheduler->deregisterLayer(layer);
     }
-    mTransactionTracing.onLayerRemoved(layer->getSequence());
+    if (mTransactionTracingEnabled) {
+        mTransactionTracing.onLayerRemoved(layer->getSequence());
+    }
 }
 
 void SurfaceFlinger::onLayerUpdate() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9794639..e1b52c5 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -690,7 +690,8 @@
     void updateLayerGeometry();
 
     void updateInputFlinger();
-    void notifyWindowInfos();
+    void buildWindowInfos(std::vector<gui::WindowInfo>& outWindowInfos,
+                          std::vector<gui::DisplayInfo>& outDisplayInfos);
     void commitInputWindowCommands() REQUIRES(mStateLock);
     void updateCursorAsync();
 
@@ -769,13 +770,13 @@
     status_t createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
                                     sp<Layer>* outLayer);
 
-    status_t createEffectLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
+    status_t createEffectLayer(const LayerCreationArgs& args, sp<IBinder>* outHandle,
                                sp<Layer>* outLayer);
 
-    status_t createContainerLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
+    status_t createContainerLayer(const LayerCreationArgs& args, sp<IBinder>* outHandle,
                                   sp<Layer>* outLayer);
 
-    status_t mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
+    status_t mirrorLayer(const LayerCreationArgs& args, const sp<IBinder>& mirrorFromHandle,
                          sp<IBinder>* outHandle, int32_t* outLayerId);
 
     // called when all clients have released all their references to
@@ -1294,8 +1295,8 @@
     const float mInternalDisplayDensity;
     const float mEmulatedDisplayDensity;
 
-    sp<os::IInputFlinger> mInputFlinger;
     // Should only be accessed by the main thread.
+    sp<os::IInputFlinger> mInputFlinger;
     InputWindowCommands mInputWindowCommands;
 
     Hwc2::impl::PowerAdvisor mPowerAdvisor;
@@ -1351,6 +1352,11 @@
     const sp<WindowInfosListenerInvoker> mWindowInfosListenerInvoker;
 
     std::unique_ptr<FlagManager> mFlagManager;
+
+    // returns the framerate of the layer with the given sequence ID
+    float getLayerFramerate(nsecs_t now, int32_t id) const {
+        return mScheduler->getLayerFramerate(now, id);
+    }
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 7e12313..378deb0 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -43,7 +43,7 @@
 }
 
 proto::TransactionState TransactionProtoParser::toProto(
-        const std::unordered_map<int32_t /* layerId */, TracingLayerState> states) {
+        const std::map<int32_t /* layerId */, TracingLayerState>& states) {
     proto::TransactionState proto;
     for (auto& [layerId, state] : states) {
         proto::LayerState layerProto = toProto(state, nullptr);
@@ -278,6 +278,7 @@
     proto.set_name(args.name);
     proto.set_flags(args.flags);
     proto.set_parent_id(args.parentId);
+    proto.set_mirror_from_id(args.mirrorFromId);
     return proto;
 }
 
@@ -312,6 +313,7 @@
     outArgs.name = proto.name();
     outArgs.flags = proto.flags();
     outArgs.parentId = proto.parent_id();
+    outArgs.mirrorFromId = proto.mirror_from_id();
 }
 
 void TransactionProtoParser::fromProto(const proto::LayerState& proto,
@@ -320,6 +322,7 @@
     fromProto(proto, getLayerHandle, static_cast<layer_state_t&>(outState));
     if (proto.what() & layer_state_t::eReparent) {
         outState.parentId = proto.parent_id();
+        outState.args.parentId = outState.parentId;
     }
     if (proto.what() & layer_state_t::eRelativeLayerChanged) {
         outState.relativeParentId = proto.relative_parent_id();
@@ -508,7 +511,9 @@
                                                DisplayIdToHandleFn getDisplayHandle) {
     DisplayState display;
     display.what = proto.what();
-    display.token = getDisplayHandle(proto.id());
+    if (getDisplayHandle != nullptr) {
+        display.token = getDisplayHandle(proto.id());
+    }
 
     if (display.what & DisplayState::eLayerStackChanged) {
         display.layerStack.id = proto.layer_stack();
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index 619ee05..b78d3d9 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -25,8 +25,9 @@
 struct TracingLayerCreationArgs {
     int32_t layerId;
     std::string name;
-    uint32_t flags;
-    int32_t parentId;
+    uint32_t flags = 0;
+    int32_t parentId = -1;
+    int32_t mirrorFromId = -1;
 };
 
 struct TracingLayerState : layer_state_t {
@@ -37,8 +38,7 @@
     int32_t parentId;
     int32_t relativeParentId;
     int32_t inputCropId;
-    std::string name;
-    uint32_t layerCreationFlags;
+    TracingLayerCreationArgs args;
 };
 
 class TransactionProtoParser {
@@ -51,7 +51,7 @@
     static proto::TransactionState toProto(const TransactionState&, LayerHandleToIdFn getLayerIdFn,
                                            DisplayHandleToIdFn getDisplayIdFn);
     static proto::TransactionState toProto(
-            const std::unordered_map<int32_t /* layerId */, TracingLayerState>);
+            const std::map<int32_t /* layerId */, TracingLayerState>&);
 
     static proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args);
 
@@ -70,4 +70,4 @@
     static DisplayState fromProto(const proto::DisplayState&, DisplayIdToHandleFn getDisplayHandle);
 };
 
-} // namespace android::surfaceflinger
\ No newline at end of file
+} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index cf488c2..c1b3d2e 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -199,7 +199,7 @@
                 entryProto.mutable_transactions()->Add(std::move(it->second));
                 mQueuedTransactions.erase(it);
             } else {
-                ALOGE("Could not find transaction id %" PRIu64, id);
+                ALOGW("Could not find transaction id %" PRIu64, id);
             }
         }
         std::vector<proto::TransactionTraceEntry> entries = mBuffer->emplace(std::move(entryProto));
@@ -227,7 +227,23 @@
 void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name,
                                       uint32_t flags, int parentId) {
     std::scoped_lock lock(mTraceLock);
-    TracingLayerCreationArgs args{layerId, name, flags, parentId};
+    TracingLayerCreationArgs args{layerId, name, flags, parentId, -1 /* mirrorFromId */};
+    if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) {
+        ALOGW("Duplicate handles found. %p", layerHandle);
+    }
+    mLayerHandles[layerHandle] = layerId;
+    proto::LayerCreationArgs protoArgs = TransactionProtoParser::toProto(args);
+    proto::LayerCreationArgs protoArgsCopy = protoArgs;
+    mCreatedLayers.push_back(protoArgs);
+}
+
+void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId,
+                                            const std::string& name, int mirrorFromId) {
+    std::scoped_lock lock(mTraceLock);
+    TracingLayerCreationArgs args{layerId, name, 0 /* flags */, -1 /* parentId */, mirrorFromId};
+    if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) {
+        ALOGW("Duplicate handles found. %p", layerHandle);
+    }
     mLayerHandles[layerHandle] = layerId;
     mCreatedLayers.emplace_back(TransactionProtoParser::toProto(args));
 }
@@ -237,6 +253,11 @@
     tryPushToTracingThread();
 }
 
+void TransactionTracing::onHandleRemoved(BBinder* layerHandle) {
+    std::scoped_lock lock(mTraceLock);
+    mLayerHandles.erase(layerHandle);
+}
+
 void TransactionTracing::tryPushToTracingThread() {
     // Try to acquire the lock from main thread.
     if (mMainThreadLock.try_lock()) {
@@ -260,7 +281,11 @@
         return -1;
     }
     auto it = mLayerHandles.find(layerHandle->localBinder());
-    return it == mLayerHandles.end() ? -1 : it->second;
+    if (it == mLayerHandles.end()) {
+        ALOGW("Could not find layer handle %p", layerHandle->localBinder());
+        return -1;
+    }
+    return it->second;
 }
 
 void TransactionTracing::updateStartingStateLocked(
@@ -270,9 +295,7 @@
     for (const proto::LayerCreationArgs& addedLayer : removedEntry.added_layers()) {
         TracingLayerState& startingState = mStartingStates[addedLayer.layer_id()];
         startingState.layerId = addedLayer.layer_id();
-        startingState.name = addedLayer.name();
-        startingState.layerCreationFlags = addedLayer.flags();
-        startingState.parentId = addedLayer.parent_id();
+        TransactionProtoParser::fromProto(addedLayer, startingState.args);
     }
 
     // Merge layer states to starting transaction state.
@@ -280,7 +303,7 @@
         for (const proto::LayerState& layerState : transaction.layer_changes()) {
             auto it = mStartingStates.find(layerState.layer_id());
             if (it == mStartingStates.end()) {
-                ALOGE("Could not find layer id %d", layerState.layer_id());
+                ALOGW("Could not find layer id %d", layerState.layer_id());
                 continue;
             }
             TransactionProtoParser::fromProto(layerState, nullptr, it->second);
@@ -290,13 +313,6 @@
     // Clean up stale starting states since the layer has been removed and the buffer does not
     // contain any references to the layer.
     for (const int32_t removedLayerId : removedEntry.removed_layers()) {
-        auto it = std::find_if(mLayerHandles.begin(), mLayerHandles.end(),
-                               [removedLayerId](auto& layer) {
-                                   return layer.second == removedLayerId;
-                               });
-        if (it != mLayerHandles.end()) {
-            mLayerHandles.erase(it);
-        }
         mStartingStates.erase(removedLayerId);
     }
 }
@@ -305,11 +321,13 @@
     proto::TransactionTraceEntry* entryProto = proto.add_entry();
     entryProto->set_elapsed_realtime_nanos(mStartingTimestamp);
     entryProto->set_vsync_id(0);
+    if (mStartingStates.size() == 0) {
+        return;
+    }
+
     entryProto->mutable_added_layers()->Reserve(static_cast<int32_t>(mStartingStates.size()));
     for (auto& [layerId, state] : mStartingStates) {
-        TracingLayerCreationArgs args{layerId, state.name, state.layerCreationFlags,
-                                      state.parentId};
-        entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(args));
+        entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(state.args));
     }
 
     proto::TransactionState transactionProto = TransactionProtoParser::toProto(mStartingStates);
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
index 0aa22ed..26a3758 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.h
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -64,7 +64,10 @@
     void setBufferSize(size_t bufferSizeInBytes);
     void onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, uint32_t flags,
                       int parentId);
+    void onMirrorLayerAdded(BBinder* layerHandle, int layerId, const std::string& name,
+                            int mirrorFromId);
     void onLayerRemoved(int layerId);
+    void onHandleRemoved(BBinder* layerHandle);
     void dump(std::string&) const;
     static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024;
     static constexpr auto ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024;
@@ -85,8 +88,7 @@
     std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock);
     std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles
             GUARDED_BY(mTraceLock);
-    std::unordered_map<int32_t /* layerId */, TracingLayerState> mStartingStates
-            GUARDED_BY(mTraceLock);
+    std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock);
 
     // We do not want main thread to block so main thread will try to acquire mMainThreadLock,
     // otherwise will push data to temporary container.
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index 10222cc..e31b502 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -53,6 +53,7 @@
     string name = 2;
     uint32 flags = 3;
     int32 parent_id = 4;
+    int32 mirror_from_id = 5;
 }
 
 message TransactionState {
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index 575e70d..39d7bd9 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -3,7 +3,7 @@
     user system
     group graphics drmrpc readproc
     capabilities SYS_NICE
-    onrestart restart zygote
+    onrestart restart --only-if-running zygote
     task_profiles HighPerformance
     socket pdx/system/vr/display/client     stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
     socket pdx/system/vr/display/manager    stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 561d9e2..5568418 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -119,6 +119,7 @@
     static_libs: [
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
+        "android.hardware.graphics.common-V3-ndk",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 00687ad..cdb2240 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -63,33 +63,42 @@
     const LayerHistory& history() const { return mScheduler->mutableLayerHistory(); }
 
     LayerHistory::Summary summarizeLayerHistory(nsecs_t now) {
-        return history().summarize(*mScheduler->refreshRateConfigs(), now);
+        // LayerHistory::summarize makes no guarantee of the order of the elements in the summary
+        // however, for testing only, a stable order is required, therefore we sort the list here.
+        // Any tests requiring ordered results must create layers with names.
+        auto summary = history().summarize(*mScheduler->refreshRateConfigs(), now);
+        std::sort(summary.begin(), summary.end(),
+                  [](const RefreshRateConfigs::LayerRequirement& a,
+                     const RefreshRateConfigs::LayerRequirement& b) -> bool {
+                      return a.name < b.name;
+                  });
+        return summary;
     }
 
     size_t layerCount() const { return mScheduler->layerHistorySize(); }
-    size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; }
+    size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS {
+        return history().mActiveLayerInfos.size();
+    }
 
     auto frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
-        const auto& infos = history().mLayerInfos;
-        return std::count_if(infos.begin(),
-                             infos.begin() + static_cast<long>(history().mActiveLayersEnd),
-                             [now](const auto& pair) { return pair.second->isFrequent(now); });
+        const auto& infos = history().mActiveLayerInfos;
+        return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) {
+            return pair.second.second->isFrequent(now);
+        });
     }
 
     auto animatingLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
-        const auto& infos = history().mLayerInfos;
-        return std::count_if(infos.begin(),
-                             infos.begin() + static_cast<long>(history().mActiveLayersEnd),
-                             [now](const auto& pair) { return pair.second->isAnimating(now); });
+        const auto& infos = history().mActiveLayerInfos;
+        return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) {
+            return pair.second.second->isAnimating(now);
+        });
     }
 
     void setDefaultLayerVote(Layer* layer,
                              LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS {
-        for (auto& [layerUnsafe, info] : history().mLayerInfos) {
-            if (layerUnsafe == layer) {
-                info->setDefaultLayerVote(vote);
-                return;
-            }
+        auto [found, layerPair] = history().findLayer(layer->getSequence());
+        if (found != LayerHistory::layerStatus::NotFound) {
+            layerPair->second->setDefaultLayerVote(vote);
         }
     }
 
@@ -144,6 +153,8 @@
     EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
     EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
 
+    // history().registerLayer(layer, LayerHistory::LayerVoteType::Max);
+
     EXPECT_EQ(1, layerCount());
     EXPECT_EQ(0, activeLayerCount());
 
@@ -368,9 +379,9 @@
 }
 
 TEST_F(LayerHistoryTest, multipleLayers) {
-    auto layer1 = createLayer();
-    auto layer2 = createLayer();
-    auto layer3 = createLayer();
+    auto layer1 = createLayer("A");
+    auto layer2 = createLayer("B");
+    auto layer3 = createLayer("C");
 
     EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
     EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
@@ -654,6 +665,29 @@
     EXPECT_EQ(1, animatingLayerCount(time));
 }
 
+TEST_F(LayerHistoryTest, getFramerate) {
+    auto layer = createLayer();
+
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    nsecs_t time = systemTime();
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+    EXPECT_EQ(0, animatingLayerCount(time));
+
+    // layer is active but infrequent.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+    }
+
+    float expectedFramerate = 1e9f / MAX_FREQUENT_LAYER_PERIOD_NS.count();
+    EXPECT_FLOAT_EQ(expectedFramerate, history().getLayerFramerate(time, layer->getSequence()));
+}
+
 TEST_F(LayerHistoryTest, heuristicLayer60Hz) {
     const auto layer = createLayer();
     EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index dabd2d2..364d8f1 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -67,11 +67,16 @@
 
     auto& mutableLayerHistory() { return mLayerHistory; }
 
-    size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mLayerInfos.size(); }
-    size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mActiveLayersEnd; }
+    size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS {
+        return mLayerHistory.mActiveLayerInfos.size() + mLayerHistory.mInactiveLayerInfos.size();
+    }
 
     auto refreshRateConfigs() { return holdRefreshRateConfigs(); }
 
+    size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS {
+        return mLayerHistory.mActiveLayerInfos.size();
+    }
+
     void replaceTouchTimer(int64_t millis) {
         if (mTouchTimer) {
             mTouchTimer.reset();
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index ffe5671..71c7bd9 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -165,7 +165,7 @@
         mTracing->onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent",
                                123 /* flags */, -1 /* parentId */);
         const sp<IBinder> fakeChildLayerHandle = new BBinder();
-        mTracing->onLayerAdded(fakeChildLayerHandle->localBinder(), 2 /* layerId */, "child",
+        mTracing->onLayerAdded(fakeChildLayerHandle->localBinder(), mChildLayerId, "child",
                                456 /* flags */, mParentLayerId);
 
         // add some layer transaction
@@ -179,7 +179,8 @@
             transaction.states.add(layerState);
             ComposerState childState;
             childState.state.surface = fakeChildLayerHandle;
-            layerState.state.z = 43;
+            childState.state.what = layer_state_t::eLayerChanged;
+            childState.state.z = 43;
             transaction.states.add(childState);
             mTracing->addQueuedTransaction(transaction);
 
@@ -227,6 +228,7 @@
     }
 
     int mParentLayerId = 1;
+    int mChildLayerId = 2;
     int64_t mVsyncId = 0;
     int64_t VSYNC_ID_FIRST_LAYER_CHANGE;
     int64_t VSYNC_ID_SECOND_LAYER_CHANGE;
@@ -244,8 +246,11 @@
     EXPECT_GT(proto.entry().size(), 0);
     EXPECT_GT(proto.entry(0).transactions().size(), 0);
     EXPECT_GT(proto.entry(0).added_layers().size(), 0);
-    EXPECT_GT(proto.entry(0).transactions(0).layer_changes().size(), 0);
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 2);
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
     EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 42);
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(1).layer_id(), mChildLayerId);
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(1).z(), 43);
 }
 
 TEST_F(TransactionTracingLayerHandlingTest, updateStartingState) {
@@ -288,4 +293,69 @@
     EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
 }
 
+class TransactionTracingMirrorLayerTest : public TransactionTracingTest {
+protected:
+    void SetUp() override {
+        TransactionTracingTest::SetUp();
+        mTracing->enable();
+        // add layers
+        mTracing->setBufferSize(SMALL_BUFFER_SIZE);
+        const sp<IBinder> fakeLayerHandle = new BBinder();
+        mTracing->onLayerAdded(fakeLayerHandle->localBinder(), mLayerId, "Test Layer",
+                               123 /* flags */, -1 /* parentId */);
+        const sp<IBinder> fakeMirrorLayerHandle = new BBinder();
+        mTracing->onMirrorLayerAdded(fakeMirrorLayerHandle->localBinder(), mMirrorLayerId, "Mirror",
+                                     mLayerId);
+
+        // add some layer transaction
+        {
+            TransactionState transaction;
+            transaction.id = 50;
+            ComposerState layerState;
+            layerState.state.surface = fakeLayerHandle;
+            layerState.state.what = layer_state_t::eLayerChanged;
+            layerState.state.z = 42;
+            transaction.states.add(layerState);
+            ComposerState mirrorState;
+            mirrorState.state.surface = fakeMirrorLayerHandle;
+            mirrorState.state.what = layer_state_t::eLayerChanged;
+            mirrorState.state.z = 43;
+            transaction.states.add(mirrorState);
+            mTracing->addQueuedTransaction(transaction);
+
+            std::vector<TransactionState> transactions;
+            transactions.emplace_back(transaction);
+            mTracing->addCommittedTransactions(transactions, ++mVsyncId);
+            flush(mVsyncId);
+        }
+    }
+
+    void TearDown() override {
+        mTracing->disable();
+        verifyDisabledTracingState();
+        TransactionTracingTest::TearDown();
+    }
+
+    int mLayerId = 5;
+    int mMirrorLayerId = 55;
+    int64_t mVsyncId = 0;
+    int64_t VSYNC_ID_FIRST_LAYER_CHANGE;
+    int64_t VSYNC_ID_SECOND_LAYER_CHANGE;
+    int64_t VSYNC_ID_CHILD_LAYER_REMOVED;
+};
+
+TEST_F(TransactionTracingMirrorLayerTest, canAddMirrorLayers) {
+    proto::TransactionTraceFile proto = writeToProto();
+    // We don't have any starting states since no layer was removed from.
+    EXPECT_EQ(proto.entry().size(), 2);
+    EXPECT_EQ(proto.entry(0).transactions().size(), 0);
+    EXPECT_EQ(proto.entry(0).added_layers().size(), 0);
+
+    // Verify the mirror layer was added
+    EXPECT_EQ(proto.entry(1).transactions().size(), 1);
+    EXPECT_EQ(proto.entry(1).added_layers().size(), 2);
+    EXPECT_EQ(proto.entry(1).added_layers(1).layer_id(), mMirrorLayerId);
+    EXPECT_EQ(proto.entry(1).transactions(0).layer_changes().size(), 2);
+    EXPECT_EQ(proto.entry(1).transactions(0).layer_changes(1).z(), 43);
+}
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 1ba3c0f..1debd65 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -136,7 +136,9 @@
                              const std::vector<uint8_t>&));
     MOCK_METHOD1(getLayerGenericMetadataKeys,
                  V2_4::Error(std::vector<IComposerClient::LayerGenericMetadataKey>*));
-    MOCK_METHOD2(getClientTargetProperty, Error(Display, IComposerClient::ClientTargetProperty*));
+    MOCK_METHOD3(getClientTargetProperty,
+                 Error(Display, IComposerClient::ClientTargetProperty*, float*));
+    MOCK_METHOD3(setLayerWhitePointNits, Error(Display, Layer, float));
 };
 
 } // namespace Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index fe1544e..83a0996 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -85,7 +85,8 @@
     MOCK_METHOD(hal::Error, getSupportedContentTypes, (std::vector<hal::ContentType> *),
                 (const, override));
     MOCK_METHOD(hal::Error, setContentType, (hal::ContentType), (override));
-    MOCK_METHOD(hal::Error, getClientTargetProperty, (hal::ClientTargetProperty *), (override));
+    MOCK_METHOD(hal::Error, getClientTargetProperty, (hal::ClientTargetProperty *, float *),
+                (override));
 };
 
 class Layer : public HWC2::Layer {
@@ -116,6 +117,7 @@
     MOCK_METHOD(hal::Error, setColorTransform, (const android::mat4 &), (override));
     MOCK_METHOD(hal::Error, setLayerGenericMetadata,
                 (const std::string &, bool, const std::vector<uint8_t> &), (override));
+    MOCK_METHOD(hal::Error, setWhitePointNits, (float whitePointNits), (override));
 };
 
 } // namespace android::HWC2::mock
diff --git a/vulkan/libvulkan/debug_report.h b/vulkan/libvulkan/debug_report.h
index e5b1587..416c0bc 100644
--- a/vulkan/libvulkan/debug_report.h
+++ b/vulkan/libvulkan/debug_report.h
@@ -78,8 +78,7 @@
         VkDebugReportCallbackEXT driver_handle;
     };
 
-    // TODO(b/143295577): use std::shared_mutex when available in libc++
-    mutable std::shared_timed_mutex rwmutex_;
+    mutable std::shared_mutex rwmutex_;
     Node head_;
 };